2 * Copyright 2012 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 for (; v >= 256; v >>= 8) {
49 buffer[bufLen] = repr[b][0];
50 buffer[bufLen + 1] = repr[b][1];
52 buffer[--bufLen] = repr[v][1];
54 buffer[--bufLen] = repr[v][0];
60 * Convert an unsigned to hex, using lower-case letters for the digits
61 * above 9. See the comments for uintToHex.
64 inline size_t uintToHexLower(char* buffer, size_t bufLen, Uint v) {
65 return uintToHex(buffer, bufLen, v, formatHexLower);
69 * Convert an unsigned to hex, using upper-case letters for the digits
70 * above 9. See the comments for uintToHex.
73 inline size_t uintToHexUpper(char* buffer, size_t bufLen, Uint v) {
74 return uintToHex(buffer, bufLen, v, formatHexUpper);
78 * Convert an unsigned to octal.
80 * Just like folly::detail::uintToBuffer in Conv.h, writes at the *end* of
81 * the supplied buffer and returns the offset of the beginning of the string
82 * from the start of the buffer. The formatted string will be in range
83 * [buf+begin, buf+bufLen).
86 size_t uintToOctal(char* buffer, size_t bufLen, Uint v) {
87 auto& repr = formatOctal;
88 for (; v >= 512; v >>= 9) {
91 buffer[bufLen] = repr[b][0];
92 buffer[bufLen + 1] = repr[b][1];
93 buffer[bufLen + 2] = repr[b][2];
95 buffer[--bufLen] = repr[v][2];
97 buffer[--bufLen] = repr[v][1];
100 buffer[--bufLen] = repr[v][0];
106 * Convert an unsigned to binary.
108 * Just like folly::detail::uintToBuffer in Conv.h, writes at the *end* of
109 * the supplied buffer and returns the offset of the beginning of the string
110 * from the start of the buffer. The formatted string will be in range
111 * [buf+begin, buf+bufLen).
113 template <class Uint>
114 size_t uintToBinary(char* buffer, size_t bufLen, Uint v) {
115 auto& repr = formatBinary;
117 buffer[--bufLen] = '0';
123 memcpy(buffer + bufLen, &(repr[b][0]), 8);
125 while (buffer[bufLen] == '0') {
131 } // namespace detail
134 template <bool containerMode, class... Args>
135 Formatter<containerMode, Args...>::Formatter(StringPiece str, Args&&... args)
137 values_(FormatValue<typename std::decay<Args>::type>(
138 std::forward<Args>(args))...) {
139 static_assert(!containerMode || sizeof...(Args) == 1,
140 "Exactly one argument required in container mode");
143 template <bool containerMode, class... Args>
144 template <class Output>
145 void Formatter<containerMode, Args...>::operator()(Output& out) const {
146 auto p = str_.begin();
147 auto end = str_.end();
149 // Copy raw string (without format specifiers) to output;
150 // not as simple as we'd like, as we still need to translate "}}" to "}"
151 // and throw if we see any lone "}"
152 auto outputString = [&out] (StringPiece s) {
156 auto q = static_cast<const char*>(memchr(p, '}', end - p));
158 out(StringPiece(p, end));
162 out(StringPiece(p, q));
165 if (p == end || *p != '}') {
166 throw std::invalid_argument(
167 "folly::format: single '}' in format string");
174 bool hasDefaultArgIndex = false;
175 bool hasExplicitArgIndex = false;
177 auto q = static_cast<const char*>(memchr(p, '{', end - p));
179 outputString(StringPiece(p, end));
182 outputString(StringPiece(p, q));
186 throw std::invalid_argument(
187 "folly::format: '}' at end of format string");
192 out(StringPiece(p, 1));
198 q = static_cast<const char*>(memchr(p, '}', end - p));
200 throw std::invalid_argument("folly::format: missing ending '}'");
202 FormatArg arg(StringPiece(p, q));
206 auto piece = arg.splitKey<true>(); // empty key component is okay
207 if (containerMode) { // static
209 arg.setNextIntKey(nextArg++);
210 hasDefaultArgIndex = true;
212 arg.setNextKey(piece);
213 hasExplicitArgIndex = true;
217 argIndex = nextArg++;
218 hasDefaultArgIndex = true;
221 argIndex = to<int>(piece);
222 } catch (const std::out_of_range& e) {
223 arg.error("argument index must be integer");
225 arg.enforce(argIndex >= 0, "argument index must be non-negative");
226 hasExplicitArgIndex = true;
230 if (hasDefaultArgIndex && hasExplicitArgIndex) {
231 throw std::invalid_argument(
232 "folly::format: may not have both default and explicit arg indexes");
235 doFormat(argIndex, arg, out);
239 namespace format_value {
241 template <class FormatCallback>
242 void formatString(StringPiece val, FormatArg& arg, FormatCallback& cb) {
243 if (arg.precision != FormatArg::kDefaultPrecision &&
244 val.size() > arg.precision) {
245 val.reset(val.data(), arg.precision);
248 constexpr int padBufSize = 128;
249 char padBuf[padBufSize];
251 // Output padding, no more than padBufSize at once
252 auto pad = [&padBuf, &cb, padBufSize] (int chars) {
254 int n = std::min(chars, padBufSize);
255 cb(StringPiece(padBuf, n));
260 int padRemaining = 0;
261 if (arg.width != FormatArg::kDefaultWidth && val.size() < arg.width) {
262 char fill = arg.fill == FormatArg::kDefaultFill ? ' ' : arg.fill;
263 int padChars = arg.width - val.size();
264 memset(padBuf, fill, std::min(padBufSize, padChars));
267 case FormatArg::Align::DEFAULT:
268 case FormatArg::Align::LEFT:
269 padRemaining = padChars;
271 case FormatArg::Align::CENTER:
273 padRemaining = padChars - padChars / 2;
275 case FormatArg::Align::RIGHT:
276 case FormatArg::Align::PAD_AFTER_SIGN:
292 template <class FormatCallback>
293 void formatNumber(StringPiece val, int prefixLen, FormatArg& arg,
294 FormatCallback& cb) {
295 // precision means something different for numbers
296 arg.precision = FormatArg::kDefaultPrecision;
297 if (arg.align == FormatArg::Align::DEFAULT) {
298 arg.align = FormatArg::Align::RIGHT;
299 } else if (prefixLen && arg.align == FormatArg::Align::PAD_AFTER_SIGN) {
300 // Split off the prefix, then do any padding if necessary
301 cb(val.subpiece(0, prefixLen));
302 val.advance(prefixLen);
303 arg.width = std::max(arg.width - prefixLen, 0);
305 format_value::formatString(val, arg, cb);
308 template <class FormatCallback, bool containerMode, class... Args>
309 void formatFormatter(const Formatter<containerMode, Args...>& formatter,
311 FormatCallback& cb) {
312 if (arg.width == FormatArg::kDefaultWidth &&
313 arg.precision == FormatArg::kDefaultPrecision) {
316 } else if (arg.align != FormatArg::Align::LEFT &&
317 arg.align != FormatArg::Align::DEFAULT) {
318 // We can only avoid creating a temporary string if we align left,
319 // as we'd need to know the size beforehand otherwise
320 format_value::formatString(formatter.fbstr(), arg, cb);
322 auto fn = [&arg, &cb] (StringPiece sp) mutable {
323 int sz = static_cast<int>(sp.size());
324 if (arg.precision != FormatArg::kDefaultPrecision) {
325 sz = std::min(arg.precision, sz);
326 sp.reset(sp.data(), sz);
331 if (arg.width != FormatArg::kDefaultWidth) {
332 arg.width = std::max(arg.width - sz, 0);
337 if (arg.width != FormatArg::kDefaultWidth && arg.width != 0) {
338 // Rely on formatString to do appropriate padding
339 format_value::formatString(StringPiece(), arg, cb);
344 } // namespace format_value
346 // Definitions for default FormatValue classes
348 // Integral types (except bool)
351 T, typename std::enable_if<
352 std::is_integral<T>::value &&
353 !std::is_same<T, bool>::value>::type>
356 explicit FormatValue(T val) : val_(val) { }
357 template <class FormatCallback>
358 void format(FormatArg& arg, FormatCallback& cb) const {
359 arg.validate(FormatArg::Type::INTEGER);
363 template <class FormatCallback>
364 void doFormat(FormatArg& arg, FormatCallback& cb) const {
365 char presentation = arg.presentation;
366 if (presentation == FormatArg::kDefaultPresentation) {
367 presentation = std::is_same<T, char>::value ? 'c' : 'd';
370 // Do all work as unsigned, we'll add the prefix ('0' or '0x' if necessary)
371 // and sign ourselves.
372 typedef typename std::make_unsigned<T>::type UT;
375 if (std::is_signed<T>::value) {
377 uval = static_cast<UT>(-val_);
380 uval = static_cast<UT>(val_);
382 case FormatArg::Sign::PLUS_OR_MINUS:
385 case FormatArg::Sign::SPACE_OR_MINUS:
397 arg.enforce(arg.sign == FormatArg::Sign::DEFAULT,
398 "sign specifications not allowed for unsigned values");
402 // #x: 0x prefix + 16 bytes = 18 bytes
403 // #o: 0 prefix + 22 bytes = 23 bytes
404 // #b: 0b prefix + 64 bytes = 65 bytes
405 // ,d: 26 bytes (including thousands separators!)
407 // + 3 for sign and prefix shenanigans (see below)
408 constexpr size_t valBufSize = 69;
409 char valBuf[valBufSize];
410 char* valBufBegin = nullptr;
411 char* valBufEnd = nullptr;
414 auto useSprintf = [&] (const char* format) mutable {
415 valBufBegin = valBuf + 3; // room for sign and base prefix
416 valBufEnd = valBufBegin + sprintf(valBufBegin, format,
417 static_cast<uintmax_t>(uval));
422 switch (presentation) {
423 case 'n': // TODO(tudorb): locale awareness?
425 arg.enforce(!arg.basePrefix,
426 "base prefix not allowed with '", presentation,
428 if (arg.thousandsSeparator) {
431 // Use uintToBuffer, faster than sprintf
432 valBufBegin = valBuf + 3;
433 valBufEnd = valBufBegin + uint64ToBufferUnsafe(uval, valBufBegin);
437 arg.enforce(!arg.basePrefix,
438 "base prefix not allowed with '", presentation,
440 arg.enforce(!arg.thousandsSeparator,
441 "thousands separator (',') not allowed with '",
442 presentation, "' specifier");
443 valBufBegin = valBuf + 3;
444 *valBufBegin = static_cast<char>(uval);
445 valBufEnd = valBufBegin + 1;
449 arg.enforce(!arg.thousandsSeparator,
450 "thousands separator (',') not allowed with '",
451 presentation, "' specifier");
452 valBufEnd = valBuf + valBufSize - 1;
453 valBufBegin = valBuf + detail::uintToOctal(valBuf, valBufSize - 1, uval);
454 if (arg.basePrefix) {
455 *--valBufBegin = '0';
460 arg.enforce(!arg.thousandsSeparator,
461 "thousands separator (',') not allowed with '",
462 presentation, "' specifier");
463 valBufEnd = valBuf + valBufSize - 1;
464 valBufBegin = valBuf + detail::uintToHexLower(valBuf, valBufSize - 1,
466 if (arg.basePrefix) {
467 *--valBufBegin = 'x';
468 *--valBufBegin = '0';
473 arg.enforce(!arg.thousandsSeparator,
474 "thousands separator (',') not allowed with '",
475 presentation, "' specifier");
476 valBufEnd = valBuf + valBufSize - 1;
477 valBufBegin = valBuf + detail::uintToHexUpper(valBuf, valBufSize - 1,
479 if (arg.basePrefix) {
480 *--valBufBegin = 'X';
481 *--valBufBegin = '0';
487 arg.enforce(!arg.thousandsSeparator,
488 "thousands separator (',') not allowed with '",
489 presentation, "' specifier");
490 valBufEnd = valBuf + valBufSize - 1;
491 valBufBegin = valBuf + detail::uintToBinary(valBuf, valBufSize - 1,
493 if (arg.basePrefix) {
494 *--valBufBegin = presentation; // 0b or 0B
495 *--valBufBegin = '0';
500 arg.error("invalid specifier '", presentation, "'");
504 *--valBufBegin = sign;
508 format_value::formatNumber(StringPiece(valBufBegin, valBufEnd), prefixLen,
518 class FormatValue<bool> {
520 explicit FormatValue(bool val) : val_(val) { }
522 template <class FormatCallback>
523 void format(FormatArg& arg, FormatCallback& cb) const {
524 if (arg.presentation == FormatArg::kDefaultPresentation) {
525 arg.validate(FormatArg::Type::OTHER);
526 format_value::formatString(val_ ? "true" : "false", arg, cb);
528 FormatValue<int>(val_).format(arg, cb);
538 class FormatValue<double> {
540 explicit FormatValue(double val) : val_(val) { }
542 template <class FormatCallback>
543 void format(FormatArg& arg, FormatCallback& cb) const {
544 using ::double_conversion::DoubleToStringConverter;
545 using ::double_conversion::StringBuilder;
547 arg.validate(FormatArg::Type::FLOAT);
549 if (arg.presentation == FormatArg::kDefaultPresentation) {
550 arg.presentation = 'g';
553 const char* infinitySymbol = isupper(arg.presentation) ? "INF" : "inf";
554 const char* nanSymbol = isupper(arg.presentation) ? "NAN" : "nan";
555 char exponentSymbol = isupper(arg.presentation) ? 'E' : 'e';
557 if (arg.precision == FormatArg::kDefaultPrecision) {
563 // 2+: for null terminator and optional sign shenanigans.
564 char buf[2 + std::max({
565 (2 + DoubleToStringConverter::kMaxFixedDigitsBeforePoint +
566 DoubleToStringConverter::kMaxFixedDigitsAfterPoint),
567 (8 + DoubleToStringConverter::kMaxExponentialDigits),
568 (7 + DoubleToStringConverter::kMaxPrecisionDigits)})];
569 StringBuilder builder(buf + 1, sizeof(buf) - 1);
573 case FormatArg::Sign::PLUS_OR_MINUS:
576 case FormatArg::Sign::SPACE_OR_MINUS:
585 switch (arg.presentation) {
592 DoubleToStringConverter::kMaxFixedDigitsAfterPoint) {
593 arg.precision = DoubleToStringConverter::kMaxFixedDigitsAfterPoint;
595 DoubleToStringConverter conv(
596 DoubleToStringConverter::EMIT_POSITIVE_EXPONENT_SIGN,
602 arg.enforce(conv.ToFixed(val, arg.precision, &builder),
603 "fixed double conversion failed");
609 if (arg.precision > DoubleToStringConverter::kMaxExponentialDigits) {
610 arg.precision = DoubleToStringConverter::kMaxExponentialDigits;
613 DoubleToStringConverter conv(
614 DoubleToStringConverter::EMIT_POSITIVE_EXPONENT_SIGN,
620 CHECK(conv.ToExponential(val, arg.precision, &builder));
623 case 'n': // should be locale-aware, but isn't
627 if (arg.precision < DoubleToStringConverter::kMinPrecisionDigits) {
628 arg.precision = DoubleToStringConverter::kMinPrecisionDigits;
629 } else if (arg.precision >
630 DoubleToStringConverter::kMaxPrecisionDigits) {
631 arg.precision = DoubleToStringConverter::kMaxPrecisionDigits;
633 DoubleToStringConverter conv(
634 DoubleToStringConverter::EMIT_POSITIVE_EXPONENT_SIGN,
640 CHECK(conv.ToShortest(val, &builder));
644 arg.error("invalid specifier '", arg.presentation, "'");
647 int len = builder.position();
651 // Add '+' or ' ' sign if needed
653 // anything that's neither negative nor nan
655 if (plusSign && (*p != '-' && *p != 'n' && *p != 'N')) {
659 } else if (*p == '-') {
663 format_value::formatNumber(StringPiece(p, len), prefixLen, arg, cb);
670 // float (defer to double)
672 class FormatValue<float> {
674 explicit FormatValue(float val) : val_(val) { }
676 template <class FormatCallback>
677 void format(FormatArg& arg, FormatCallback& cb) const {
678 FormatValue<double>(val_).format(arg, cb);
685 // Sring-y types (implicitly convertible to StringPiece, except char*)
688 T, typename std::enable_if<
689 (!std::is_pointer<T>::value ||
690 !std::is_same<char, typename std::decay<
691 typename std::remove_pointer<T>::type>::type>::value) &&
692 std::is_convertible<T, StringPiece>::value>::type>
695 explicit FormatValue(StringPiece val) : val_(val) { }
697 template <class FormatCallback>
698 void format(FormatArg& arg, FormatCallback& cb) const {
699 if (arg.keyEmpty()) {
700 arg.validate(FormatArg::Type::OTHER);
701 arg.enforce(arg.presentation == FormatArg::kDefaultPresentation ||
702 arg.presentation == 's',
703 "invalid specifier '", arg.presentation, "'");
704 format_value::formatString(val_, arg, cb);
706 FormatValue<char>(val_.at(arg.splitIntKey())).format(arg, cb);
716 class FormatValue<std::nullptr_t> {
718 explicit FormatValue(std::nullptr_t) { }
720 template <class FormatCallback>
721 void format(FormatArg& arg, FormatCallback& cb) const {
722 arg.validate(FormatArg::Type::OTHER);
723 arg.enforce(arg.presentation == FormatArg::kDefaultPresentation,
724 "invalid specifier '", arg.presentation, "'");
725 format_value::formatString("(null)", arg, cb);
729 // Partial specialization of FormatValue for char*
733 typename std::enable_if<
734 std::is_same<char, typename std::decay<T>::type>::value>::type>
737 explicit FormatValue(T* val) : val_(val) { }
739 template <class FormatCallback>
740 void format(FormatArg& arg, FormatCallback& cb) const {
741 if (arg.keyEmpty()) {
743 FormatValue<std::nullptr_t>(nullptr).format(arg, cb);
745 FormatValue<StringPiece>(val_).format(arg, cb);
748 FormatValue<typename std::decay<T>::type>(
749 val_[arg.splitIntKey()]).format(arg, cb);
757 // Partial specialization of FormatValue for void*
761 typename std::enable_if<
762 std::is_same<void, typename std::decay<T>::type>::value>::type>
765 explicit FormatValue(T* val) : val_(val) { }
767 template <class FormatCallback>
768 void format(FormatArg& arg, FormatCallback& cb) const {
770 FormatValue<std::nullptr_t>(nullptr).format(arg, cb);
772 // Print as a pointer, in hex.
773 arg.validate(FormatArg::Type::OTHER);
774 arg.enforce(arg.presentation == FormatArg::kDefaultPresentation,
775 "invalid specifier '", arg.presentation, "'");
776 arg.basePrefix = true;
777 arg.presentation = 'x';
778 if (arg.align == FormatArg::Align::DEFAULT) {
779 arg.align = FormatArg::Align::LEFT;
781 FormatValue<uintptr_t>(
782 reinterpret_cast<uintptr_t>(val_)).doFormat(arg, cb);
790 template <class T, class = void>
791 class TryFormatValue {
793 template <class FormatCallback>
794 static void formatOrFail(T& value, FormatArg& arg, FormatCallback& cb) {
795 arg.error("No formatter available for this type");
800 class TryFormatValue<
802 typename std::enable_if<
803 0 < sizeof(FormatValue<typename std::decay<T>::type>)>::type>
806 template <class FormatCallback>
807 static void formatOrFail(T& value, FormatArg& arg, FormatCallback& cb) {
808 FormatValue<typename std::decay<T>::type>(value).format(arg, cb);
812 // Partial specialization of FormatValue for other pointers
816 typename std::enable_if<
817 !std::is_same<char, typename std::decay<T>::type>::value &&
818 !std::is_same<void, typename std::decay<T>::type>::value>::type>
821 explicit FormatValue(T* val) : val_(val) { }
823 template <class FormatCallback>
824 void format(FormatArg& arg, FormatCallback& cb) const {
825 if (arg.keyEmpty()) {
826 FormatValue<void*>((void*)val_).format(arg, cb);
828 TryFormatValue<T>::formatOrFail(val_[arg.splitIntKey()], arg, cb);
837 // Shortcut, so we don't have to use enable_if everywhere
838 struct FormatTraitsBase {
839 typedef void enabled;
842 // Traits that define enabled, value_type, and at() for anything
843 // indexable with integral keys: pointers, arrays, vectors, and maps
844 // with integral keys
845 template <class T, class Enable=void> struct IndexableTraits;
847 // Base class for sequences (vectors, deques)
849 struct IndexableTraitsSeq : public FormatTraitsBase {
850 typedef C container_type;
851 typedef typename C::value_type value_type;
852 static const value_type& at(const C& c, int idx) {
857 // Base class for associative types (maps)
859 struct IndexableTraitsAssoc : public FormatTraitsBase {
860 typedef typename C::value_type::second_type value_type;
861 static const value_type& at(const C& c, int idx) {
862 return c.at(static_cast<typename C::key_type>(idx));
867 template <class T, size_t N>
868 struct IndexableTraits<std::array<T, N>>
869 : public IndexableTraitsSeq<std::array<T, N>> {
873 template <class T, class A>
874 struct IndexableTraits<std::vector<T, A>>
875 : public IndexableTraitsSeq<std::vector<T, A>> {
879 template <class T, class A>
880 struct IndexableTraits<std::deque<T, A>>
881 : public IndexableTraitsSeq<std::deque<T, A>> {
885 template <class T, class A>
886 struct IndexableTraits<fbvector<T, A>>
887 : public IndexableTraitsSeq<fbvector<T, A>> {
891 template <class T, size_t M, class A, class B, class C>
892 struct IndexableTraits<small_vector<T, M, A, B, C>>
893 : public IndexableTraitsSeq<small_vector<T, M, A, B, C>> {
896 // std::map with integral keys
897 template <class K, class T, class C, class A>
898 struct IndexableTraits<
899 std::map<K, T, C, A>,
900 typename std::enable_if<std::is_integral<K>::value>::type>
901 : public IndexableTraitsAssoc<std::map<K, T, C, A>> {
904 // std::unordered_map with integral keys
905 template <class K, class T, class H, class E, class A>
906 struct IndexableTraits<
907 std::unordered_map<K, T, H, E, A>,
908 typename std::enable_if<std::is_integral<K>::value>::type>
909 : public IndexableTraitsAssoc<std::unordered_map<K, T, H, E, A>> {
912 } // namespace detail
914 // Partial specialization of FormatValue for integer-indexable containers
918 typename detail::IndexableTraits<T>::enabled> {
920 explicit FormatValue(const T& val) : val_(val) { }
922 template <class FormatCallback>
923 void format(FormatArg& arg, FormatCallback& cb) const {
924 FormatValue<typename std::decay<
925 typename detail::IndexableTraits<T>::value_type>::type>(
926 detail::IndexableTraits<T>::at(
927 val_, arg.splitIntKey())).format(arg, cb);
936 // Define enabled, key_type, convert from StringPiece to the key types
938 template <class T> struct KeyFromStringPiece;
942 struct KeyFromStringPiece<std::string> : public FormatTraitsBase {
943 typedef std::string key_type;
944 static std::string convert(StringPiece s) {
947 typedef void enabled;
952 struct KeyFromStringPiece<fbstring> : public FormatTraitsBase {
953 typedef fbstring key_type;
954 static fbstring convert(StringPiece s) {
955 return s.toFbstring();
961 struct KeyFromStringPiece<StringPiece> : public FormatTraitsBase {
962 typedef StringPiece key_type;
963 static StringPiece convert(StringPiece s) {
968 // Base class for associative types keyed by strings
969 template <class T> struct KeyableTraitsAssoc : public FormatTraitsBase {
970 typedef typename T::key_type key_type;
971 typedef typename T::value_type::second_type value_type;
972 static const value_type& at(const T& map, StringPiece key) {
973 return map.at(KeyFromStringPiece<key_type>::convert(key));
977 // Define enabled, key_type, value_type, at() for supported string-keyed
979 template <class T, class Enabled=void> struct KeyableTraits;
981 // std::map with string key
982 template <class K, class T, class C, class A>
983 struct KeyableTraits<
984 std::map<K, T, C, A>,
985 typename KeyFromStringPiece<K>::enabled>
986 : public KeyableTraitsAssoc<std::map<K, T, C, A>> {
989 // std::unordered_map with string key
990 template <class K, class T, class H, class E, class A>
991 struct KeyableTraits<
992 std::unordered_map<K, T, H, E, A>,
993 typename KeyFromStringPiece<K>::enabled>
994 : public KeyableTraitsAssoc<std::unordered_map<K, T, H, E, A>> {
997 } // namespace detail
999 // Partial specialization of FormatValue for string-keyed containers
1003 typename detail::KeyableTraits<T>::enabled> {
1005 explicit FormatValue(const T& val) : val_(val) { }
1007 template <class FormatCallback>
1008 void format(FormatArg& arg, FormatCallback& cb) const {
1009 FormatValue<typename std::decay<
1010 typename detail::KeyableTraits<T>::value_type>::type>(
1011 detail::KeyableTraits<T>::at(
1012 val_, arg.splitKey())).format(arg, cb);
1019 // Partial specialization of FormatValue for pairs
1020 template <class A, class B>
1021 class FormatValue<std::pair<A, B>> {
1023 explicit FormatValue(const std::pair<A, B>& val) : val_(val) { }
1025 template <class FormatCallback>
1026 void format(FormatArg& arg, FormatCallback& cb) const {
1027 int key = arg.splitIntKey();
1030 FormatValue<typename std::decay<A>::type>(val_.first).format(arg, cb);
1033 FormatValue<typename std::decay<B>::type>(val_.second).format(arg, cb);
1036 arg.error("invalid index for pair");
1041 const std::pair<A, B>& val_;
1044 // Partial specialization of FormatValue for tuples
1045 template <class... Args>
1046 class FormatValue<std::tuple<Args...>> {
1047 typedef std::tuple<Args...> Tuple;
1049 explicit FormatValue(const Tuple& val) : val_(val) { }
1051 template <class FormatCallback>
1052 void format(FormatArg& arg, FormatCallback& cb) const {
1053 int key = arg.splitIntKey();
1054 arg.enforce(key >= 0, "tuple index must be non-negative");
1055 doFormat(key, arg, cb);
1059 static constexpr size_t valueCount = std::tuple_size<Tuple>::value;
1061 template <size_t K, class Callback>
1062 typename std::enable_if<K == valueCount>::type
1063 doFormatFrom(size_t i, FormatArg& arg, Callback& cb) const {
1064 arg.enforce("tuple index out of range, max=", i);
1067 template <size_t K, class Callback>
1068 typename std::enable_if<(K < valueCount)>::type
1069 doFormatFrom(size_t i, FormatArg& arg, Callback& cb) const {
1071 FormatValue<typename std::decay<
1072 typename std::tuple_element<K, Tuple>::type>::type>(
1073 std::get<K>(val_)).format(arg, cb);
1075 doFormatFrom<K+1>(i, arg, cb);
1079 template <class Callback>
1080 void doFormat(size_t i, FormatArg& arg, Callback& cb) const {
1081 return doFormatFrom<0>(i, arg, cb);
1087 // Partial specialization of FormatValue for nested Formatters
1088 template <bool containerMode, class... Args>
1089 class FormatValue<Formatter<containerMode, Args...>, void> {
1090 typedef Formatter<containerMode, Args...> FormatterValue;
1092 explicit FormatValue(const FormatterValue& f) : f_(f) { }
1094 template <class FormatCallback>
1095 void format(FormatArg& arg, FormatCallback& cb) const {
1096 format_value::formatFormatter(f_, arg, cb);
1099 const FormatterValue& f_;
1103 * Formatter objects can be appended to strings, and therefore they're
1104 * compatible with folly::toAppend and folly::to.
1106 template <class Tgt, bool containerMode, class... Args>
1107 typename std::enable_if<
1108 detail::IsSomeString<Tgt>::value>::type
1109 toAppend(const Formatter<containerMode, Args...>& value, Tgt * result) {
1110 value.appendTo(*result);
1113 } // namespace folly