2 * Copyright 2017 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 #include <unordered_map>
28 #include <folly/Exception.h>
29 #include <folly/FormatTraits.h>
30 #include <folly/Traits.h>
31 #include <folly/portability/Windows.h>
33 // Ignore -Wformat-nonliteral warnings within this file
34 #pragma GCC diagnostic push
35 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
41 // Updates the end of the buffer after the comma separators have been added.
42 void insertThousandsGroupingUnsafe(char* start_buffer, char** end_buffer);
44 extern const char formatHexUpper[256][2];
45 extern const char formatHexLower[256][2];
46 extern const char formatOctal[512][3];
47 extern const char formatBinary[256][8];
49 const size_t kMaxHexLength = 2 * sizeof(uintmax_t);
50 const size_t kMaxOctalLength = 3 * sizeof(uintmax_t);
51 const size_t kMaxBinaryLength = 8 * sizeof(uintmax_t);
54 * Convert an unsigned to hex, using repr (which maps from each possible
55 * 2-hex-bytes value to the 2-character representation).
57 * Just like folly::detail::uintToBuffer in Conv.h, writes at the *end* of
58 * the supplied buffer and returns the offset of the beginning of the string
59 * from the start of the buffer. The formatted string will be in range
60 * [buf+begin, buf+bufLen).
64 uintToHex(char* buffer, size_t bufLen, Uint v, const char (&repr)[256][2]) {
65 // 'v >>= 7, v >>= 1' is no more than a work around to get rid of shift size
66 // warning when Uint = uint8_t (it's false as v >= 256 implies sizeof(v) > 1).
67 for (; !less_than<unsigned, 256>(v); v >>= 7, v >>= 1) {
70 buffer[bufLen] = repr[b][0];
71 buffer[bufLen + 1] = repr[b][1];
73 buffer[--bufLen] = repr[v][1];
75 buffer[--bufLen] = repr[v][0];
81 * Convert an unsigned to hex, using lower-case letters for the digits
82 * above 9. See the comments for uintToHex.
85 inline size_t uintToHexLower(char* buffer, size_t bufLen, Uint v) {
86 return uintToHex(buffer, bufLen, v, formatHexLower);
90 * Convert an unsigned to hex, using upper-case letters for the digits
91 * above 9. See the comments for uintToHex.
94 inline size_t uintToHexUpper(char* buffer, size_t bufLen, Uint v) {
95 return uintToHex(buffer, bufLen, v, formatHexUpper);
99 * Convert an unsigned to octal.
101 * Just like folly::detail::uintToBuffer in Conv.h, writes at the *end* of
102 * the supplied buffer and returns the offset of the beginning of the string
103 * from the start of the buffer. The formatted string will be in range
104 * [buf+begin, buf+bufLen).
106 template <class Uint>
107 size_t uintToOctal(char* buffer, size_t bufLen, Uint v) {
108 auto& repr = formatOctal;
109 // 'v >>= 7, v >>= 2' is no more than a work around to get rid of shift size
110 // warning when Uint = uint8_t (it's false as v >= 512 implies sizeof(v) > 1).
111 for (; !less_than<unsigned, 512>(v); v >>= 7, v >>= 2) {
114 buffer[bufLen] = repr[b][0];
115 buffer[bufLen + 1] = repr[b][1];
116 buffer[bufLen + 2] = repr[b][2];
118 buffer[--bufLen] = repr[v][2];
120 buffer[--bufLen] = repr[v][1];
123 buffer[--bufLen] = repr[v][0];
129 * Convert an unsigned to binary.
131 * Just like folly::detail::uintToBuffer in Conv.h, writes at the *end* of
132 * the supplied buffer and returns the offset of the beginning of the string
133 * from the start of the buffer. The formatted string will be in range
134 * [buf+begin, buf+bufLen).
136 template <class Uint>
137 size_t uintToBinary(char* buffer, size_t bufLen, Uint v) {
138 auto& repr = formatBinary;
140 buffer[--bufLen] = '0';
143 for (; v; v >>= 7, v >>= 1) {
146 memcpy(buffer + bufLen, &(repr[b][0]), 8);
148 while (buffer[bufLen] == '0') {
154 } // namespace detail
156 template <class Derived, bool containerMode, class... Args>
157 BaseFormatter<Derived, containerMode, Args...>::BaseFormatter(
161 values_(FormatValue<typename std::decay<Args>::type>(
162 std::forward<Args>(args))...) {
164 !containerMode || sizeof...(Args) == 1,
165 "Exactly one argument required in container mode");
168 template <class Derived, bool containerMode, class... Args>
169 template <class Output>
170 void BaseFormatter<Derived, containerMode, Args...>::operator()(
172 // Copy raw string (without format specifiers) to output;
173 // not as simple as we'd like, as we still need to translate "}}" to "}"
174 // and throw if we see any lone "}"
175 auto outputString = [&out](StringPiece s) {
179 auto q = static_cast<const char*>(memchr(p, '}', size_t(end - p)));
181 out(StringPiece(p, end));
185 out(StringPiece(p, q));
188 if (p == end || *p != '}') {
189 throw BadFormatArg("folly::format: single '}' in format string");
195 auto p = str_.begin();
196 auto end = str_.end();
199 bool hasDefaultArgIndex = false;
200 bool hasExplicitArgIndex = false;
202 auto q = static_cast<const char*>(memchr(p, '{', size_t(end - p)));
204 outputString(StringPiece(p, end));
207 outputString(StringPiece(p, q));
211 throw BadFormatArg("folly::format: '}' at end of format string");
216 out(StringPiece(p, 1));
222 q = static_cast<const char*>(memchr(p, '}', size_t(end - p)));
224 throw BadFormatArg("folly::format: missing ending '}'");
226 FormatArg arg(StringPiece(p, q));
230 auto piece = arg.splitKey<true>(); // empty key component is okay
231 if (containerMode) { // static
233 arg.width != FormatArg::kDynamicWidth,
234 "dynamic field width not supported in vformat()");
236 arg.setNextIntKey(nextArg++);
237 hasDefaultArgIndex = true;
239 arg.setNextKey(piece);
240 hasExplicitArgIndex = true;
244 if (arg.width == FormatArg::kDynamicWidth) {
246 arg.widthIndex == FormatArg::kNoIndex,
247 "cannot provide width arg index without value arg index");
248 int sizeArg = nextArg++;
249 arg.width = getSizeArg(size_t(sizeArg), arg);
252 argIndex = nextArg++;
253 hasDefaultArgIndex = true;
255 if (arg.width == FormatArg::kDynamicWidth) {
257 arg.widthIndex != FormatArg::kNoIndex,
258 "cannot provide value arg index without width arg index");
259 arg.width = getSizeArg(size_t(arg.widthIndex), arg);
263 argIndex = to<int>(piece);
264 } catch (const std::out_of_range&) {
265 arg.error("argument index must be integer");
267 arg.enforce(argIndex >= 0, "argument index must be non-negative");
268 hasExplicitArgIndex = true;
272 if (hasDefaultArgIndex && hasExplicitArgIndex) {
274 "folly::format: may not have both default and explicit arg indexes");
277 doFormat(size_t(argIndex), arg, out);
281 template <class Derived, bool containerMode, class... Args>
284 const BaseFormatter<Derived, containerMode, Args...>& formatter) {
285 auto writer = [fp](StringPiece sp) {
286 size_t n = fwrite(sp.data(), 1, sp.size(), fp);
288 throwSystemError("Formatter writeTo", "fwrite failed");
294 namespace format_value {
296 template <class FormatCallback>
297 void formatString(StringPiece val, FormatArg& arg, FormatCallback& cb) {
298 if (arg.width != FormatArg::kDefaultWidth && arg.width < 0) {
299 throw BadFormatArg("folly::format: invalid width");
301 if (arg.precision != FormatArg::kDefaultPrecision && arg.precision < 0) {
302 throw BadFormatArg("folly::format: invalid precision");
305 // XXX: clang should be smart enough to not need the two static_cast<size_t>
306 // uses below given the above checks. If clang ever becomes that smart, we
307 // should remove the otherwise unnecessary warts.
309 if (arg.precision != FormatArg::kDefaultPrecision &&
310 val.size() > static_cast<size_t>(arg.precision)) {
311 val.reset(val.data(), size_t(arg.precision));
314 constexpr int padBufSize = 128;
315 char padBuf[padBufSize];
317 // Output padding, no more than padBufSize at once
318 auto pad = [&padBuf, &cb, padBufSize](int chars) {
320 int n = std::min(chars, padBufSize);
321 cb(StringPiece(padBuf, size_t(n)));
326 int padRemaining = 0;
327 if (arg.width != FormatArg::kDefaultWidth &&
328 val.size() < static_cast<size_t>(arg.width)) {
329 char fill = arg.fill == FormatArg::kDefaultFill ? ' ' : arg.fill;
330 int padChars = static_cast<int>(arg.width - val.size());
331 memset(padBuf, fill, size_t(std::min(padBufSize, padChars)));
334 case FormatArg::Align::DEFAULT:
335 case FormatArg::Align::LEFT:
336 padRemaining = padChars;
338 case FormatArg::Align::CENTER:
340 padRemaining = padChars - padChars / 2;
342 case FormatArg::Align::RIGHT:
343 case FormatArg::Align::PAD_AFTER_SIGN:
359 template <class FormatCallback>
364 FormatCallback& cb) {
365 // precision means something different for numbers
366 arg.precision = FormatArg::kDefaultPrecision;
367 if (arg.align == FormatArg::Align::DEFAULT) {
368 arg.align = FormatArg::Align::RIGHT;
369 } else if (prefixLen && arg.align == FormatArg::Align::PAD_AFTER_SIGN) {
370 // Split off the prefix, then do any padding if necessary
371 cb(val.subpiece(0, size_t(prefixLen)));
372 val.advance(size_t(prefixLen));
373 arg.width = std::max(arg.width - prefixLen, 0);
375 format_value::formatString(val, arg, cb);
379 class FormatCallback,
383 void formatFormatter(
384 const BaseFormatter<Derived, containerMode, Args...>& formatter,
386 FormatCallback& cb) {
387 if (arg.width == FormatArg::kDefaultWidth &&
388 arg.precision == FormatArg::kDefaultPrecision) {
392 arg.align != FormatArg::Align::LEFT &&
393 arg.align != FormatArg::Align::DEFAULT) {
394 // We can only avoid creating a temporary string if we align left,
395 // as we'd need to know the size beforehand otherwise
396 format_value::formatString(formatter.fbstr(), arg, cb);
398 auto fn = [&arg, &cb](StringPiece sp) mutable {
399 int sz = static_cast<int>(sp.size());
400 if (arg.precision != FormatArg::kDefaultPrecision) {
401 sz = std::min(arg.precision, sz);
402 sp.reset(sp.data(), size_t(sz));
407 if (arg.width != FormatArg::kDefaultWidth) {
408 arg.width = std::max(arg.width - sz, 0);
413 if (arg.width != FormatArg::kDefaultWidth && arg.width != 0) {
414 // Rely on formatString to do appropriate padding
415 format_value::formatString(StringPiece(), arg, cb);
420 } // namespace format_value
422 // Definitions for default FormatValue classes
424 // Integral types (except bool)
428 typename std::enable_if<
429 std::is_integral<T>::value && !std::is_same<T, bool>::value>::type> {
431 explicit FormatValue(T val) : val_(val) {}
437 template <class FormatCallback>
438 void format(FormatArg& arg, FormatCallback& cb) const {
439 arg.validate(FormatArg::Type::INTEGER);
443 template <class FormatCallback>
444 void doFormat(FormatArg& arg, FormatCallback& cb) const {
445 char presentation = arg.presentation;
446 if (presentation == FormatArg::kDefaultPresentation) {
447 presentation = std::is_same<T, char>::value ? 'c' : 'd';
450 // Do all work as unsigned, we'll add the prefix ('0' or '0x' if necessary)
451 // and sign ourselves.
452 typedef typename std::make_unsigned<T>::type UT;
455 if (std::is_signed<T>::value) {
456 if (folly::is_negative(val_)) {
457 uval = UT(-static_cast<UT>(val_));
460 uval = static_cast<UT>(val_);
462 case FormatArg::Sign::PLUS_OR_MINUS:
465 case FormatArg::Sign::SPACE_OR_MINUS:
474 uval = static_cast<UT>(val_);
478 arg.sign == FormatArg::Sign::DEFAULT,
479 "sign specifications not allowed for unsigned values");
483 // #x: 0x prefix + 16 bytes = 18 bytes
484 // #o: 0 prefix + 22 bytes = 23 bytes
485 // #b: 0b prefix + 64 bytes = 65 bytes
486 // ,d: 26 bytes (including thousands separators!)
488 // + 3 for sign and prefix shenanigans (see below)
489 constexpr size_t valBufSize = 69;
490 char valBuf[valBufSize];
491 char* valBufBegin = nullptr;
492 char* valBufEnd = nullptr;
495 switch (presentation) {
499 "base prefix not allowed with '",
504 !arg.thousandsSeparator,
505 "cannot use ',' with the '",
509 valBufBegin = valBuf + 3; // room for sign and base prefix
510 #if defined(__ANDROID__)
513 (valBuf + valBufSize) - valBufBegin,
515 static_cast<uintmax_t>(uval));
519 size_t((valBuf + valBufSize) - valBufBegin),
521 static_cast<uintmax_t>(uval));
523 // valBufSize should always be big enough, so this should never
525 assert(len < valBuf + valBufSize - valBufBegin);
526 valBufEnd = valBufBegin + len;
532 "base prefix not allowed with '",
535 valBufBegin = valBuf + 3; // room for sign and base prefix
537 // Use uintToBuffer, faster than sprintf
538 valBufEnd = valBufBegin + uint64ToBufferUnsafe(uval, valBufBegin);
539 if (arg.thousandsSeparator) {
540 detail::insertThousandsGroupingUnsafe(valBufBegin, &valBufEnd);
546 "base prefix not allowed with '",
550 !arg.thousandsSeparator,
551 "thousands separator (',') not allowed with '",
554 valBufBegin = valBuf + 3;
555 *valBufBegin = static_cast<char>(uval);
556 valBufEnd = valBufBegin + 1;
561 !arg.thousandsSeparator,
562 "thousands separator (',') not allowed with '",
565 valBufEnd = valBuf + valBufSize - 1;
567 valBuf + detail::uintToOctal(valBuf, valBufSize - 1, uval);
568 if (arg.basePrefix) {
569 *--valBufBegin = '0';
575 !arg.thousandsSeparator,
576 "thousands separator (',') not allowed with '",
579 valBufEnd = valBuf + valBufSize - 1;
581 valBuf + detail::uintToHexLower(valBuf, valBufSize - 1, uval);
582 if (arg.basePrefix) {
583 *--valBufBegin = 'x';
584 *--valBufBegin = '0';
590 !arg.thousandsSeparator,
591 "thousands separator (',') not allowed with '",
594 valBufEnd = valBuf + valBufSize - 1;
596 valBuf + detail::uintToHexUpper(valBuf, valBufSize - 1, uval);
597 if (arg.basePrefix) {
598 *--valBufBegin = 'X';
599 *--valBufBegin = '0';
606 !arg.thousandsSeparator,
607 "thousands separator (',') not allowed with '",
610 valBufEnd = valBuf + valBufSize - 1;
612 valBuf + detail::uintToBinary(valBuf, valBufSize - 1, uval);
613 if (arg.basePrefix) {
614 *--valBufBegin = presentation; // 0b or 0B
615 *--valBufBegin = '0';
620 arg.error("invalid specifier '", presentation, "'");
624 *--valBufBegin = sign;
628 format_value::formatNumber(
629 StringPiece(valBufBegin, valBufEnd), prefixLen, arg, cb);
638 class FormatValue<bool> {
640 explicit FormatValue(bool val) : val_(val) {}
642 template <class FormatCallback>
643 void format(FormatArg& arg, FormatCallback& cb) const {
644 if (arg.presentation == FormatArg::kDefaultPresentation) {
645 arg.validate(FormatArg::Type::OTHER);
646 format_value::formatString(val_ ? "true" : "false", arg, cb);
648 FormatValue<int>(val_).format(arg, cb);
658 class FormatValue<double> {
660 explicit FormatValue(double val) : val_(val) {}
662 template <class FormatCallback>
663 void format(FormatArg& arg, FormatCallback& cb) const {
666 formatHelper(piece, prefixLen, arg);
667 format_value::formatNumber(piece, prefixLen, arg, cb);
671 void formatHelper(fbstring& piece, int& prefixLen, FormatArg& arg) const;
676 // float (defer to double)
678 class FormatValue<float> {
680 explicit FormatValue(float val) : val_(val) {}
682 template <class FormatCallback>
683 void format(FormatArg& arg, FormatCallback& cb) const {
684 FormatValue<double>(val_).format(arg, cb);
691 // Sring-y types (implicitly convertible to StringPiece, except char*)
695 typename std::enable_if<
696 (!std::is_pointer<T>::value ||
699 typename std::decay<typename std::remove_pointer<T>::type>::type>::
701 std::is_convertible<T, StringPiece>::value>::type> {
703 explicit FormatValue(StringPiece val) : val_(val) {}
705 template <class FormatCallback>
706 void format(FormatArg& arg, FormatCallback& cb) const {
707 if (arg.keyEmpty()) {
708 arg.validate(FormatArg::Type::OTHER);
710 arg.presentation == FormatArg::kDefaultPresentation ||
711 arg.presentation == 's',
712 "invalid specifier '",
715 format_value::formatString(val_, arg, cb);
717 FormatValue<char>(val_.at(size_t(arg.splitIntKey()))).format(arg, cb);
727 class FormatValue<std::nullptr_t> {
729 explicit FormatValue(std::nullptr_t) {}
731 template <class FormatCallback>
732 void format(FormatArg& arg, FormatCallback& cb) const {
733 arg.validate(FormatArg::Type::OTHER);
735 arg.presentation == FormatArg::kDefaultPresentation,
736 "invalid specifier '",
739 format_value::formatString("(null)", arg, cb);
743 // Partial specialization of FormatValue for char*
747 typename std::enable_if<
748 std::is_same<char, typename std::decay<T>::type>::value>::type> {
750 explicit FormatValue(T* val) : val_(val) {}
752 template <class FormatCallback>
753 void format(FormatArg& arg, FormatCallback& cb) const {
754 if (arg.keyEmpty()) {
756 FormatValue<std::nullptr_t>(nullptr).format(arg, cb);
758 FormatValue<StringPiece>(val_).format(arg, cb);
761 FormatValue<typename std::decay<T>::type>(val_[arg.splitIntKey()])
770 // Partial specialization of FormatValue for void*
774 typename std::enable_if<
775 std::is_same<void, typename std::decay<T>::type>::value>::type> {
777 explicit FormatValue(T* val) : val_(val) {}
779 template <class FormatCallback>
780 void format(FormatArg& arg, FormatCallback& cb) const {
782 FormatValue<std::nullptr_t>(nullptr).format(arg, cb);
784 // Print as a pointer, in hex.
785 arg.validate(FormatArg::Type::OTHER);
787 arg.presentation == FormatArg::kDefaultPresentation,
788 "invalid specifier '",
791 arg.basePrefix = true;
792 arg.presentation = 'x';
793 if (arg.align == FormatArg::Align::DEFAULT) {
794 arg.align = FormatArg::Align::LEFT;
796 FormatValue<uintptr_t>(reinterpret_cast<uintptr_t>(val_))
805 template <class T, class = void>
806 class TryFormatValue {
808 template <class FormatCallback>
810 formatOrFail(T& /* value */, FormatArg& arg, FormatCallback& /* cb */) {
811 arg.error("No formatter available for this type");
816 class TryFormatValue<
818 typename std::enable_if<
819 0 < sizeof(FormatValue<typename std::decay<T>::type>)>::type> {
821 template <class FormatCallback>
822 static void formatOrFail(T& value, FormatArg& arg, FormatCallback& cb) {
823 FormatValue<typename std::decay<T>::type>(value).format(arg, cb);
827 // Partial specialization of FormatValue for other pointers
831 typename std::enable_if<
832 !std::is_same<char, typename std::decay<T>::type>::value &&
833 !std::is_same<void, typename std::decay<T>::type>::value>::type> {
835 explicit FormatValue(T* val) : val_(val) {}
837 template <class FormatCallback>
838 void format(FormatArg& arg, FormatCallback& cb) const {
839 if (arg.keyEmpty()) {
840 FormatValue<void*>((void*)val_).format(arg, cb);
842 TryFormatValue<T>::formatOrFail(val_[arg.splitIntKey()], arg, cb);
853 template <class T, size_t N>
854 struct IndexableTraits<std::array<T, N>>
855 : public IndexableTraitsSeq<std::array<T, N>> {};
858 template <class T, class A>
859 struct IndexableTraits<std::vector<T, A>>
860 : public IndexableTraitsSeq<std::vector<T, A>> {};
863 template <class T, class A>
864 struct IndexableTraits<std::deque<T, A>>
865 : public IndexableTraitsSeq<std::deque<T, A>> {};
867 // std::map with integral keys
868 template <class K, class T, class C, class A>
869 struct IndexableTraits<
870 std::map<K, T, C, A>,
871 typename std::enable_if<std::is_integral<K>::value>::type>
872 : public IndexableTraitsAssoc<std::map<K, T, C, A>> {};
874 // std::unordered_map with integral keys
875 template <class K, class T, class H, class E, class A>
876 struct IndexableTraits<
877 std::unordered_map<K, T, H, E, A>,
878 typename std::enable_if<std::is_integral<K>::value>::type>
879 : public IndexableTraitsAssoc<std::unordered_map<K, T, H, E, A>> {};
881 } // namespace detail
883 // Partial specialization of FormatValue for integer-indexable containers
885 class FormatValue<T, typename detail::IndexableTraits<T>::enabled> {
887 explicit FormatValue(const T& val) : val_(val) {}
889 template <class FormatCallback>
890 void format(FormatArg& arg, FormatCallback& cb) const {
891 FormatValue<typename std::decay<
892 typename detail::IndexableTraits<T>::value_type>::type>(
893 detail::IndexableTraits<T>::at(val_, arg.splitIntKey()))
901 template <class Container, class Value>
903 detail::DefaultValueWrapper<Container, Value>,
904 typename detail::IndexableTraits<Container>::enabled> {
906 explicit FormatValue(const detail::DefaultValueWrapper<Container, Value>& val)
909 template <class FormatCallback>
910 void format(FormatArg& arg, FormatCallback& cb) const {
911 FormatValue<typename std::decay<
912 typename detail::IndexableTraits<Container>::value_type>::type>(
913 detail::IndexableTraits<Container>::at(
914 val_.container, arg.splitIntKey(), val_.defaultValue))
919 const detail::DefaultValueWrapper<Container, Value>& val_;
924 // Define enabled, key_type, convert from StringPiece to the key types
927 struct KeyFromStringPiece;
931 struct KeyFromStringPiece<std::string> : public FormatTraitsBase {
932 typedef std::string key_type;
933 static std::string convert(StringPiece s) {
936 typedef void enabled;
941 struct KeyFromStringPiece<fbstring> : public FormatTraitsBase {
942 typedef fbstring key_type;
943 static fbstring convert(StringPiece s) {
944 return s.toFbstring();
950 struct KeyFromStringPiece<StringPiece> : public FormatTraitsBase {
951 typedef StringPiece key_type;
952 static StringPiece convert(StringPiece s) {
957 // Base class for associative types keyed by strings
959 struct KeyableTraitsAssoc : public FormatTraitsBase {
960 typedef typename T::key_type key_type;
961 typedef typename T::value_type::second_type value_type;
962 static const value_type& at(const T& map, StringPiece key) {
963 return map.at(KeyFromStringPiece<key_type>::convert(key));
965 static const value_type&
966 at(const T& map, StringPiece key, const value_type& dflt) {
967 auto pos = map.find(KeyFromStringPiece<key_type>::convert(key));
968 return pos != map.end() ? pos->second : dflt;
972 // Define enabled, key_type, value_type, at() for supported string-keyed
974 template <class T, class Enabled = void>
975 struct KeyableTraits;
977 // std::map with string key
978 template <class K, class T, class C, class A>
979 struct KeyableTraits<
980 std::map<K, T, C, A>,
981 typename KeyFromStringPiece<K>::enabled>
982 : 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>> {};
991 } // namespace detail
993 // Partial specialization of FormatValue for string-keyed containers
995 class FormatValue<T, typename detail::KeyableTraits<T>::enabled> {
997 explicit FormatValue(const T& val) : val_(val) {}
999 template <class FormatCallback>
1000 void format(FormatArg& arg, FormatCallback& cb) const {
1001 FormatValue<typename std::decay<
1002 typename detail::KeyableTraits<T>::value_type>::type>(
1003 detail::KeyableTraits<T>::at(val_, arg.splitKey()))
1011 template <class Container, class Value>
1013 detail::DefaultValueWrapper<Container, Value>,
1014 typename detail::KeyableTraits<Container>::enabled> {
1016 explicit FormatValue(const detail::DefaultValueWrapper<Container, Value>& val)
1019 template <class FormatCallback>
1020 void format(FormatArg& arg, FormatCallback& cb) const {
1021 FormatValue<typename std::decay<
1022 typename detail::KeyableTraits<Container>::value_type>::type>(
1023 detail::KeyableTraits<Container>::at(
1024 val_.container, arg.splitKey(), val_.defaultValue))
1029 const detail::DefaultValueWrapper<Container, Value>& val_;
1032 // Partial specialization of FormatValue for pairs
1033 template <class A, class B>
1034 class FormatValue<std::pair<A, B>> {
1036 explicit FormatValue(const std::pair<A, B>& val) : val_(val) {}
1038 template <class FormatCallback>
1039 void format(FormatArg& arg, FormatCallback& cb) const {
1040 int key = arg.splitIntKey();
1043 FormatValue<typename std::decay<A>::type>(val_.first).format(arg, cb);
1046 FormatValue<typename std::decay<B>::type>(val_.second).format(arg, cb);
1049 arg.error("invalid index for pair");
1054 const std::pair<A, B>& val_;
1057 // Partial specialization of FormatValue for tuples
1058 template <class... Args>
1059 class FormatValue<std::tuple<Args...>> {
1060 typedef std::tuple<Args...> Tuple;
1063 explicit FormatValue(const Tuple& val) : val_(val) {}
1065 template <class FormatCallback>
1066 void format(FormatArg& arg, FormatCallback& cb) const {
1067 int key = arg.splitIntKey();
1068 arg.enforce(key >= 0, "tuple index must be non-negative");
1069 doFormat(size_t(key), arg, cb);
1073 static constexpr size_t valueCount = std::tuple_size<Tuple>::value;
1075 template <size_t K, class Callback>
1076 typename std::enable_if<K == valueCount>::type
1077 doFormatFrom(size_t i, FormatArg& arg, Callback& /* cb */) const {
1078 arg.enforce("tuple index out of range, max=", i);
1081 template <size_t K, class Callback>
1082 typename std::enable_if<(K < valueCount)>::type
1083 doFormatFrom(size_t i, FormatArg& arg, Callback& cb) const {
1085 FormatValue<typename std::decay<
1086 typename std::tuple_element<K, Tuple>::type>::type>(std::get<K>(val_))
1089 doFormatFrom<K + 1>(i, arg, cb);
1093 template <class Callback>
1094 void doFormat(size_t i, FormatArg& arg, Callback& cb) const {
1095 return doFormatFrom<0>(i, arg, cb);
1101 // Partial specialization of FormatValue for nested Formatters
1102 template <bool containerMode, class... Args, template <bool, class...> class F>
1104 F<containerMode, Args...>,
1105 typename std::enable_if<
1106 detail::IsFormatter<F<containerMode, Args...>>::value>::type> {
1107 typedef typename F<containerMode, Args...>::BaseType FormatterValue;
1110 explicit FormatValue(const FormatterValue& f) : f_(f) {}
1112 template <class FormatCallback>
1113 void format(FormatArg& arg, FormatCallback& cb) const {
1114 format_value::formatFormatter(f_, arg, cb);
1118 const FormatterValue& f_;
1122 * Formatter objects can be appended to strings, and therefore they're
1123 * compatible with folly::toAppend and folly::to.
1125 template <class Tgt, class Derived, bool containerMode, class... Args>
1126 typename std::enable_if<IsSomeString<Tgt>::value>::type toAppend(
1127 const BaseFormatter<Derived, containerMode, Args...>& value,
1129 value.appendTo(*result);
1132 } // namespace folly
1134 #pragma GCC diagnostic pop