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.
25 extern const char formatHexUpper[256][2];
26 extern const char formatHexLower[256][2];
27 extern const char formatOctal[512][3];
28 extern const char formatBinary[256][8];
30 const size_t kMaxHexLength = 2 * sizeof(uintmax_t);
31 const size_t kMaxOctalLength = 3 * sizeof(uintmax_t);
32 const size_t kMaxBinaryLength = 8 * sizeof(uintmax_t);
35 * Convert an unsigned to hex, using repr (which maps from each possible
36 * 2-hex-bytes value to the 2-character representation).
38 * Just like folly::detail::uintToBuffer in Conv.h, writes at the *end* of
39 * the supplied buffer and returns the offset of the beginning of the string
40 * from the start of the buffer. The formatted string will be in range
41 * [buf+begin, buf+bufLen).
44 size_t uintToHex(char* buffer, size_t bufLen, Uint v,
45 const char (&repr)[256][2]) {
46 // 'v >>= 7, v >>= 1' is no more than a work around to get rid of shift size
47 // warning when Uint = uint8_t (it's false as v >= 256 implies sizeof(v) > 1).
48 for (; v >= 256; v >>= 7, v >>= 1) {
51 buffer[bufLen] = repr[b][0];
52 buffer[bufLen + 1] = repr[b][1];
54 buffer[--bufLen] = repr[v][1];
56 buffer[--bufLen] = repr[v][0];
62 * Convert an unsigned to hex, using lower-case letters for the digits
63 * above 9. See the comments for uintToHex.
66 inline size_t uintToHexLower(char* buffer, size_t bufLen, Uint v) {
67 return uintToHex(buffer, bufLen, v, formatHexLower);
71 * Convert an unsigned to hex, using upper-case letters for the digits
72 * above 9. See the comments for uintToHex.
75 inline size_t uintToHexUpper(char* buffer, size_t bufLen, Uint v) {
76 return uintToHex(buffer, bufLen, v, formatHexUpper);
80 * Convert an unsigned to octal.
82 * Just like folly::detail::uintToBuffer in Conv.h, writes at the *end* of
83 * the supplied buffer and returns the offset of the beginning of the string
84 * from the start of the buffer. The formatted string will be in range
85 * [buf+begin, buf+bufLen).
88 size_t uintToOctal(char* buffer, size_t bufLen, Uint v) {
89 auto& repr = formatOctal;
90 // 'v >>= 7, v >>= 2' is no more than a work around to get rid of shift size
91 // warning when Uint = uint8_t (it's false as v >= 512 implies sizeof(v) > 1).
92 for (; v >= 512; v >>= 7, v >>= 2) {
95 buffer[bufLen] = repr[b][0];
96 buffer[bufLen + 1] = repr[b][1];
97 buffer[bufLen + 2] = repr[b][2];
99 buffer[--bufLen] = repr[v][2];
101 buffer[--bufLen] = repr[v][1];
104 buffer[--bufLen] = repr[v][0];
110 * Convert an unsigned to binary.
112 * Just like folly::detail::uintToBuffer in Conv.h, writes at the *end* of
113 * the supplied buffer and returns the offset of the beginning of the string
114 * from the start of the buffer. The formatted string will be in range
115 * [buf+begin, buf+bufLen).
117 template <class Uint>
118 size_t uintToBinary(char* buffer, size_t bufLen, Uint v) {
119 auto& repr = formatBinary;
121 buffer[--bufLen] = '0';
124 for (; v; v >>= 7, v >>= 1) {
127 memcpy(buffer + bufLen, &(repr[b][0]), 8);
129 while (buffer[bufLen] == '0') {
135 } // namespace detail
138 template <bool containerMode, class... Args>
139 Formatter<containerMode, Args...>::Formatter(StringPiece str, Args&&... args)
141 values_(FormatValue<typename std::decay<Args>::type>(
142 std::forward<Args>(args))...) {
143 static_assert(!containerMode || sizeof...(Args) == 1,
144 "Exactly one argument required in container mode");
147 template <bool containerMode, class... Args>
148 template <class Output>
149 void Formatter<containerMode, Args...>::operator()(Output& out) const {
150 auto p = str_.begin();
151 auto end = str_.end();
153 // Copy raw string (without format specifiers) to output;
154 // not as simple as we'd like, as we still need to translate "}}" to "}"
155 // and throw if we see any lone "}"
156 auto outputString = [&out] (StringPiece s) {
160 auto q = static_cast<const char*>(memchr(p, '}', end - p));
162 out(StringPiece(p, end));
166 out(StringPiece(p, q));
169 if (p == end || *p != '}') {
170 throw std::invalid_argument(
171 "folly::format: 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));
190 throw std::invalid_argument(
191 "folly::format: '}' at end of format string");
196 out(StringPiece(p, 1));
202 q = static_cast<const char*>(memchr(p, '}', end - p));
204 throw std::invalid_argument("folly::format: missing ending '}'");
206 FormatArg arg(StringPiece(p, q));
210 auto piece = arg.splitKey<true>(); // empty key component is okay
211 if (containerMode) { // static
213 arg.setNextIntKey(nextArg++);
214 hasDefaultArgIndex = true;
216 arg.setNextKey(piece);
217 hasExplicitArgIndex = true;
221 argIndex = nextArg++;
222 hasDefaultArgIndex = true;
225 argIndex = to<int>(piece);
226 } catch (const std::out_of_range& e) {
227 arg.error("argument index must be integer");
229 arg.enforce(argIndex >= 0, "argument index must be non-negative");
230 hasExplicitArgIndex = true;
234 if (hasDefaultArgIndex && hasExplicitArgIndex) {
235 throw std::invalid_argument(
236 "folly::format: may not have both default and explicit arg indexes");
239 doFormat(argIndex, arg, out);
243 namespace format_value {
245 template <class FormatCallback>
246 void formatString(StringPiece val, FormatArg& arg, FormatCallback& cb) {
247 if (arg.precision != FormatArg::kDefaultPrecision &&
248 val.size() > arg.precision) {
249 val.reset(val.data(), arg.precision);
252 constexpr int padBufSize = 128;
253 char padBuf[padBufSize];
255 // Output padding, no more than padBufSize at once
256 auto pad = [&padBuf, &cb, padBufSize] (int chars) {
258 int n = std::min(chars, padBufSize);
259 cb(StringPiece(padBuf, n));
264 int padRemaining = 0;
265 if (arg.width != FormatArg::kDefaultWidth && val.size() < arg.width) {
266 char fill = arg.fill == FormatArg::kDefaultFill ? ' ' : arg.fill;
267 int padChars = arg.width - val.size();
268 memset(padBuf, fill, std::min(padBufSize, padChars));
271 case FormatArg::Align::DEFAULT:
272 case FormatArg::Align::LEFT:
273 padRemaining = padChars;
275 case FormatArg::Align::CENTER:
277 padRemaining = padChars - padChars / 2;
279 case FormatArg::Align::RIGHT:
280 case FormatArg::Align::PAD_AFTER_SIGN:
296 template <class FormatCallback>
297 void formatNumber(StringPiece val, int prefixLen, FormatArg& arg,
298 FormatCallback& cb) {
299 // precision means something different for numbers
300 arg.precision = FormatArg::kDefaultPrecision;
301 if (arg.align == FormatArg::Align::DEFAULT) {
302 arg.align = FormatArg::Align::RIGHT;
303 } else if (prefixLen && arg.align == FormatArg::Align::PAD_AFTER_SIGN) {
304 // Split off the prefix, then do any padding if necessary
305 cb(val.subpiece(0, prefixLen));
306 val.advance(prefixLen);
307 arg.width = std::max(arg.width - prefixLen, 0);
309 format_value::formatString(val, arg, cb);
312 template <class FormatCallback, bool containerMode, class... Args>
313 void formatFormatter(const Formatter<containerMode, Args...>& formatter,
315 FormatCallback& cb) {
316 if (arg.width == FormatArg::kDefaultWidth &&
317 arg.precision == FormatArg::kDefaultPrecision) {
320 } else if (arg.align != FormatArg::Align::LEFT &&
321 arg.align != FormatArg::Align::DEFAULT) {
322 // We can only avoid creating a temporary string if we align left,
323 // as we'd need to know the size beforehand otherwise
324 format_value::formatString(formatter.fbstr(), arg, cb);
326 auto fn = [&arg, &cb] (StringPiece sp) mutable {
327 int sz = static_cast<int>(sp.size());
328 if (arg.precision != FormatArg::kDefaultPrecision) {
329 sz = std::min(arg.precision, sz);
330 sp.reset(sp.data(), sz);
335 if (arg.width != FormatArg::kDefaultWidth) {
336 arg.width = std::max(arg.width - sz, 0);
341 if (arg.width != FormatArg::kDefaultWidth && arg.width != 0) {
342 // Rely on formatString to do appropriate padding
343 format_value::formatString(StringPiece(), arg, cb);
348 } // namespace format_value
350 // Definitions for default FormatValue classes
352 // Integral types (except bool)
355 T, typename std::enable_if<
356 std::is_integral<T>::value &&
357 !std::is_same<T, bool>::value>::type>
360 explicit FormatValue(T val) : val_(val) { }
361 template <class FormatCallback>
362 void format(FormatArg& arg, FormatCallback& cb) const {
363 arg.validate(FormatArg::Type::INTEGER);
367 template <class FormatCallback>
368 void doFormat(FormatArg& arg, FormatCallback& cb) const {
369 char presentation = arg.presentation;
370 if (presentation == FormatArg::kDefaultPresentation) {
371 presentation = std::is_same<T, char>::value ? 'c' : 'd';
374 // Do all work as unsigned, we'll add the prefix ('0' or '0x' if necessary)
375 // and sign ourselves.
376 typedef typename std::make_unsigned<T>::type UT;
379 if (std::is_signed<T>::value) {
380 if (folly::is_negative(val_)) {
381 uval = static_cast<UT>(-val_);
384 uval = static_cast<UT>(val_);
386 case FormatArg::Sign::PLUS_OR_MINUS:
389 case FormatArg::Sign::SPACE_OR_MINUS:
401 arg.enforce(arg.sign == FormatArg::Sign::DEFAULT,
402 "sign specifications not allowed for unsigned values");
406 // #x: 0x prefix + 16 bytes = 18 bytes
407 // #o: 0 prefix + 22 bytes = 23 bytes
408 // #b: 0b prefix + 64 bytes = 65 bytes
409 // ,d: 26 bytes (including thousands separators!)
411 // + 3 for sign and prefix shenanigans (see below)
412 constexpr size_t valBufSize = 69;
413 char valBuf[valBufSize];
414 char* valBufBegin = nullptr;
415 char* valBufEnd = nullptr;
418 auto useSprintf = [&] (const char* format) mutable {
419 valBufBegin = valBuf + 3; // room for sign and base prefix
420 valBufEnd = valBufBegin + sprintf(valBufBegin, format,
421 static_cast<uintmax_t>(uval));
426 switch (presentation) {
427 case 'n': // TODO(tudorb): locale awareness?
429 arg.enforce(!arg.basePrefix,
430 "base prefix not allowed with '", presentation,
432 if (arg.thousandsSeparator) {
435 // Use uintToBuffer, faster than sprintf
436 valBufBegin = valBuf + 3;
437 valBufEnd = valBufBegin + uint64ToBufferUnsafe(uval, valBufBegin);
441 arg.enforce(!arg.basePrefix,
442 "base prefix not allowed with '", presentation,
444 arg.enforce(!arg.thousandsSeparator,
445 "thousands separator (',') not allowed with '",
446 presentation, "' specifier");
447 valBufBegin = valBuf + 3;
448 *valBufBegin = static_cast<char>(uval);
449 valBufEnd = valBufBegin + 1;
453 arg.enforce(!arg.thousandsSeparator,
454 "thousands separator (',') not allowed with '",
455 presentation, "' specifier");
456 valBufEnd = valBuf + valBufSize - 1;
457 valBufBegin = valBuf + detail::uintToOctal(valBuf, valBufSize - 1, uval);
458 if (arg.basePrefix) {
459 *--valBufBegin = '0';
464 arg.enforce(!arg.thousandsSeparator,
465 "thousands separator (',') not allowed with '",
466 presentation, "' specifier");
467 valBufEnd = valBuf + valBufSize - 1;
468 valBufBegin = valBuf + detail::uintToHexLower(valBuf, valBufSize - 1,
470 if (arg.basePrefix) {
471 *--valBufBegin = 'x';
472 *--valBufBegin = '0';
477 arg.enforce(!arg.thousandsSeparator,
478 "thousands separator (',') not allowed with '",
479 presentation, "' specifier");
480 valBufEnd = valBuf + valBufSize - 1;
481 valBufBegin = valBuf + detail::uintToHexUpper(valBuf, valBufSize - 1,
483 if (arg.basePrefix) {
484 *--valBufBegin = 'X';
485 *--valBufBegin = '0';
491 arg.enforce(!arg.thousandsSeparator,
492 "thousands separator (',') not allowed with '",
493 presentation, "' specifier");
494 valBufEnd = valBuf + valBufSize - 1;
495 valBufBegin = valBuf + detail::uintToBinary(valBuf, valBufSize - 1,
497 if (arg.basePrefix) {
498 *--valBufBegin = presentation; // 0b or 0B
499 *--valBufBegin = '0';
504 arg.error("invalid specifier '", presentation, "'");
508 *--valBufBegin = sign;
512 format_value::formatNumber(StringPiece(valBufBegin, valBufEnd), prefixLen,
522 class FormatValue<bool> {
524 explicit FormatValue(bool val) : val_(val) { }
526 template <class FormatCallback>
527 void format(FormatArg& arg, FormatCallback& cb) const {
528 if (arg.presentation == FormatArg::kDefaultPresentation) {
529 arg.validate(FormatArg::Type::OTHER);
530 format_value::formatString(val_ ? "true" : "false", arg, cb);
532 FormatValue<int>(val_).format(arg, cb);
542 class FormatValue<double> {
544 explicit FormatValue(double val) : val_(val) { }
546 template <class FormatCallback>
547 void format(FormatArg& arg, FormatCallback& cb) const {
548 using ::double_conversion::DoubleToStringConverter;
549 using ::double_conversion::StringBuilder;
551 arg.validate(FormatArg::Type::FLOAT);
553 if (arg.presentation == FormatArg::kDefaultPresentation) {
554 arg.presentation = 'g';
557 const char* infinitySymbol = isupper(arg.presentation) ? "INF" : "inf";
558 const char* nanSymbol = isupper(arg.presentation) ? "NAN" : "nan";
559 char exponentSymbol = isupper(arg.presentation) ? 'E' : 'e';
561 if (arg.precision == FormatArg::kDefaultPrecision) {
565 // 2+: for null terminator and optional sign shenanigans.
566 char buf[2 + std::max({
567 (2 + DoubleToStringConverter::kMaxFixedDigitsBeforePoint +
568 DoubleToStringConverter::kMaxFixedDigitsAfterPoint),
569 (8 + DoubleToStringConverter::kMaxExponentialDigits),
570 (7 + DoubleToStringConverter::kMaxPrecisionDigits)})];
571 StringBuilder builder(buf + 1, sizeof(buf) - 1);
575 case FormatArg::Sign::PLUS_OR_MINUS:
578 case FormatArg::Sign::SPACE_OR_MINUS:
587 switch (arg.presentation) {
594 DoubleToStringConverter::kMaxFixedDigitsAfterPoint) {
595 arg.precision = DoubleToStringConverter::kMaxFixedDigitsAfterPoint;
597 DoubleToStringConverter conv(
598 DoubleToStringConverter::EMIT_POSITIVE_EXPONENT_SIGN,
604 arg.enforce(conv.ToFixed(val, arg.precision, &builder),
605 "fixed double conversion failed");
611 if (arg.precision > DoubleToStringConverter::kMaxExponentialDigits) {
612 arg.precision = DoubleToStringConverter::kMaxExponentialDigits;
615 DoubleToStringConverter conv(
616 DoubleToStringConverter::EMIT_POSITIVE_EXPONENT_SIGN,
622 CHECK(conv.ToExponential(val, arg.precision, &builder));
625 case 'n': // should be locale-aware, but isn't
629 if (arg.precision < DoubleToStringConverter::kMinPrecisionDigits) {
630 arg.precision = DoubleToStringConverter::kMinPrecisionDigits;
631 } else if (arg.precision >
632 DoubleToStringConverter::kMaxPrecisionDigits) {
633 arg.precision = DoubleToStringConverter::kMaxPrecisionDigits;
635 DoubleToStringConverter conv(
636 DoubleToStringConverter::EMIT_POSITIVE_EXPONENT_SIGN,
642 CHECK(conv.ToShortest(val, &builder));
646 arg.error("invalid specifier '", arg.presentation, "'");
649 int len = builder.position();
653 // Add '+' or ' ' sign if needed
655 // anything that's neither negative nor nan
657 if (plusSign && (*p != '-' && *p != 'n' && *p != 'N')) {
661 } else if (*p == '-') {
665 format_value::formatNumber(StringPiece(p, len), prefixLen, arg, cb);
672 // float (defer to double)
674 class FormatValue<float> {
676 explicit FormatValue(float val) : val_(val) { }
678 template <class FormatCallback>
679 void format(FormatArg& arg, FormatCallback& cb) const {
680 FormatValue<double>(val_).format(arg, cb);
687 // Sring-y types (implicitly convertible to StringPiece, except char*)
690 T, typename std::enable_if<
691 (!std::is_pointer<T>::value ||
692 !std::is_same<char, typename std::decay<
693 typename std::remove_pointer<T>::type>::type>::value) &&
694 std::is_convertible<T, StringPiece>::value>::type>
697 explicit FormatValue(StringPiece val) : val_(val) { }
699 template <class FormatCallback>
700 void format(FormatArg& arg, FormatCallback& cb) const {
701 if (arg.keyEmpty()) {
702 arg.validate(FormatArg::Type::OTHER);
703 arg.enforce(arg.presentation == FormatArg::kDefaultPresentation ||
704 arg.presentation == 's',
705 "invalid specifier '", arg.presentation, "'");
706 format_value::formatString(val_, arg, cb);
708 FormatValue<char>(val_.at(arg.splitIntKey())).format(arg, cb);
718 class FormatValue<std::nullptr_t> {
720 explicit FormatValue(std::nullptr_t) { }
722 template <class FormatCallback>
723 void format(FormatArg& arg, FormatCallback& cb) const {
724 arg.validate(FormatArg::Type::OTHER);
725 arg.enforce(arg.presentation == FormatArg::kDefaultPresentation,
726 "invalid specifier '", arg.presentation, "'");
727 format_value::formatString("(null)", arg, cb);
731 // Partial specialization of FormatValue for char*
735 typename std::enable_if<
736 std::is_same<char, typename std::decay<T>::type>::value>::type>
739 explicit FormatValue(T* val) : val_(val) { }
741 template <class FormatCallback>
742 void format(FormatArg& arg, FormatCallback& cb) const {
743 if (arg.keyEmpty()) {
745 FormatValue<std::nullptr_t>(nullptr).format(arg, cb);
747 FormatValue<StringPiece>(val_).format(arg, cb);
750 FormatValue<typename std::decay<T>::type>(
751 val_[arg.splitIntKey()]).format(arg, cb);
759 // Partial specialization of FormatValue for void*
763 typename std::enable_if<
764 std::is_same<void, typename std::decay<T>::type>::value>::type>
767 explicit FormatValue(T* val) : val_(val) { }
769 template <class FormatCallback>
770 void format(FormatArg& arg, FormatCallback& cb) const {
772 FormatValue<std::nullptr_t>(nullptr).format(arg, cb);
774 // Print as a pointer, in hex.
775 arg.validate(FormatArg::Type::OTHER);
776 arg.enforce(arg.presentation == FormatArg::kDefaultPresentation,
777 "invalid specifier '", arg.presentation, "'");
778 arg.basePrefix = true;
779 arg.presentation = 'x';
780 if (arg.align == FormatArg::Align::DEFAULT) {
781 arg.align = FormatArg::Align::LEFT;
783 FormatValue<uintptr_t>(
784 reinterpret_cast<uintptr_t>(val_)).doFormat(arg, cb);
792 template <class T, class = void>
793 class TryFormatValue {
795 template <class FormatCallback>
796 static void formatOrFail(T& value, FormatArg& arg, FormatCallback& cb) {
797 arg.error("No formatter available for this type");
802 class TryFormatValue<
804 typename std::enable_if<
805 0 < sizeof(FormatValue<typename std::decay<T>::type>)>::type>
808 template <class FormatCallback>
809 static void formatOrFail(T& value, FormatArg& arg, FormatCallback& cb) {
810 FormatValue<typename std::decay<T>::type>(value).format(arg, cb);
814 // Partial specialization of FormatValue for other pointers
818 typename std::enable_if<
819 !std::is_same<char, typename std::decay<T>::type>::value &&
820 !std::is_same<void, typename std::decay<T>::type>::value>::type>
823 explicit FormatValue(T* val) : val_(val) { }
825 template <class FormatCallback>
826 void format(FormatArg& arg, FormatCallback& cb) const {
827 if (arg.keyEmpty()) {
828 FormatValue<void*>((void*)val_).format(arg, cb);
830 TryFormatValue<T>::formatOrFail(val_[arg.splitIntKey()], arg, cb);
839 // Shortcut, so we don't have to use enable_if everywhere
840 struct FormatTraitsBase {
841 typedef void enabled;
844 // Traits that define enabled, value_type, and at() for anything
845 // indexable with integral keys: pointers, arrays, vectors, and maps
846 // with integral keys
847 template <class T, class Enable=void> struct IndexableTraits;
849 // Base class for sequences (vectors, deques)
851 struct IndexableTraitsSeq : public FormatTraitsBase {
852 typedef C container_type;
853 typedef typename C::value_type value_type;
854 static const value_type& at(const C& c, int idx) {
859 // Base class for associative types (maps)
861 struct IndexableTraitsAssoc : public FormatTraitsBase {
862 typedef typename C::value_type::second_type value_type;
863 static const value_type& at(const C& c, int idx) {
864 return c.at(static_cast<typename C::key_type>(idx));
869 template <class T, size_t N>
870 struct IndexableTraits<std::array<T, N>>
871 : public IndexableTraitsSeq<std::array<T, N>> {
875 template <class T, class A>
876 struct IndexableTraits<std::vector<T, A>>
877 : public IndexableTraitsSeq<std::vector<T, A>> {
881 template <class T, class A>
882 struct IndexableTraits<std::deque<T, A>>
883 : public IndexableTraitsSeq<std::deque<T, A>> {
887 template <class T, class A>
888 struct IndexableTraits<fbvector<T, A>>
889 : public IndexableTraitsSeq<fbvector<T, A>> {
893 template <class T, size_t M, class A, class B, class C>
894 struct IndexableTraits<small_vector<T, M, A, B, C>>
895 : public IndexableTraitsSeq<small_vector<T, M, A, B, C>> {
898 // std::map with integral keys
899 template <class K, class T, class C, class A>
900 struct IndexableTraits<
901 std::map<K, T, C, A>,
902 typename std::enable_if<std::is_integral<K>::value>::type>
903 : public IndexableTraitsAssoc<std::map<K, T, C, A>> {
906 // std::unordered_map with integral keys
907 template <class K, class T, class H, class E, class A>
908 struct IndexableTraits<
909 std::unordered_map<K, T, H, E, A>,
910 typename std::enable_if<std::is_integral<K>::value>::type>
911 : public IndexableTraitsAssoc<std::unordered_map<K, T, H, E, A>> {
914 } // namespace detail
916 // Partial specialization of FormatValue for integer-indexable containers
920 typename detail::IndexableTraits<T>::enabled> {
922 explicit FormatValue(const T& val) : val_(val) { }
924 template <class FormatCallback>
925 void format(FormatArg& arg, FormatCallback& cb) const {
926 FormatValue<typename std::decay<
927 typename detail::IndexableTraits<T>::value_type>::type>(
928 detail::IndexableTraits<T>::at(
929 val_, arg.splitIntKey())).format(arg, cb);
938 // Define enabled, key_type, convert from StringPiece to the key types
940 template <class T> struct KeyFromStringPiece;
944 struct KeyFromStringPiece<std::string> : public FormatTraitsBase {
945 typedef std::string key_type;
946 static std::string convert(StringPiece s) {
949 typedef void enabled;
954 struct KeyFromStringPiece<fbstring> : public FormatTraitsBase {
955 typedef fbstring key_type;
956 static fbstring convert(StringPiece s) {
957 return s.toFbstring();
963 struct KeyFromStringPiece<StringPiece> : public FormatTraitsBase {
964 typedef StringPiece key_type;
965 static StringPiece convert(StringPiece s) {
970 // Base class for associative types keyed by strings
971 template <class T> struct KeyableTraitsAssoc : public FormatTraitsBase {
972 typedef typename T::key_type key_type;
973 typedef typename T::value_type::second_type value_type;
974 static const value_type& at(const T& map, StringPiece key) {
975 return map.at(KeyFromStringPiece<key_type>::convert(key));
979 // Define enabled, key_type, value_type, at() for supported string-keyed
981 template <class T, class Enabled=void> struct KeyableTraits;
983 // std::map with string key
984 template <class K, class T, class C, class A>
985 struct KeyableTraits<
986 std::map<K, T, C, A>,
987 typename KeyFromStringPiece<K>::enabled>
988 : public KeyableTraitsAssoc<std::map<K, T, C, A>> {
991 // std::unordered_map with string key
992 template <class K, class T, class H, class E, class A>
993 struct KeyableTraits<
994 std::unordered_map<K, T, H, E, A>,
995 typename KeyFromStringPiece<K>::enabled>
996 : public KeyableTraitsAssoc<std::unordered_map<K, T, H, E, A>> {
999 } // namespace detail
1001 // Partial specialization of FormatValue for string-keyed containers
1005 typename detail::KeyableTraits<T>::enabled> {
1007 explicit FormatValue(const T& val) : val_(val) { }
1009 template <class FormatCallback>
1010 void format(FormatArg& arg, FormatCallback& cb) const {
1011 FormatValue<typename std::decay<
1012 typename detail::KeyableTraits<T>::value_type>::type>(
1013 detail::KeyableTraits<T>::at(
1014 val_, arg.splitKey())).format(arg, cb);
1021 // Partial specialization of FormatValue for pairs
1022 template <class A, class B>
1023 class FormatValue<std::pair<A, B>> {
1025 explicit FormatValue(const std::pair<A, B>& val) : val_(val) { }
1027 template <class FormatCallback>
1028 void format(FormatArg& arg, FormatCallback& cb) const {
1029 int key = arg.splitIntKey();
1032 FormatValue<typename std::decay<A>::type>(val_.first).format(arg, cb);
1035 FormatValue<typename std::decay<B>::type>(val_.second).format(arg, cb);
1038 arg.error("invalid index for pair");
1043 const std::pair<A, B>& val_;
1046 // Partial specialization of FormatValue for tuples
1047 template <class... Args>
1048 class FormatValue<std::tuple<Args...>> {
1049 typedef std::tuple<Args...> Tuple;
1051 explicit FormatValue(const Tuple& val) : val_(val) { }
1053 template <class FormatCallback>
1054 void format(FormatArg& arg, FormatCallback& cb) const {
1055 int key = arg.splitIntKey();
1056 arg.enforce(key >= 0, "tuple index must be non-negative");
1057 doFormat(key, arg, cb);
1061 static constexpr size_t valueCount = std::tuple_size<Tuple>::value;
1063 template <size_t K, class Callback>
1064 typename std::enable_if<K == valueCount>::type
1065 doFormatFrom(size_t i, FormatArg& arg, Callback& cb) const {
1066 arg.enforce("tuple index out of range, max=", i);
1069 template <size_t K, class Callback>
1070 typename std::enable_if<(K < valueCount)>::type
1071 doFormatFrom(size_t i, FormatArg& arg, Callback& cb) const {
1073 FormatValue<typename std::decay<
1074 typename std::tuple_element<K, Tuple>::type>::type>(
1075 std::get<K>(val_)).format(arg, cb);
1077 doFormatFrom<K+1>(i, arg, cb);
1081 template <class Callback>
1082 void doFormat(size_t i, FormatArg& arg, Callback& cb) const {
1083 return doFormatFrom<0>(i, arg, cb);
1089 // Partial specialization of FormatValue for nested Formatters
1090 template <bool containerMode, class... Args>
1091 class FormatValue<Formatter<containerMode, Args...>, void> {
1092 typedef Formatter<containerMode, Args...> FormatterValue;
1094 explicit FormatValue(const FormatterValue& f) : f_(f) { }
1096 template <class FormatCallback>
1097 void format(FormatArg& arg, FormatCallback& cb) const {
1098 format_value::formatFormatter(f_, arg, cb);
1101 const FormatterValue& f_;
1105 * Formatter objects can be appended to strings, and therefore they're
1106 * compatible with folly::toAppend and folly::to.
1108 template <class Tgt, bool containerMode, class... Args>
1109 typename std::enable_if<
1110 detail::IsSomeString<Tgt>::value>::type
1111 toAppend(const Formatter<containerMode, Args...>& value, Tgt * result) {
1112 value.appendTo(*result);
1115 } // namespace folly