2 * Copyright 2014 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"
28 extern const char formatHexUpper[256][2];
29 extern const char formatHexLower[256][2];
30 extern const char formatOctal[512][3];
31 extern const char formatBinary[256][8];
33 const size_t kMaxHexLength = 2 * sizeof(uintmax_t);
34 const size_t kMaxOctalLength = 3 * sizeof(uintmax_t);
35 const size_t kMaxBinaryLength = 8 * sizeof(uintmax_t);
38 * Convert an unsigned to hex, using repr (which maps from each possible
39 * 2-hex-bytes value to the 2-character representation).
41 * Just like folly::detail::uintToBuffer in Conv.h, writes at the *end* of
42 * the supplied buffer and returns the offset of the beginning of the string
43 * from the start of the buffer. The formatted string will be in range
44 * [buf+begin, buf+bufLen).
47 size_t uintToHex(char* buffer, size_t bufLen, Uint v,
48 const char (&repr)[256][2]) {
49 // 'v >>= 7, v >>= 1' is no more than a work around to get rid of shift size
50 // warning when Uint = uint8_t (it's false as v >= 256 implies sizeof(v) > 1).
51 for (; !less_than<unsigned, 256>(v); v >>= 7, v >>= 1) {
54 buffer[bufLen] = repr[b][0];
55 buffer[bufLen + 1] = repr[b][1];
57 buffer[--bufLen] = repr[v][1];
59 buffer[--bufLen] = repr[v][0];
65 * Convert an unsigned to hex, using lower-case letters for the digits
66 * above 9. See the comments for uintToHex.
69 inline size_t uintToHexLower(char* buffer, size_t bufLen, Uint v) {
70 return uintToHex(buffer, bufLen, v, formatHexLower);
74 * Convert an unsigned to hex, using upper-case letters for the digits
75 * above 9. See the comments for uintToHex.
78 inline size_t uintToHexUpper(char* buffer, size_t bufLen, Uint v) {
79 return uintToHex(buffer, bufLen, v, formatHexUpper);
83 * Convert an unsigned to octal.
85 * Just like folly::detail::uintToBuffer in Conv.h, writes at the *end* of
86 * the supplied buffer and returns the offset of the beginning of the string
87 * from the start of the buffer. The formatted string will be in range
88 * [buf+begin, buf+bufLen).
91 size_t uintToOctal(char* buffer, size_t bufLen, Uint v) {
92 auto& repr = formatOctal;
93 // 'v >>= 7, v >>= 2' is no more than a work around to get rid of shift size
94 // warning when Uint = uint8_t (it's false as v >= 512 implies sizeof(v) > 1).
95 for (; !less_than<unsigned, 512>(v); v >>= 7, v >>= 2) {
98 buffer[bufLen] = repr[b][0];
99 buffer[bufLen + 1] = repr[b][1];
100 buffer[bufLen + 2] = repr[b][2];
102 buffer[--bufLen] = repr[v][2];
104 buffer[--bufLen] = repr[v][1];
107 buffer[--bufLen] = repr[v][0];
113 * Convert an unsigned to binary.
115 * Just like folly::detail::uintToBuffer in Conv.h, writes at the *end* of
116 * the supplied buffer and returns the offset of the beginning of the string
117 * from the start of the buffer. The formatted string will be in range
118 * [buf+begin, buf+bufLen).
120 template <class Uint>
121 size_t uintToBinary(char* buffer, size_t bufLen, Uint v) {
122 auto& repr = formatBinary;
124 buffer[--bufLen] = '0';
127 for (; v; v >>= 7, v >>= 1) {
130 memcpy(buffer + bufLen, &(repr[b][0]), 8);
132 while (buffer[bufLen] == '0') {
138 } // namespace detail
141 template <bool containerMode, class... Args>
142 Formatter<containerMode, Args...>::Formatter(StringPiece str, Args&&... args)
144 values_(FormatValue<typename std::decay<Args>::type>(
145 std::forward<Args>(args))...) {
146 static_assert(!containerMode || sizeof...(Args) == 1,
147 "Exactly one argument required in container mode");
150 template <bool containerMode, class... Args>
151 template <class Output>
152 void Formatter<containerMode, Args...>::operator()(Output& out) const {
153 auto p = str_.begin();
154 auto end = str_.end();
156 // Copy raw string (without format specifiers) to output;
157 // not as simple as we'd like, as we still need to translate "}}" to "}"
158 // and throw if we see any lone "}"
159 auto outputString = [&out] (StringPiece s) {
163 auto q = static_cast<const char*>(memchr(p, '}', end - p));
165 out(StringPiece(p, end));
169 out(StringPiece(p, q));
172 CHECK(p != end && *p == '}') << "single '}' in format string";
178 bool hasDefaultArgIndex = false;
179 bool hasExplicitArgIndex = false;
181 auto q = static_cast<const char*>(memchr(p, '{', end - p));
183 outputString(StringPiece(p, end));
186 outputString(StringPiece(p, q));
189 CHECK(p != end) << "'{' at end of format string";
193 out(StringPiece(p, 1));
199 q = static_cast<const char*>(memchr(p, '}', end - p));
200 CHECK(q != end) << "missing ending '}'";
201 FormatArg arg(StringPiece(p, q));
205 auto piece = arg.splitKey<true>(); // empty key component is okay
206 if (containerMode) { // static
208 arg.setNextIntKey(nextArg++);
209 hasDefaultArgIndex = true;
211 arg.setNextKey(piece);
212 hasExplicitArgIndex = true;
216 argIndex = nextArg++;
217 hasDefaultArgIndex = true;
220 argIndex = to<int>(piece);
221 } catch (const std::out_of_range& e) {
222 LOG(FATAL) << "argument index must be integer";
225 << arg.errorStr("argument index must be non-negative");
226 hasExplicitArgIndex = true;
230 CHECK(!hasDefaultArgIndex || !hasExplicitArgIndex)
231 << "may not have both default and explicit arg indexes";
233 doFormat(argIndex, arg, out);
237 template <bool containerMode, class... Args>
238 void writeTo(FILE* fp, const Formatter<containerMode, Args...>& formatter) {
239 auto writer = [fp] (StringPiece sp) {
240 ssize_t n = fwrite(sp.data(), 1, sp.size(), fp);
242 throwSystemError("Formatter writeTo", "fwrite failed");
248 namespace format_value {
250 template <class FormatCallback>
251 void formatString(StringPiece val, FormatArg& arg, FormatCallback& cb) {
252 if (arg.precision != FormatArg::kDefaultPrecision &&
253 val.size() > arg.precision) {
254 val.reset(val.data(), arg.precision);
257 constexpr int padBufSize = 128;
258 char padBuf[padBufSize];
260 // Output padding, no more than padBufSize at once
261 auto pad = [&padBuf, &cb, padBufSize] (int chars) {
263 int n = std::min(chars, padBufSize);
264 cb(StringPiece(padBuf, n));
269 int padRemaining = 0;
270 if (arg.width != FormatArg::kDefaultWidth && val.size() < arg.width) {
271 char fill = arg.fill == FormatArg::kDefaultFill ? ' ' : arg.fill;
272 int padChars = arg.width - val.size();
273 memset(padBuf, fill, std::min(padBufSize, padChars));
276 case FormatArg::Align::DEFAULT:
277 case FormatArg::Align::LEFT:
278 padRemaining = padChars;
280 case FormatArg::Align::CENTER:
282 padRemaining = padChars - padChars / 2;
284 case FormatArg::Align::RIGHT:
285 case FormatArg::Align::PAD_AFTER_SIGN:
301 template <class FormatCallback>
302 void formatNumber(StringPiece val, int prefixLen, FormatArg& arg,
303 FormatCallback& cb) {
304 // precision means something different for numbers
305 arg.precision = FormatArg::kDefaultPrecision;
306 if (arg.align == FormatArg::Align::DEFAULT) {
307 arg.align = FormatArg::Align::RIGHT;
308 } else if (prefixLen && arg.align == FormatArg::Align::PAD_AFTER_SIGN) {
309 // Split off the prefix, then do any padding if necessary
310 cb(val.subpiece(0, prefixLen));
311 val.advance(prefixLen);
312 arg.width = std::max(arg.width - prefixLen, 0);
314 format_value::formatString(val, arg, cb);
317 template <class FormatCallback, bool containerMode, class... Args>
318 void formatFormatter(const Formatter<containerMode, Args...>& formatter,
320 FormatCallback& cb) {
321 if (arg.width == FormatArg::kDefaultWidth &&
322 arg.precision == FormatArg::kDefaultPrecision) {
325 } else if (arg.align != FormatArg::Align::LEFT &&
326 arg.align != FormatArg::Align::DEFAULT) {
327 // We can only avoid creating a temporary string if we align left,
328 // as we'd need to know the size beforehand otherwise
329 format_value::formatString(formatter.fbstr(), arg, cb);
331 auto fn = [&arg, &cb] (StringPiece sp) mutable {
332 int sz = static_cast<int>(sp.size());
333 if (arg.precision != FormatArg::kDefaultPrecision) {
334 sz = std::min(arg.precision, sz);
335 sp.reset(sp.data(), sz);
340 if (arg.width != FormatArg::kDefaultWidth) {
341 arg.width = std::max(arg.width - sz, 0);
346 if (arg.width != FormatArg::kDefaultWidth && arg.width != 0) {
347 // Rely on formatString to do appropriate padding
348 format_value::formatString(StringPiece(), arg, cb);
353 } // namespace format_value
355 // Definitions for default FormatValue classes
357 // Integral types (except bool)
360 T, typename std::enable_if<
361 std::is_integral<T>::value &&
362 !std::is_same<T, bool>::value>::type>
365 explicit FormatValue(T val) : val_(val) { }
366 template <class FormatCallback>
367 void format(FormatArg& arg, FormatCallback& cb) const {
368 arg.validate(FormatArg::Type::INTEGER);
372 template <class FormatCallback>
373 void doFormat(FormatArg& arg, FormatCallback& cb) const {
374 char presentation = arg.presentation;
375 if (presentation == FormatArg::kDefaultPresentation) {
376 presentation = std::is_same<T, char>::value ? 'c' : 'd';
379 // Do all work as unsigned, we'll add the prefix ('0' or '0x' if necessary)
380 // and sign ourselves.
381 typedef typename std::make_unsigned<T>::type UT;
384 if (std::is_signed<T>::value) {
385 if (folly::is_negative(val_)) {
386 uval = static_cast<UT>(-val_);
389 uval = static_cast<UT>(val_);
391 case FormatArg::Sign::PLUS_OR_MINUS:
394 case FormatArg::Sign::SPACE_OR_MINUS:
406 CHECK(arg.sign == FormatArg::Sign::DEFAULT)
407 << arg.errorStr("sign specifications not allowed for unsigned values");
411 // #x: 0x prefix + 16 bytes = 18 bytes
412 // #o: 0 prefix + 22 bytes = 23 bytes
413 // #b: 0b prefix + 64 bytes = 65 bytes
414 // ,d: 26 bytes (including thousands separators!)
416 // + 3 for sign and prefix shenanigans (see below)
417 constexpr size_t valBufSize = 69;
418 char valBuf[valBufSize];
419 char* valBufBegin = nullptr;
420 char* valBufEnd = nullptr;
423 auto useSprintf = [&] (const char* format) mutable {
424 valBufBegin = valBuf + 3; // room for sign and base prefix
425 valBufEnd = valBufBegin + sprintf(valBufBegin, format,
426 static_cast<uintmax_t>(uval));
431 switch (presentation) {
432 case 'n': // TODO(tudorb): locale awareness?
434 CHECK(!arg.basePrefix)
435 << arg.errorStr("base prefix not allowed with '", presentation,
437 if (arg.thousandsSeparator) {
440 // Use uintToBuffer, faster than sprintf
441 valBufBegin = valBuf + 3;
442 valBufEnd = valBufBegin + uint64ToBufferUnsafe(uval, valBufBegin);
446 CHECK(!arg.basePrefix)
447 << arg.errorStr("base prefix not allowed with '", presentation,
449 CHECK(!arg.thousandsSeparator)
450 << arg.errorStr("thousands separator (',') not allowed with '",
451 presentation, "' specifier");
452 valBufBegin = valBuf + 3;
453 *valBufBegin = static_cast<char>(uval);
454 valBufEnd = valBufBegin + 1;
458 CHECK(!arg.thousandsSeparator)
459 << arg.errorStr("thousands separator (',') not allowed with '",
460 presentation, "' specifier");
461 valBufEnd = valBuf + valBufSize - 1;
462 valBufBegin = valBuf + detail::uintToOctal(valBuf, valBufSize - 1, uval);
463 if (arg.basePrefix) {
464 *--valBufBegin = '0';
469 CHECK(!arg.thousandsSeparator)
470 << arg.errorStr("thousands separator (',') not allowed with '",
471 presentation, "' specifier");
472 valBufEnd = valBuf + valBufSize - 1;
473 valBufBegin = valBuf + detail::uintToHexLower(valBuf, valBufSize - 1,
475 if (arg.basePrefix) {
476 *--valBufBegin = 'x';
477 *--valBufBegin = '0';
482 CHECK(!arg.thousandsSeparator)
483 << arg.errorStr("thousands separator (',') not allowed with '",
484 presentation, "' specifier");
485 valBufEnd = valBuf + valBufSize - 1;
486 valBufBegin = valBuf + detail::uintToHexUpper(valBuf, valBufSize - 1,
488 if (arg.basePrefix) {
489 *--valBufBegin = 'X';
490 *--valBufBegin = '0';
496 CHECK(!arg.thousandsSeparator)
497 << arg.errorStr("thousands separator (',') not allowed with '",
498 presentation, "' specifier");
499 valBufEnd = valBuf + valBufSize - 1;
500 valBufBegin = valBuf + detail::uintToBinary(valBuf, valBufSize - 1,
502 if (arg.basePrefix) {
503 *--valBufBegin = presentation; // 0b or 0B
504 *--valBufBegin = '0';
509 LOG(FATAL) << arg.errorStr("invalid specifier '", presentation, "'");
513 *--valBufBegin = sign;
517 format_value::formatNumber(StringPiece(valBufBegin, valBufEnd), prefixLen,
527 class FormatValue<bool> {
529 explicit FormatValue(bool val) : val_(val) { }
531 template <class FormatCallback>
532 void format(FormatArg& arg, FormatCallback& cb) const {
533 if (arg.presentation == FormatArg::kDefaultPresentation) {
534 arg.validate(FormatArg::Type::OTHER);
535 format_value::formatString(val_ ? "true" : "false", arg, cb);
537 FormatValue<int>(val_).format(arg, cb);
547 class FormatValue<double> {
549 explicit FormatValue(double val) : val_(val) { }
551 template <class FormatCallback>
552 void format(FormatArg& arg, FormatCallback& cb) const {
553 using ::double_conversion::DoubleToStringConverter;
554 using ::double_conversion::StringBuilder;
556 arg.validate(FormatArg::Type::FLOAT);
558 if (arg.presentation == FormatArg::kDefaultPresentation) {
559 arg.presentation = 'g';
562 const char* infinitySymbol = isupper(arg.presentation) ? "INF" : "inf";
563 const char* nanSymbol = isupper(arg.presentation) ? "NAN" : "nan";
564 char exponentSymbol = isupper(arg.presentation) ? 'E' : 'e';
566 if (arg.precision == FormatArg::kDefaultPrecision) {
570 // 2+: for null terminator and optional sign shenanigans.
571 char buf[2 + std::max({
572 (2 + DoubleToStringConverter::kMaxFixedDigitsBeforePoint +
573 DoubleToStringConverter::kMaxFixedDigitsAfterPoint),
574 (8 + DoubleToStringConverter::kMaxExponentialDigits),
575 (7 + DoubleToStringConverter::kMaxPrecisionDigits)})];
576 StringBuilder builder(buf + 1, sizeof(buf) - 1);
580 case FormatArg::Sign::PLUS_OR_MINUS:
583 case FormatArg::Sign::SPACE_OR_MINUS:
592 switch (arg.presentation) {
599 DoubleToStringConverter::kMaxFixedDigitsAfterPoint) {
600 arg.precision = DoubleToStringConverter::kMaxFixedDigitsAfterPoint;
602 DoubleToStringConverter conv(
603 DoubleToStringConverter::EMIT_POSITIVE_EXPONENT_SIGN,
609 arg.enforce(conv.ToFixed(val, arg.precision, &builder),
610 "fixed double conversion failed");
616 if (arg.precision > DoubleToStringConverter::kMaxExponentialDigits) {
617 arg.precision = DoubleToStringConverter::kMaxExponentialDigits;
620 DoubleToStringConverter conv(
621 DoubleToStringConverter::EMIT_POSITIVE_EXPONENT_SIGN,
627 CHECK(conv.ToExponential(val, arg.precision, &builder));
630 case 'n': // should be locale-aware, but isn't
634 if (arg.precision < DoubleToStringConverter::kMinPrecisionDigits) {
635 arg.precision = DoubleToStringConverter::kMinPrecisionDigits;
636 } else if (arg.precision >
637 DoubleToStringConverter::kMaxPrecisionDigits) {
638 arg.precision = DoubleToStringConverter::kMaxPrecisionDigits;
640 DoubleToStringConverter conv(
641 DoubleToStringConverter::EMIT_POSITIVE_EXPONENT_SIGN,
647 CHECK(conv.ToShortest(val, &builder));
651 LOG(FATAL) << arg.errorStr("invalid specifier '", arg.presentation, "'");
654 int len = builder.position();
658 // Add '+' or ' ' sign if needed
660 // anything that's neither negative nor nan
662 if (plusSign && (*p != '-' && *p != 'n' && *p != 'N')) {
666 } else if (*p == '-') {
670 format_value::formatNumber(StringPiece(p, len), prefixLen, arg, cb);
677 // float (defer to double)
679 class FormatValue<float> {
681 explicit FormatValue(float val) : val_(val) { }
683 template <class FormatCallback>
684 void format(FormatArg& arg, FormatCallback& cb) const {
685 FormatValue<double>(val_).format(arg, cb);
692 // Sring-y types (implicitly convertible to StringPiece, except char*)
695 T, typename std::enable_if<
696 (!std::is_pointer<T>::value ||
697 !std::is_same<char, typename std::decay<
698 typename std::remove_pointer<T>::type>::type>::value) &&
699 std::is_convertible<T, StringPiece>::value>::type>
702 explicit FormatValue(StringPiece val) : val_(val) { }
704 template <class FormatCallback>
705 void format(FormatArg& arg, FormatCallback& cb) const {
706 if (arg.keyEmpty()) {
707 arg.validate(FormatArg::Type::OTHER);
708 CHECK(arg.presentation == FormatArg::kDefaultPresentation ||
709 arg.presentation == 's')
710 << arg.errorStr("invalid specifier '", arg.presentation, "'");
711 format_value::formatString(val_, arg, cb);
713 FormatValue<char>(val_.at(arg.splitIntKey())).format(arg, cb);
723 class FormatValue<std::nullptr_t> {
725 explicit FormatValue(std::nullptr_t) { }
727 template <class FormatCallback>
728 void format(FormatArg& arg, FormatCallback& cb) const {
729 arg.validate(FormatArg::Type::OTHER);
730 CHECK(arg.presentation == FormatArg::kDefaultPresentation)
731 << arg.errorStr("invalid specifier '", arg.presentation, "'");
732 format_value::formatString("(null)", arg, cb);
736 // Partial specialization of FormatValue for char*
740 typename std::enable_if<
741 std::is_same<char, typename std::decay<T>::type>::value>::type>
744 explicit FormatValue(T* val) : val_(val) { }
746 template <class FormatCallback>
747 void format(FormatArg& arg, FormatCallback& cb) const {
748 if (arg.keyEmpty()) {
750 FormatValue<std::nullptr_t>(nullptr).format(arg, cb);
752 FormatValue<StringPiece>(val_).format(arg, cb);
755 FormatValue<typename std::decay<T>::type>(
756 val_[arg.splitIntKey()]).format(arg, cb);
764 // Partial specialization of FormatValue for void*
768 typename std::enable_if<
769 std::is_same<void, typename std::decay<T>::type>::value>::type>
772 explicit FormatValue(T* val) : val_(val) { }
774 template <class FormatCallback>
775 void format(FormatArg& arg, FormatCallback& cb) const {
777 FormatValue<std::nullptr_t>(nullptr).format(arg, cb);
779 // Print as a pointer, in hex.
780 arg.validate(FormatArg::Type::OTHER);
781 CHECK(arg.presentation == FormatArg::kDefaultPresentation)
782 << arg.errorStr("invalid specifier '", arg.presentation, "'");
783 arg.basePrefix = true;
784 arg.presentation = 'x';
785 if (arg.align == FormatArg::Align::DEFAULT) {
786 arg.align = FormatArg::Align::LEFT;
788 FormatValue<uintptr_t>(
789 reinterpret_cast<uintptr_t>(val_)).doFormat(arg, cb);
797 template <class T, class = void>
798 class TryFormatValue {
800 template <class FormatCallback>
801 static void formatOrFail(T& value, FormatArg& arg, FormatCallback& cb) {
802 LOG(FATAL) << arg.errorStr("No formatter available for this type");
807 class TryFormatValue<
809 typename std::enable_if<
810 0 < sizeof(FormatValue<typename std::decay<T>::type>)>::type>
813 template <class FormatCallback>
814 static void formatOrFail(T& value, FormatArg& arg, FormatCallback& cb) {
815 FormatValue<typename std::decay<T>::type>(value).format(arg, cb);
819 // Partial specialization of FormatValue for other pointers
823 typename std::enable_if<
824 !std::is_same<char, typename std::decay<T>::type>::value &&
825 !std::is_same<void, typename std::decay<T>::type>::value>::type>
828 explicit FormatValue(T* val) : val_(val) { }
830 template <class FormatCallback>
831 void format(FormatArg& arg, FormatCallback& cb) const {
832 if (arg.keyEmpty()) {
833 FormatValue<void*>((void*)val_).format(arg, cb);
835 TryFormatValue<T>::formatOrFail(val_[arg.splitIntKey()], arg, cb);
844 // Shortcut, so we don't have to use enable_if everywhere
845 struct FormatTraitsBase {
846 typedef void enabled;
849 // Traits that define enabled, value_type, and at() for anything
850 // indexable with integral keys: pointers, arrays, vectors, and maps
851 // with integral keys
852 template <class T, class Enable=void> struct IndexableTraits;
854 // Base class for sequences (vectors, deques)
856 struct IndexableTraitsSeq : public FormatTraitsBase {
857 typedef C container_type;
858 typedef typename C::value_type value_type;
859 static const value_type& at(const C& c, int idx) {
864 // Base class for associative types (maps)
866 struct IndexableTraitsAssoc : public FormatTraitsBase {
867 typedef typename C::value_type::second_type value_type;
868 static const value_type& at(const C& c, int idx) {
869 return c.at(static_cast<typename C::key_type>(idx));
874 template <class T, size_t N>
875 struct IndexableTraits<std::array<T, N>>
876 : public IndexableTraitsSeq<std::array<T, N>> {
880 template <class T, class A>
881 struct IndexableTraits<std::vector<T, A>>
882 : public IndexableTraitsSeq<std::vector<T, A>> {
886 template <class T, class A>
887 struct IndexableTraits<std::deque<T, A>>
888 : public IndexableTraitsSeq<std::deque<T, A>> {
892 template <class T, class A>
893 struct IndexableTraits<fbvector<T, A>>
894 : public IndexableTraitsSeq<fbvector<T, A>> {
898 template <class T, size_t M, class A, class B, class C>
899 struct IndexableTraits<small_vector<T, M, A, B, C>>
900 : public IndexableTraitsSeq<small_vector<T, M, A, B, C>> {
903 // std::map with integral keys
904 template <class K, class T, class C, class A>
905 struct IndexableTraits<
906 std::map<K, T, C, A>,
907 typename std::enable_if<std::is_integral<K>::value>::type>
908 : public IndexableTraitsAssoc<std::map<K, T, C, A>> {
911 // std::unordered_map with integral keys
912 template <class K, class T, class H, class E, class A>
913 struct IndexableTraits<
914 std::unordered_map<K, T, H, E, A>,
915 typename std::enable_if<std::is_integral<K>::value>::type>
916 : public IndexableTraitsAssoc<std::unordered_map<K, T, H, E, A>> {
919 } // namespace detail
921 // Partial specialization of FormatValue for integer-indexable containers
925 typename detail::IndexableTraits<T>::enabled> {
927 explicit FormatValue(const T& val) : val_(val) { }
929 template <class FormatCallback>
930 void format(FormatArg& arg, FormatCallback& cb) const {
931 FormatValue<typename std::decay<
932 typename detail::IndexableTraits<T>::value_type>::type>(
933 detail::IndexableTraits<T>::at(
934 val_, arg.splitIntKey())).format(arg, cb);
943 // Define enabled, key_type, convert from StringPiece to the key types
945 template <class T> struct KeyFromStringPiece;
949 struct KeyFromStringPiece<std::string> : public FormatTraitsBase {
950 typedef std::string key_type;
951 static std::string convert(StringPiece s) {
954 typedef void enabled;
959 struct KeyFromStringPiece<fbstring> : public FormatTraitsBase {
960 typedef fbstring key_type;
961 static fbstring convert(StringPiece s) {
962 return s.toFbstring();
968 struct KeyFromStringPiece<StringPiece> : public FormatTraitsBase {
969 typedef StringPiece key_type;
970 static StringPiece convert(StringPiece s) {
975 // Base class for associative types keyed by strings
976 template <class T> struct KeyableTraitsAssoc : public FormatTraitsBase {
977 typedef typename T::key_type key_type;
978 typedef typename T::value_type::second_type value_type;
979 static const value_type& at(const T& map, StringPiece key) {
980 return map.at(KeyFromStringPiece<key_type>::convert(key));
984 // Define enabled, key_type, value_type, at() for supported string-keyed
986 template <class T, class Enabled=void> struct KeyableTraits;
988 // std::map with string key
989 template <class K, class T, class C, class A>
990 struct KeyableTraits<
991 std::map<K, T, C, A>,
992 typename KeyFromStringPiece<K>::enabled>
993 : public KeyableTraitsAssoc<std::map<K, T, C, A>> {
996 // std::unordered_map with string key
997 template <class K, class T, class H, class E, class A>
998 struct KeyableTraits<
999 std::unordered_map<K, T, H, E, A>,
1000 typename KeyFromStringPiece<K>::enabled>
1001 : public KeyableTraitsAssoc<std::unordered_map<K, T, H, E, A>> {
1004 } // namespace detail
1006 // Partial specialization of FormatValue for string-keyed containers
1010 typename detail::KeyableTraits<T>::enabled> {
1012 explicit FormatValue(const T& val) : val_(val) { }
1014 template <class FormatCallback>
1015 void format(FormatArg& arg, FormatCallback& cb) const {
1016 FormatValue<typename std::decay<
1017 typename detail::KeyableTraits<T>::value_type>::type>(
1018 detail::KeyableTraits<T>::at(
1019 val_, arg.splitKey())).format(arg, cb);
1026 // Partial specialization of FormatValue for pairs
1027 template <class A, class B>
1028 class FormatValue<std::pair<A, B>> {
1030 explicit FormatValue(const std::pair<A, B>& val) : val_(val) { }
1032 template <class FormatCallback>
1033 void format(FormatArg& arg, FormatCallback& cb) const {
1034 int key = arg.splitIntKey();
1037 FormatValue<typename std::decay<A>::type>(val_.first).format(arg, cb);
1040 FormatValue<typename std::decay<B>::type>(val_.second).format(arg, cb);
1043 LOG(FATAL) << arg.errorStr("invalid index for pair");
1048 const std::pair<A, B>& val_;
1051 // Partial specialization of FormatValue for tuples
1052 template <class... Args>
1053 class FormatValue<std::tuple<Args...>> {
1054 typedef std::tuple<Args...> Tuple;
1056 explicit FormatValue(const Tuple& val) : val_(val) { }
1058 template <class FormatCallback>
1059 void format(FormatArg& arg, FormatCallback& cb) const {
1060 int key = arg.splitIntKey();
1061 CHECK(key >= 0) << arg.errorStr("tuple index must be non-negative");
1062 doFormat(key, arg, cb);
1066 static constexpr size_t valueCount = std::tuple_size<Tuple>::value;
1068 template <size_t K, class Callback>
1069 typename std::enable_if<K == valueCount>::type
1070 doFormatFrom(size_t i, FormatArg& arg, Callback& cb) const {
1071 LOG(FATAL) << arg.errorStr("tuple index out of range, max=", i);
1074 template <size_t K, class Callback>
1075 typename std::enable_if<(K < valueCount)>::type
1076 doFormatFrom(size_t i, FormatArg& arg, Callback& cb) const {
1078 FormatValue<typename std::decay<
1079 typename std::tuple_element<K, Tuple>::type>::type>(
1080 std::get<K>(val_)).format(arg, cb);
1082 doFormatFrom<K+1>(i, arg, cb);
1086 template <class Callback>
1087 void doFormat(size_t i, FormatArg& arg, Callback& cb) const {
1088 return doFormatFrom<0>(i, arg, cb);
1094 // Partial specialization of FormatValue for nested Formatters
1095 template <bool containerMode, class... Args>
1096 class FormatValue<Formatter<containerMode, Args...>, void> {
1097 typedef Formatter<containerMode, Args...> FormatterValue;
1099 explicit FormatValue(const FormatterValue& f) : f_(f) { }
1101 template <class FormatCallback>
1102 void format(FormatArg& arg, FormatCallback& cb) const {
1103 format_value::formatFormatter(f_, arg, cb);
1106 const FormatterValue& f_;
1110 * Formatter objects can be appended to strings, and therefore they're
1111 * compatible with folly::toAppend and folly::to.
1113 template <class Tgt, bool containerMode, class... Args>
1114 typename std::enable_if<
1115 IsSomeString<Tgt>::value>::type
1116 toAppend(const Formatter<containerMode, Args...>& value, Tgt * result) {
1117 value.appendTo(*result);
1120 } // namespace folly