2 * Copyright 2012-present 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/MapUtil.h>
31 #include <folly/Traits.h>
32 #include <folly/portability/Windows.h>
34 // Ignore -Wformat-nonliteral warnings within this file
36 FOLLY_GCC_DISABLE_WARNING("-Wformat-nonliteral")
42 // Updates the end of the buffer after the comma separators have been added.
43 void insertThousandsGroupingUnsafe(char* start_buffer, char** end_buffer);
45 extern const char formatHexUpper[256][2];
46 extern const char formatHexLower[256][2];
47 extern const char formatOctal[512][3];
48 extern const char formatBinary[256][8];
50 const size_t kMaxHexLength = 2 * sizeof(uintmax_t);
51 const size_t kMaxOctalLength = 3 * sizeof(uintmax_t);
52 const size_t kMaxBinaryLength = 8 * sizeof(uintmax_t);
55 * Convert an unsigned to hex, using repr (which maps from each possible
56 * 2-hex-bytes value to the 2-character representation).
58 * Just like folly::detail::uintToBuffer in Conv.h, writes at the *end* of
59 * the supplied buffer and returns the offset of the beginning of the string
60 * from the start of the buffer. The formatted string will be in range
61 * [buf+begin, buf+bufLen).
65 uintToHex(char* buffer, size_t bufLen, Uint v, const char (&repr)[256][2]) {
66 // 'v >>= 7, v >>= 1' is no more than a work around to get rid of shift size
67 // warning when Uint = uint8_t (it's false as v >= 256 implies sizeof(v) > 1).
68 for (; !less_than<unsigned, 256>(v); v >>= 7, v >>= 1) {
71 buffer[bufLen] = repr[b][0];
72 buffer[bufLen + 1] = repr[b][1];
74 buffer[--bufLen] = repr[v][1];
76 buffer[--bufLen] = repr[v][0];
82 * Convert an unsigned to hex, using lower-case letters for the digits
83 * above 9. See the comments for uintToHex.
86 inline size_t uintToHexLower(char* buffer, size_t bufLen, Uint v) {
87 return uintToHex(buffer, bufLen, v, formatHexLower);
91 * Convert an unsigned to hex, using upper-case letters for the digits
92 * above 9. See the comments for uintToHex.
95 inline size_t uintToHexUpper(char* buffer, size_t bufLen, Uint v) {
96 return uintToHex(buffer, bufLen, v, formatHexUpper);
100 * Convert an unsigned to octal.
102 * Just like folly::detail::uintToBuffer in Conv.h, writes at the *end* of
103 * the supplied buffer and returns the offset of the beginning of the string
104 * from the start of the buffer. The formatted string will be in range
105 * [buf+begin, buf+bufLen).
107 template <class Uint>
108 size_t uintToOctal(char* buffer, size_t bufLen, Uint v) {
109 auto& repr = formatOctal;
110 // 'v >>= 7, v >>= 2' is no more than a work around to get rid of shift size
111 // warning when Uint = uint8_t (it's false as v >= 512 implies sizeof(v) > 1).
112 for (; !less_than<unsigned, 512>(v); v >>= 7, v >>= 2) {
115 buffer[bufLen] = repr[b][0];
116 buffer[bufLen + 1] = repr[b][1];
117 buffer[bufLen + 2] = repr[b][2];
119 buffer[--bufLen] = repr[v][2];
121 buffer[--bufLen] = repr[v][1];
124 buffer[--bufLen] = repr[v][0];
130 * Convert an unsigned to binary.
132 * Just like folly::detail::uintToBuffer in Conv.h, writes at the *end* of
133 * the supplied buffer and returns the offset of the beginning of the string
134 * from the start of the buffer. The formatted string will be in range
135 * [buf+begin, buf+bufLen).
137 template <class Uint>
138 size_t uintToBinary(char* buffer, size_t bufLen, Uint v) {
139 auto& repr = formatBinary;
141 buffer[--bufLen] = '0';
144 for (; v; v >>= 7, v >>= 1) {
147 memcpy(buffer + bufLen, &(repr[b][0]), 8);
149 while (buffer[bufLen] == '0') {
155 } // namespace detail
157 template <class Derived, bool containerMode, class... Args>
158 BaseFormatter<Derived, containerMode, Args...>::BaseFormatter(
161 : str_(str), values_(std::forward<Args>(args)...) {}
163 template <class Derived, bool containerMode, class... Args>
164 template <class Output>
165 void BaseFormatter<Derived, containerMode, Args...>::operator()(
167 // Copy raw string (without format specifiers) to output;
168 // not as simple as we'd like, as we still need to translate "}}" to "}"
169 // and throw if we see any lone "}"
170 auto outputString = [&out](StringPiece s) {
174 auto q = static_cast<const char*>(memchr(p, '}', size_t(end - p)));
176 out(StringPiece(p, end));
180 out(StringPiece(p, q));
183 if (p == end || *p != '}') {
184 throwBadFormatArg("folly::format: single '}' in format string");
190 auto p = str_.begin();
191 auto end = str_.end();
194 bool hasDefaultArgIndex = false;
195 bool hasExplicitArgIndex = false;
197 auto q = static_cast<const char*>(memchr(p, '{', size_t(end - p)));
199 outputString(StringPiece(p, end));
202 outputString(StringPiece(p, q));
206 throwBadFormatArg("folly::format: '}' at end of format string");
211 out(StringPiece(p, 1));
217 q = static_cast<const char*>(memchr(p, '}', size_t(end - p)));
219 throwBadFormatArg("folly::format: missing ending '}'");
221 FormatArg arg(StringPiece(p, q));
225 auto piece = arg.splitKey<true>(); // empty key component is okay
226 if (containerMode) { // static
228 arg.width != FormatArg::kDynamicWidth,
229 "dynamic field width not supported in vformat()");
231 arg.setNextIntKey(nextArg++);
232 hasDefaultArgIndex = true;
234 arg.setNextKey(piece);
235 hasExplicitArgIndex = true;
239 if (arg.width == FormatArg::kDynamicWidth) {
241 arg.widthIndex == FormatArg::kNoIndex,
242 "cannot provide width arg index without value arg index");
243 int sizeArg = nextArg++;
244 arg.width = asDerived().getSizeArg(size_t(sizeArg), arg);
247 argIndex = nextArg++;
248 hasDefaultArgIndex = true;
250 if (arg.width == FormatArg::kDynamicWidth) {
252 arg.widthIndex != FormatArg::kNoIndex,
253 "cannot provide value arg index without width arg index");
254 arg.width = asDerived().getSizeArg(size_t(arg.widthIndex), arg);
258 argIndex = to<int>(piece);
259 } catch (const std::out_of_range&) {
260 arg.error("argument index must be integer");
262 arg.enforce(argIndex >= 0, "argument index must be non-negative");
263 hasExplicitArgIndex = true;
267 if (hasDefaultArgIndex && hasExplicitArgIndex) {
269 "folly::format: may not have both default and explicit arg indexes");
272 asDerived().doFormat(size_t(argIndex), arg, out);
276 template <class Derived, bool containerMode, class... Args>
279 const BaseFormatter<Derived, containerMode, Args...>& formatter) {
280 auto writer = [fp](StringPiece sp) {
281 size_t n = fwrite(sp.data(), 1, sp.size(), fp);
283 throwSystemError("Formatter writeTo", "fwrite failed");
289 namespace format_value {
291 template <class FormatCallback>
292 void formatString(StringPiece val, FormatArg& arg, FormatCallback& cb) {
293 if (arg.width != FormatArg::kDefaultWidth && arg.width < 0) {
294 throwBadFormatArg("folly::format: invalid width");
296 if (arg.precision != FormatArg::kDefaultPrecision && arg.precision < 0) {
297 throwBadFormatArg("folly::format: invalid precision");
300 if (arg.precision != FormatArg::kDefaultPrecision &&
301 val.size() > static_cast<size_t>(arg.precision)) {
302 val.reset(val.data(), static_cast<size_t>(arg.precision));
305 constexpr int padBufSize = 128;
306 char padBuf[padBufSize];
308 // Output padding, no more than padBufSize at once
309 auto pad = [&padBuf, &cb, padBufSize](int chars) {
311 int n = std::min(chars, padBufSize);
312 cb(StringPiece(padBuf, size_t(n)));
317 int padRemaining = 0;
318 if (arg.width != FormatArg::kDefaultWidth &&
319 val.size() < static_cast<size_t>(arg.width)) {
320 char fill = arg.fill == FormatArg::kDefaultFill ? ' ' : arg.fill;
321 int padChars = static_cast<int>(arg.width - val.size());
322 memset(padBuf, fill, size_t(std::min(padBufSize, padChars)));
325 case FormatArg::Align::DEFAULT:
326 case FormatArg::Align::LEFT:
327 padRemaining = padChars;
329 case FormatArg::Align::CENTER:
331 padRemaining = padChars - padChars / 2;
333 case FormatArg::Align::RIGHT:
334 case FormatArg::Align::PAD_AFTER_SIGN:
350 template <class FormatCallback>
355 FormatCallback& cb) {
356 // precision means something different for numbers
357 arg.precision = FormatArg::kDefaultPrecision;
358 if (arg.align == FormatArg::Align::DEFAULT) {
359 arg.align = FormatArg::Align::RIGHT;
360 } else if (prefixLen && arg.align == FormatArg::Align::PAD_AFTER_SIGN) {
361 // Split off the prefix, then do any padding if necessary
362 cb(val.subpiece(0, size_t(prefixLen)));
363 val.advance(size_t(prefixLen));
364 arg.width = std::max(arg.width - prefixLen, 0);
366 format_value::formatString(val, arg, cb);
370 class FormatCallback,
374 void formatFormatter(
375 const BaseFormatter<Derived, containerMode, Args...>& formatter,
377 FormatCallback& cb) {
378 if (arg.width == FormatArg::kDefaultWidth &&
379 arg.precision == FormatArg::kDefaultPrecision) {
383 arg.align != FormatArg::Align::LEFT &&
384 arg.align != FormatArg::Align::DEFAULT) {
385 // We can only avoid creating a temporary string if we align left,
386 // as we'd need to know the size beforehand otherwise
387 format_value::formatString(formatter.fbstr(), arg, cb);
389 auto fn = [&arg, &cb](StringPiece sp) mutable {
390 int sz = static_cast<int>(sp.size());
391 if (arg.precision != FormatArg::kDefaultPrecision) {
392 sz = std::min(arg.precision, sz);
393 sp.reset(sp.data(), size_t(sz));
398 if (arg.width != FormatArg::kDefaultWidth) {
399 arg.width = std::max(arg.width - sz, 0);
404 if (arg.width != FormatArg::kDefaultWidth && arg.width != 0) {
405 // Rely on formatString to do appropriate padding
406 format_value::formatString(StringPiece(), arg, cb);
411 } // namespace format_value
413 // Definitions for default FormatValue classes
415 // Integral types (except bool)
419 typename std::enable_if<
420 std::is_integral<T>::value && !std::is_same<T, bool>::value>::type> {
422 explicit FormatValue(T val) : val_(val) {}
428 template <class FormatCallback>
429 void format(FormatArg& arg, FormatCallback& cb) const {
430 arg.validate(FormatArg::Type::INTEGER);
434 template <class FormatCallback>
435 void doFormat(FormatArg& arg, FormatCallback& cb) const {
436 char presentation = arg.presentation;
437 if (presentation == FormatArg::kDefaultPresentation) {
438 presentation = std::is_same<T, char>::value ? 'c' : 'd';
441 // Do all work as unsigned, we'll add the prefix ('0' or '0x' if necessary)
442 // and sign ourselves.
443 typedef typename std::make_unsigned<T>::type UT;
446 if (std::is_signed<T>::value) {
447 if (folly::is_negative(val_)) {
448 uval = UT(-static_cast<UT>(val_));
451 uval = static_cast<UT>(val_);
453 case FormatArg::Sign::PLUS_OR_MINUS:
456 case FormatArg::Sign::SPACE_OR_MINUS:
465 uval = static_cast<UT>(val_);
469 arg.sign == FormatArg::Sign::DEFAULT,
470 "sign specifications not allowed for unsigned values");
474 // #x: 0x prefix + 16 bytes = 18 bytes
475 // #o: 0 prefix + 22 bytes = 23 bytes
476 // #b: 0b prefix + 64 bytes = 65 bytes
477 // ,d: 26 bytes (including thousands separators!)
479 // + 3 for sign and prefix shenanigans (see below)
480 constexpr size_t valBufSize = 69;
481 char valBuf[valBufSize];
482 char* valBufBegin = nullptr;
483 char* valBufEnd = nullptr;
486 switch (presentation) {
490 "base prefix not allowed with '",
495 !arg.thousandsSeparator,
496 "cannot use ',' with the '",
500 valBufBegin = valBuf + 3; // room for sign and base prefix
501 #if defined(__ANDROID__)
504 (valBuf + valBufSize) - valBufBegin,
506 static_cast<uintmax_t>(uval));
510 size_t((valBuf + valBufSize) - valBufBegin),
512 static_cast<uintmax_t>(uval));
514 // valBufSize should always be big enough, so this should never
516 assert(len < valBuf + valBufSize - valBufBegin);
517 valBufEnd = valBufBegin + len;
523 "base prefix not allowed with '",
526 valBufBegin = valBuf + 3; // room for sign and base prefix
528 // Use uintToBuffer, faster than sprintf
529 valBufEnd = valBufBegin + uint64ToBufferUnsafe(uval, valBufBegin);
530 if (arg.thousandsSeparator) {
531 detail::insertThousandsGroupingUnsafe(valBufBegin, &valBufEnd);
537 "base prefix not allowed with '",
541 !arg.thousandsSeparator,
542 "thousands separator (',') not allowed with '",
545 valBufBegin = valBuf + 3;
546 *valBufBegin = static_cast<char>(uval);
547 valBufEnd = valBufBegin + 1;
552 !arg.thousandsSeparator,
553 "thousands separator (',') not allowed with '",
556 valBufEnd = valBuf + valBufSize - 1;
558 valBuf + detail::uintToOctal(valBuf, valBufSize - 1, uval);
559 if (arg.basePrefix) {
560 *--valBufBegin = '0';
566 !arg.thousandsSeparator,
567 "thousands separator (',') not allowed with '",
570 valBufEnd = valBuf + valBufSize - 1;
572 valBuf + detail::uintToHexLower(valBuf, valBufSize - 1, uval);
573 if (arg.basePrefix) {
574 *--valBufBegin = 'x';
575 *--valBufBegin = '0';
581 !arg.thousandsSeparator,
582 "thousands separator (',') not allowed with '",
585 valBufEnd = valBuf + valBufSize - 1;
587 valBuf + detail::uintToHexUpper(valBuf, valBufSize - 1, uval);
588 if (arg.basePrefix) {
589 *--valBufBegin = 'X';
590 *--valBufBegin = '0';
597 !arg.thousandsSeparator,
598 "thousands separator (',') not allowed with '",
601 valBufEnd = valBuf + valBufSize - 1;
603 valBuf + detail::uintToBinary(valBuf, valBufSize - 1, uval);
604 if (arg.basePrefix) {
605 *--valBufBegin = presentation; // 0b or 0B
606 *--valBufBegin = '0';
611 arg.error("invalid specifier '", presentation, "'");
615 *--valBufBegin = sign;
619 format_value::formatNumber(
620 StringPiece(valBufBegin, valBufEnd), prefixLen, arg, cb);
629 class FormatValue<bool> {
631 explicit FormatValue(bool val) : val_(val) {}
633 template <class FormatCallback>
634 void format(FormatArg& arg, FormatCallback& cb) const {
635 if (arg.presentation == FormatArg::kDefaultPresentation) {
636 arg.validate(FormatArg::Type::OTHER);
637 format_value::formatString(val_ ? "true" : "false", arg, cb);
639 FormatValue<int>(val_).format(arg, cb);
649 class FormatValue<double> {
651 explicit FormatValue(double val) : val_(val) {}
653 template <class FormatCallback>
654 void format(FormatArg& arg, FormatCallback& cb) const {
657 formatHelper(piece, prefixLen, arg);
658 format_value::formatNumber(piece, prefixLen, arg, cb);
662 void formatHelper(fbstring& piece, int& prefixLen, FormatArg& arg) const;
667 // float (defer to double)
669 class FormatValue<float> {
671 explicit FormatValue(float val) : val_(val) {}
673 template <class FormatCallback>
674 void format(FormatArg& arg, FormatCallback& cb) const {
675 FormatValue<double>(val_).format(arg, cb);
682 // String-y types (implicitly convertible to StringPiece, except char*)
686 typename std::enable_if<
687 (!std::is_pointer<T>::value ||
690 typename std::decay<typename std::remove_pointer<T>::type>::type>::
692 std::is_convertible<T, StringPiece>::value>::type> {
694 explicit FormatValue(StringPiece val) : val_(val) {}
696 template <class FormatCallback>
697 void format(FormatArg& arg, FormatCallback& cb) const {
698 if (arg.keyEmpty()) {
699 arg.validate(FormatArg::Type::OTHER);
701 arg.presentation == FormatArg::kDefaultPresentation ||
702 arg.presentation == 's',
703 "invalid specifier '",
706 format_value::formatString(val_, arg, cb);
708 FormatValue<char>(val_.at(size_t(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);
726 arg.presentation == FormatArg::kDefaultPresentation,
727 "invalid specifier '",
730 format_value::formatString("(null)", arg, cb);
734 // Partial specialization of FormatValue for char*
738 typename std::enable_if<
739 std::is_same<char, typename std::decay<T>::type>::value>::type> {
741 explicit FormatValue(T* val) : val_(val) {}
743 template <class FormatCallback>
744 void format(FormatArg& arg, FormatCallback& cb) const {
745 if (arg.keyEmpty()) {
747 FormatValue<std::nullptr_t>(nullptr).format(arg, cb);
749 FormatValue<StringPiece>(val_).format(arg, cb);
752 FormatValue<typename std::decay<T>::type>(val_[arg.splitIntKey()])
761 // Partial specialization of FormatValue for void*
765 typename std::enable_if<
766 std::is_same<void, typename std::decay<T>::type>::value>::type> {
768 explicit FormatValue(T* val) : val_(val) {}
770 template <class FormatCallback>
771 void format(FormatArg& arg, FormatCallback& cb) const {
773 FormatValue<std::nullptr_t>(nullptr).format(arg, cb);
775 // Print as a pointer, in hex.
776 arg.validate(FormatArg::Type::OTHER);
778 arg.presentation == FormatArg::kDefaultPresentation,
779 "invalid specifier '",
782 arg.basePrefix = true;
783 arg.presentation = 'x';
784 if (arg.align == FormatArg::Align::DEFAULT) {
785 arg.align = FormatArg::Align::LEFT;
787 FormatValue<uintptr_t>(reinterpret_cast<uintptr_t>(val_))
796 template <class T, class = void>
797 class TryFormatValue {
799 template <class FormatCallback>
801 formatOrFail(T& /* value */, FormatArg& arg, FormatCallback& /* cb */) {
802 arg.error("No formatter available for this type");
807 class TryFormatValue<
809 typename std::enable_if<
810 0 < sizeof(FormatValue<typename std::decay<T>::type>)>::type> {
812 template <class FormatCallback>
813 static void formatOrFail(T& value, FormatArg& arg, FormatCallback& cb) {
814 FormatValue<typename std::decay<T>::type>(value).format(arg, cb);
818 // Partial specialization of FormatValue for other pointers
822 typename std::enable_if<
823 !std::is_same<char, typename std::decay<T>::type>::value &&
824 !std::is_same<void, typename std::decay<T>::type>::value>::type> {
826 explicit FormatValue(T* val) : val_(val) {}
828 template <class FormatCallback>
829 void format(FormatArg& arg, FormatCallback& cb) const {
830 if (arg.keyEmpty()) {
831 FormatValue<void*>((void*)val_).format(arg, cb);
833 TryFormatValue<T>::formatOrFail(val_[arg.splitIntKey()], arg, cb);
844 template <class T, size_t N>
845 struct IndexableTraits<std::array<T, N>>
846 : public IndexableTraitsSeq<std::array<T, N>> {};
849 template <class T, class A>
850 struct IndexableTraits<std::vector<T, A>>
851 : public IndexableTraitsSeq<std::vector<T, A>> {};
854 template <class T, class A>
855 struct IndexableTraits<std::deque<T, A>>
856 : public IndexableTraitsSeq<std::deque<T, A>> {};
858 // std::map with integral keys
859 template <class K, class T, class C, class A>
860 struct IndexableTraits<
861 std::map<K, T, C, A>,
862 typename std::enable_if<std::is_integral<K>::value>::type>
863 : public IndexableTraitsAssoc<std::map<K, T, C, A>> {};
865 // std::unordered_map with integral keys
866 template <class K, class T, class H, class E, class A>
867 struct IndexableTraits<
868 std::unordered_map<K, T, H, E, A>,
869 typename std::enable_if<std::is_integral<K>::value>::type>
870 : public IndexableTraitsAssoc<std::unordered_map<K, T, H, E, A>> {};
872 } // namespace detail
874 // Partial specialization of FormatValue for integer-indexable containers
876 class FormatValue<T, typename detail::IndexableTraits<T>::enabled> {
878 explicit FormatValue(const T& val) : val_(val) {}
880 template <class FormatCallback>
881 void format(FormatArg& arg, FormatCallback& cb) const {
882 FormatValue<typename std::decay<
883 typename detail::IndexableTraits<T>::value_type>::type>(
884 detail::IndexableTraits<T>::at(val_, arg.splitIntKey()))
892 template <class Container, class Value>
894 detail::DefaultValueWrapper<Container, Value>,
895 typename detail::IndexableTraits<Container>::enabled> {
897 explicit FormatValue(const detail::DefaultValueWrapper<Container, Value>& val)
900 template <class FormatCallback>
901 void format(FormatArg& arg, FormatCallback& cb) const {
902 FormatValue<typename std::decay<
903 typename detail::IndexableTraits<Container>::value_type>::type>(
904 detail::IndexableTraits<Container>::at(
905 val_.container, arg.splitIntKey(), val_.defaultValue))
910 const detail::DefaultValueWrapper<Container, Value>& val_;
915 // Define enabled, key_type, convert from StringPiece to the key types
918 struct KeyFromStringPiece;
922 struct KeyFromStringPiece<std::string> : public FormatTraitsBase {
923 typedef std::string key_type;
924 static std::string convert(StringPiece s) {
927 typedef void enabled;
932 struct KeyFromStringPiece<fbstring> : public FormatTraitsBase {
933 typedef fbstring key_type;
934 static fbstring convert(StringPiece s) {
935 return s.to<fbstring>();
941 struct KeyFromStringPiece<StringPiece> : public FormatTraitsBase {
942 typedef StringPiece key_type;
943 static StringPiece convert(StringPiece s) {
948 // Base class for associative types keyed by strings
950 struct KeyableTraitsAssoc : public FormatTraitsBase {
951 typedef typename T::key_type key_type;
952 typedef typename T::value_type::second_type value_type;
953 static const value_type& at(const T& map, StringPiece key) {
954 if (auto ptr = get_ptr(map, KeyFromStringPiece<key_type>::convert(key))) {
957 detail::throwFormatKeyNotFoundException(key);
959 static const value_type&
960 at(const T& map, StringPiece key, const value_type& dflt) {
961 auto pos = map.find(KeyFromStringPiece<key_type>::convert(key));
962 return pos != map.end() ? pos->second : dflt;
966 // Define enabled, key_type, value_type, at() for supported string-keyed
968 template <class T, class Enabled = void>
969 struct KeyableTraits;
971 // std::map with string key
972 template <class K, class T, class C, class A>
973 struct KeyableTraits<
974 std::map<K, T, C, A>,
975 typename KeyFromStringPiece<K>::enabled>
976 : public KeyableTraitsAssoc<std::map<K, T, C, A>> {};
978 // std::unordered_map with string key
979 template <class K, class T, class H, class E, class A>
980 struct KeyableTraits<
981 std::unordered_map<K, T, H, E, A>,
982 typename KeyFromStringPiece<K>::enabled>
983 : public KeyableTraitsAssoc<std::unordered_map<K, T, H, E, A>> {};
985 } // namespace detail
987 // Partial specialization of FormatValue for string-keyed containers
989 class FormatValue<T, typename detail::KeyableTraits<T>::enabled> {
991 explicit FormatValue(const T& val) : val_(val) {}
993 template <class FormatCallback>
994 void format(FormatArg& arg, FormatCallback& cb) const {
995 FormatValue<typename std::decay<
996 typename detail::KeyableTraits<T>::value_type>::type>(
997 detail::KeyableTraits<T>::at(val_, arg.splitKey()))
1005 template <class Container, class Value>
1007 detail::DefaultValueWrapper<Container, Value>,
1008 typename detail::KeyableTraits<Container>::enabled> {
1010 explicit FormatValue(const detail::DefaultValueWrapper<Container, Value>& val)
1013 template <class FormatCallback>
1014 void format(FormatArg& arg, FormatCallback& cb) const {
1015 FormatValue<typename std::decay<
1016 typename detail::KeyableTraits<Container>::value_type>::type>(
1017 detail::KeyableTraits<Container>::at(
1018 val_.container, arg.splitKey(), val_.defaultValue))
1023 const detail::DefaultValueWrapper<Container, Value>& val_;
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 arg.error("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;
1057 explicit FormatValue(const Tuple& val) : val_(val) {}
1059 template <class FormatCallback>
1060 void format(FormatArg& arg, FormatCallback& cb) const {
1061 int key = arg.splitIntKey();
1062 arg.enforce(key >= 0, "tuple index must be non-negative");
1063 doFormat(size_t(key), arg, cb);
1067 static constexpr size_t valueCount = std::tuple_size<Tuple>::value;
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 {
1072 arg.enforce("tuple index out of range, max=", i);
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 {
1079 FormatValue<typename std::decay<
1080 typename std::tuple_element<K, Tuple>::type>::type>(std::get<K>(val_))
1083 doFormatFrom<K + 1>(i, arg, cb);
1087 template <class Callback>
1088 void doFormat(size_t i, FormatArg& arg, Callback& cb) const {
1089 return doFormatFrom<0>(i, arg, cb);
1095 // Partial specialization of FormatValue for nested Formatters
1096 template <bool containerMode, class... Args, template <bool, class...> class F>
1098 F<containerMode, Args...>,
1099 typename std::enable_if<
1100 detail::IsFormatter<F<containerMode, Args...>>::value>::type> {
1101 typedef typename F<containerMode, Args...>::BaseType FormatterValue;
1104 explicit FormatValue(const FormatterValue& f) : f_(f) {}
1106 template <class FormatCallback>
1107 void format(FormatArg& arg, FormatCallback& cb) const {
1108 format_value::formatFormatter(f_, arg, cb);
1112 const FormatterValue& f_;
1116 * Formatter objects can be appended to strings, and therefore they're
1117 * compatible with folly::toAppend and folly::to.
1119 template <class Tgt, class Derived, bool containerMode, class... Args>
1120 typename std::enable_if<IsSomeString<Tgt>::value>::type toAppend(
1121 const BaseFormatter<Derived, containerMode, Args...>& value,
1123 value.appendTo(*result);
1126 } // namespace folly