2 * Copyright 2015 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.
24 #include <unordered_map>
27 #include <folly/Exception.h>
28 #include <folly/FormatTraits.h>
29 #include <folly/Traits.h>
31 // Ignore -Wformat-nonliteral warnings within this file
32 #pragma GCC diagnostic push
33 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
39 // Updates the end of the buffer after the comma separators have been added.
40 void insertThousandsGroupingUnsafe(char* start_buffer, char** end_buffer);
42 extern const char formatHexUpper[256][2];
43 extern const char formatHexLower[256][2];
44 extern const char formatOctal[512][3];
45 extern const char formatBinary[256][8];
47 const size_t kMaxHexLength = 2 * sizeof(uintmax_t);
48 const size_t kMaxOctalLength = 3 * sizeof(uintmax_t);
49 const size_t kMaxBinaryLength = 8 * sizeof(uintmax_t);
52 * Convert an unsigned to hex, using repr (which maps from each possible
53 * 2-hex-bytes value to the 2-character representation).
55 * Just like folly::detail::uintToBuffer in Conv.h, writes at the *end* of
56 * the supplied buffer and returns the offset of the beginning of the string
57 * from the start of the buffer. The formatted string will be in range
58 * [buf+begin, buf+bufLen).
61 size_t uintToHex(char* buffer, size_t bufLen, Uint v,
62 const char (&repr)[256][2]) {
63 // 'v >>= 7, v >>= 1' is no more than a work around to get rid of shift size
64 // warning when Uint = uint8_t (it's false as v >= 256 implies sizeof(v) > 1).
65 for (; !less_than<unsigned, 256>(v); v >>= 7, v >>= 1) {
68 buffer[bufLen] = repr[b][0];
69 buffer[bufLen + 1] = repr[b][1];
71 buffer[--bufLen] = repr[v][1];
73 buffer[--bufLen] = repr[v][0];
79 * Convert an unsigned to hex, using lower-case letters for the digits
80 * above 9. See the comments for uintToHex.
83 inline size_t uintToHexLower(char* buffer, size_t bufLen, Uint v) {
84 return uintToHex(buffer, bufLen, v, formatHexLower);
88 * Convert an unsigned to hex, using upper-case letters for the digits
89 * above 9. See the comments for uintToHex.
92 inline size_t uintToHexUpper(char* buffer, size_t bufLen, Uint v) {
93 return uintToHex(buffer, bufLen, v, formatHexUpper);
97 * Convert an unsigned to octal.
99 * Just like folly::detail::uintToBuffer in Conv.h, writes at the *end* of
100 * the supplied buffer and returns the offset of the beginning of the string
101 * from the start of the buffer. The formatted string will be in range
102 * [buf+begin, buf+bufLen).
104 template <class Uint>
105 size_t uintToOctal(char* buffer, size_t bufLen, Uint v) {
106 auto& repr = formatOctal;
107 // 'v >>= 7, v >>= 2' is no more than a work around to get rid of shift size
108 // warning when Uint = uint8_t (it's false as v >= 512 implies sizeof(v) > 1).
109 for (; !less_than<unsigned, 512>(v); v >>= 7, v >>= 2) {
112 buffer[bufLen] = repr[b][0];
113 buffer[bufLen + 1] = repr[b][1];
114 buffer[bufLen + 2] = repr[b][2];
116 buffer[--bufLen] = repr[v][2];
118 buffer[--bufLen] = repr[v][1];
121 buffer[--bufLen] = repr[v][0];
127 * Convert an unsigned to binary.
129 * Just like folly::detail::uintToBuffer in Conv.h, writes at the *end* of
130 * the supplied buffer and returns the offset of the beginning of the string
131 * from the start of the buffer. The formatted string will be in range
132 * [buf+begin, buf+bufLen).
134 template <class Uint>
135 size_t uintToBinary(char* buffer, size_t bufLen, Uint v) {
136 auto& repr = formatBinary;
138 buffer[--bufLen] = '0';
141 for (; v; v >>= 7, v >>= 1) {
144 memcpy(buffer + bufLen, &(repr[b][0]), 8);
146 while (buffer[bufLen] == '0') {
152 } // namespace detail
154 template <class Derived, bool containerMode, class... Args>
155 BaseFormatter<Derived, containerMode, Args...>::BaseFormatter(StringPiece str,
158 values_(FormatValue<typename std::decay<Args>::type>(
159 std::forward<Args>(args))...) {
160 static_assert(!containerMode || sizeof...(Args) == 1,
161 "Exactly one argument required in container mode");
164 template <class Derived, bool containerMode, class... Args>
165 template <class Output>
166 void BaseFormatter<Derived, containerMode, Args...>::operator()(Output& out)
168 // Copy raw string (without format specifiers) to output;
169 // not as simple as we'd like, as we still need to translate "}}" to "}"
170 // and throw if we see any lone "}"
171 auto outputString = [&out] (StringPiece s) {
175 auto q = static_cast<const char*>(memchr(p, '}', end - p));
177 out(StringPiece(p, end));
181 out(StringPiece(p, q));
184 if (p == end || *p != '}') {
185 throw BadFormatArg("folly::format: single '}' in format string");
191 auto p = str_.begin();
192 auto end = str_.end();
195 bool hasDefaultArgIndex = false;
196 bool hasExplicitArgIndex = false;
198 auto q = static_cast<const char*>(memchr(p, '{', end - p));
200 outputString(StringPiece(p, end));
203 outputString(StringPiece(p, q));
207 throw BadFormatArg("folly::format: '}' at end of format string");
212 out(StringPiece(p, 1));
218 q = static_cast<const char*>(memchr(p, '}', end - p));
220 throw BadFormatArg("folly::format: missing ending '}'");
222 FormatArg arg(StringPiece(p, q));
226 auto piece = arg.splitKey<true>(); // empty key component is okay
227 if (containerMode) { // static
228 arg.enforce(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) {
240 arg.enforce(arg.widthIndex == FormatArg::kNoIndex,
241 "cannot provide width arg index without value arg index");
242 int sizeArg = nextArg++;
243 arg.width = getSizeArg(sizeArg, arg);
246 argIndex = nextArg++;
247 hasDefaultArgIndex = true;
249 if (arg.width == FormatArg::kDynamicWidth) {
250 arg.enforce(arg.widthIndex != FormatArg::kNoIndex,
251 "cannot provide value arg index without width arg index");
252 arg.width = getSizeArg(arg.widthIndex, arg);
256 argIndex = to<int>(piece);
257 } catch (const std::out_of_range& e) {
258 arg.error("argument index must be integer");
260 arg.enforce(argIndex >= 0, "argument index must be non-negative");
261 hasExplicitArgIndex = true;
265 if (hasDefaultArgIndex && hasExplicitArgIndex) {
267 "folly::format: may not have both default and explicit arg indexes");
270 doFormat(argIndex, arg, out);
274 template <class Derived, bool containerMode, class... Args>
275 void writeTo(FILE* fp,
276 const BaseFormatter<Derived, containerMode, Args...>& formatter) {
277 auto writer = [fp] (StringPiece sp) {
278 size_t n = fwrite(sp.data(), 1, sp.size(), fp);
280 throwSystemError("Formatter writeTo", "fwrite failed");
286 namespace format_value {
288 template <class FormatCallback>
289 void formatString(StringPiece val, FormatArg& arg, FormatCallback& cb) {
290 if (arg.width != FormatArg::kDefaultWidth && arg.width < 0) {
291 throw BadFormatArg("folly::format: invalid width");
293 if (arg.precision != FormatArg::kDefaultPrecision && arg.precision < 0) {
294 throw BadFormatArg("folly::format: invalid precision");
297 // XXX: clang should be smart enough to not need the two static_cast<size_t>
298 // uses below given the above checks. If clang ever becomes that smart, we
299 // should remove the otherwise unnecessary warts.
301 if (arg.precision != FormatArg::kDefaultPrecision &&
302 val.size() > static_cast<size_t>(arg.precision)) {
303 val.reset(val.data(), arg.precision);
306 constexpr int padBufSize = 128;
307 char padBuf[padBufSize];
309 // Output padding, no more than padBufSize at once
310 auto pad = [&padBuf, &cb, padBufSize] (int chars) {
312 int n = std::min(chars, padBufSize);
313 cb(StringPiece(padBuf, n));
318 int padRemaining = 0;
319 if (arg.width != FormatArg::kDefaultWidth &&
320 val.size() < static_cast<size_t>(arg.width)) {
321 char fill = arg.fill == FormatArg::kDefaultFill ? ' ' : arg.fill;
322 int padChars = static_cast<int> (arg.width - val.size());
323 memset(padBuf, fill, std::min(padBufSize, padChars));
326 case FormatArg::Align::DEFAULT:
327 case FormatArg::Align::LEFT:
328 padRemaining = padChars;
330 case FormatArg::Align::CENTER:
332 padRemaining = padChars - padChars / 2;
334 case FormatArg::Align::RIGHT:
335 case FormatArg::Align::PAD_AFTER_SIGN:
351 template <class FormatCallback>
352 void formatNumber(StringPiece val, int prefixLen, FormatArg& arg,
353 FormatCallback& cb) {
354 // precision means something different for numbers
355 arg.precision = FormatArg::kDefaultPrecision;
356 if (arg.align == FormatArg::Align::DEFAULT) {
357 arg.align = FormatArg::Align::RIGHT;
358 } else if (prefixLen && arg.align == FormatArg::Align::PAD_AFTER_SIGN) {
359 // Split off the prefix, then do any padding if necessary
360 cb(val.subpiece(0, prefixLen));
361 val.advance(prefixLen);
362 arg.width = std::max(arg.width - prefixLen, 0);
364 format_value::formatString(val, arg, cb);
367 template <class FormatCallback,
371 void formatFormatter(
372 const BaseFormatter<Derived, containerMode, Args...>& formatter,
374 FormatCallback& cb) {
375 if (arg.width == FormatArg::kDefaultWidth &&
376 arg.precision == FormatArg::kDefaultPrecision) {
379 } else if (arg.align != FormatArg::Align::LEFT &&
380 arg.align != FormatArg::Align::DEFAULT) {
381 // We can only avoid creating a temporary string if we align left,
382 // as we'd need to know the size beforehand otherwise
383 format_value::formatString(formatter.fbstr(), arg, cb);
385 auto fn = [&arg, &cb] (StringPiece sp) mutable {
386 int sz = static_cast<int>(sp.size());
387 if (arg.precision != FormatArg::kDefaultPrecision) {
388 sz = std::min(arg.precision, sz);
389 sp.reset(sp.data(), sz);
394 if (arg.width != FormatArg::kDefaultWidth) {
395 arg.width = std::max(arg.width - sz, 0);
400 if (arg.width != FormatArg::kDefaultWidth && arg.width != 0) {
401 // Rely on formatString to do appropriate padding
402 format_value::formatString(StringPiece(), arg, cb);
407 } // namespace format_value
409 // Definitions for default FormatValue classes
411 // Integral types (except bool)
414 T, typename std::enable_if<
415 std::is_integral<T>::value &&
416 !std::is_same<T, bool>::value>::type>
419 explicit FormatValue(T val) : val_(val) { }
425 template <class FormatCallback>
426 void format(FormatArg& arg, FormatCallback& cb) const {
427 arg.validate(FormatArg::Type::INTEGER);
431 template <class FormatCallback>
432 void doFormat(FormatArg& arg, FormatCallback& cb) const {
433 char presentation = arg.presentation;
434 if (presentation == FormatArg::kDefaultPresentation) {
435 presentation = std::is_same<T, char>::value ? 'c' : 'd';
438 // Do all work as unsigned, we'll add the prefix ('0' or '0x' if necessary)
439 // and sign ourselves.
440 typedef typename std::make_unsigned<T>::type UT;
443 if (std::is_signed<T>::value) {
444 if (folly::is_negative(val_)) {
445 uval = static_cast<UT>(-val_);
448 uval = static_cast<UT>(val_);
450 case FormatArg::Sign::PLUS_OR_MINUS:
453 case FormatArg::Sign::SPACE_OR_MINUS:
465 arg.enforce(arg.sign == FormatArg::Sign::DEFAULT,
466 "sign specifications not allowed for unsigned values");
470 // #x: 0x prefix + 16 bytes = 18 bytes
471 // #o: 0 prefix + 22 bytes = 23 bytes
472 // #b: 0b prefix + 64 bytes = 65 bytes
473 // ,d: 26 bytes (including thousands separators!)
475 // + 3 for sign and prefix shenanigans (see below)
476 constexpr size_t valBufSize = 69;
477 char valBuf[valBufSize];
478 char* valBufBegin = nullptr;
479 char* valBufEnd = nullptr;
482 switch (presentation) {
484 arg.enforce(!arg.basePrefix,
485 "base prefix not allowed with '", presentation,
488 arg.enforce(!arg.thousandsSeparator,
489 "cannot use ',' with the '", presentation,
492 valBufBegin = valBuf + 3; // room for sign and base prefix
494 char valBuf2[valBufSize];
495 snprintf(valBuf2, valBufSize, "%ju", static_cast<uintmax_t>(uval));
496 int len = GetNumberFormat(
502 (int)((valBuf + valBufSize) - valBufBegin)
505 int len = snprintf(valBufBegin, (valBuf + valBufSize) - valBufBegin,
506 "%'ju", static_cast<uintmax_t>(uval));
508 // valBufSize should always be big enough, so this should never
510 assert(len < valBuf + valBufSize - valBufBegin);
511 valBufEnd = valBufBegin + len;
515 arg.enforce(!arg.basePrefix,
516 "base prefix not allowed with '", presentation,
518 valBufBegin = valBuf + 3; // room for sign and base prefix
520 // Use uintToBuffer, faster than sprintf
521 valBufEnd = valBufBegin + uint64ToBufferUnsafe(uval, valBufBegin);
522 if (arg.thousandsSeparator) {
523 detail::insertThousandsGroupingUnsafe(valBufBegin, &valBufEnd);
527 arg.enforce(!arg.basePrefix,
528 "base prefix not allowed with '", presentation,
530 arg.enforce(!arg.thousandsSeparator,
531 "thousands separator (',') not allowed with '",
532 presentation, "' specifier");
533 valBufBegin = valBuf + 3;
534 *valBufBegin = static_cast<char>(uval);
535 valBufEnd = valBufBegin + 1;
539 arg.enforce(!arg.thousandsSeparator,
540 "thousands separator (',') not allowed with '",
541 presentation, "' specifier");
542 valBufEnd = valBuf + valBufSize - 1;
543 valBufBegin = valBuf + detail::uintToOctal(valBuf, valBufSize - 1, uval);
544 if (arg.basePrefix) {
545 *--valBufBegin = '0';
550 arg.enforce(!arg.thousandsSeparator,
551 "thousands separator (',') not allowed with '",
552 presentation, "' specifier");
553 valBufEnd = valBuf + valBufSize - 1;
554 valBufBegin = valBuf + detail::uintToHexLower(valBuf, valBufSize - 1,
556 if (arg.basePrefix) {
557 *--valBufBegin = 'x';
558 *--valBufBegin = '0';
563 arg.enforce(!arg.thousandsSeparator,
564 "thousands separator (',') not allowed with '",
565 presentation, "' specifier");
566 valBufEnd = valBuf + valBufSize - 1;
567 valBufBegin = valBuf + detail::uintToHexUpper(valBuf, valBufSize - 1,
569 if (arg.basePrefix) {
570 *--valBufBegin = 'X';
571 *--valBufBegin = '0';
577 arg.enforce(!arg.thousandsSeparator,
578 "thousands separator (',') not allowed with '",
579 presentation, "' specifier");
580 valBufEnd = valBuf + valBufSize - 1;
581 valBufBegin = valBuf + detail::uintToBinary(valBuf, valBufSize - 1,
583 if (arg.basePrefix) {
584 *--valBufBegin = presentation; // 0b or 0B
585 *--valBufBegin = '0';
590 arg.error("invalid specifier '", presentation, "'");
594 *--valBufBegin = sign;
598 format_value::formatNumber(StringPiece(valBufBegin, valBufEnd), prefixLen,
608 class FormatValue<bool> {
610 explicit FormatValue(bool val) : val_(val) { }
612 template <class FormatCallback>
613 void format(FormatArg& arg, FormatCallback& cb) const {
614 if (arg.presentation == FormatArg::kDefaultPresentation) {
615 arg.validate(FormatArg::Type::OTHER);
616 format_value::formatString(val_ ? "true" : "false", arg, cb);
618 FormatValue<int>(val_).format(arg, cb);
628 class FormatValue<double> {
630 explicit FormatValue(double val) : val_(val) { }
632 template <class FormatCallback>
633 void format(FormatArg& arg, FormatCallback& cb) const {
636 formatHelper(piece, prefixLen, arg);
637 format_value::formatNumber(piece, prefixLen, arg, cb);
641 void formatHelper(fbstring& piece, int& prefixLen, FormatArg& arg) const;
646 // float (defer to double)
648 class FormatValue<float> {
650 explicit FormatValue(float val) : val_(val) { }
652 template <class FormatCallback>
653 void format(FormatArg& arg, FormatCallback& cb) const {
654 FormatValue<double>(val_).format(arg, cb);
661 // Sring-y types (implicitly convertible to StringPiece, except char*)
664 T, typename std::enable_if<
665 (!std::is_pointer<T>::value ||
666 !std::is_same<char, typename std::decay<
667 typename std::remove_pointer<T>::type>::type>::value) &&
668 std::is_convertible<T, StringPiece>::value>::type>
671 explicit FormatValue(StringPiece val) : val_(val) { }
673 template <class FormatCallback>
674 void format(FormatArg& arg, FormatCallback& cb) const {
675 if (arg.keyEmpty()) {
676 arg.validate(FormatArg::Type::OTHER);
677 arg.enforce(arg.presentation == FormatArg::kDefaultPresentation ||
678 arg.presentation == 's',
679 "invalid specifier '", arg.presentation, "'");
680 format_value::formatString(val_, arg, cb);
682 FormatValue<char>(val_.at(arg.splitIntKey())).format(arg, cb);
692 class FormatValue<std::nullptr_t> {
694 explicit FormatValue(std::nullptr_t) { }
696 template <class FormatCallback>
697 void format(FormatArg& arg, FormatCallback& cb) const {
698 arg.validate(FormatArg::Type::OTHER);
699 arg.enforce(arg.presentation == FormatArg::kDefaultPresentation,
700 "invalid specifier '", arg.presentation, "'");
701 format_value::formatString("(null)", arg, cb);
705 // Partial specialization of FormatValue for char*
709 typename std::enable_if<
710 std::is_same<char, typename std::decay<T>::type>::value>::type>
713 explicit FormatValue(T* val) : val_(val) { }
715 template <class FormatCallback>
716 void format(FormatArg& arg, FormatCallback& cb) const {
717 if (arg.keyEmpty()) {
719 FormatValue<std::nullptr_t>(nullptr).format(arg, cb);
721 FormatValue<StringPiece>(val_).format(arg, cb);
724 FormatValue<typename std::decay<T>::type>(
725 val_[arg.splitIntKey()]).format(arg, cb);
733 // Partial specialization of FormatValue for void*
737 typename std::enable_if<
738 std::is_same<void, 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 {
746 FormatValue<std::nullptr_t>(nullptr).format(arg, cb);
748 // Print as a pointer, in hex.
749 arg.validate(FormatArg::Type::OTHER);
750 arg.enforce(arg.presentation == FormatArg::kDefaultPresentation,
751 "invalid specifier '", arg.presentation, "'");
752 arg.basePrefix = true;
753 arg.presentation = 'x';
754 if (arg.align == FormatArg::Align::DEFAULT) {
755 arg.align = FormatArg::Align::LEFT;
757 FormatValue<uintptr_t>(
758 reinterpret_cast<uintptr_t>(val_)).doFormat(arg, cb);
766 template <class T, class = void>
767 class TryFormatValue {
769 template <class FormatCallback>
770 static void formatOrFail(T& value, FormatArg& arg, FormatCallback& cb) {
771 arg.error("No formatter available for this type");
776 class TryFormatValue<
778 typename std::enable_if<
779 0 < sizeof(FormatValue<typename std::decay<T>::type>)>::type>
782 template <class FormatCallback>
783 static void formatOrFail(T& value, FormatArg& arg, FormatCallback& cb) {
784 FormatValue<typename std::decay<T>::type>(value).format(arg, cb);
788 // Partial specialization of FormatValue for other pointers
792 typename std::enable_if<
793 !std::is_same<char, typename std::decay<T>::type>::value &&
794 !std::is_same<void, typename std::decay<T>::type>::value>::type>
797 explicit FormatValue(T* val) : val_(val) { }
799 template <class FormatCallback>
800 void format(FormatArg& arg, FormatCallback& cb) const {
801 if (arg.keyEmpty()) {
802 FormatValue<void*>((void*)val_).format(arg, cb);
804 TryFormatValue<T>::formatOrFail(val_[arg.splitIntKey()], arg, cb);
814 template <class T, size_t N>
815 struct IndexableTraits<std::array<T, N>>
816 : public IndexableTraitsSeq<std::array<T, N>> {
820 template <class T, class A>
821 struct IndexableTraits<std::vector<T, A>>
822 : public IndexableTraitsSeq<std::vector<T, A>> {
826 template <class T, class A>
827 struct IndexableTraits<std::deque<T, A>>
828 : public IndexableTraitsSeq<std::deque<T, A>> {
831 // std::map with integral keys
832 template <class K, class T, class C, class A>
833 struct IndexableTraits<
834 std::map<K, T, C, A>,
835 typename std::enable_if<std::is_integral<K>::value>::type>
836 : public IndexableTraitsAssoc<std::map<K, T, C, A>> {
839 // std::unordered_map with integral keys
840 template <class K, class T, class H, class E, class A>
841 struct IndexableTraits<
842 std::unordered_map<K, T, H, E, A>,
843 typename std::enable_if<std::is_integral<K>::value>::type>
844 : public IndexableTraitsAssoc<std::unordered_map<K, T, H, E, A>> {
847 } // namespace detail
849 // Partial specialization of FormatValue for integer-indexable containers
853 typename detail::IndexableTraits<T>::enabled> {
855 explicit FormatValue(const T& val) : val_(val) { }
857 template <class FormatCallback>
858 void format(FormatArg& arg, FormatCallback& cb) const {
859 FormatValue<typename std::decay<
860 typename detail::IndexableTraits<T>::value_type>::type>(
861 detail::IndexableTraits<T>::at(
862 val_, arg.splitIntKey())).format(arg, cb);
869 template <class Container, class Value>
871 detail::DefaultValueWrapper<Container, Value>,
872 typename detail::IndexableTraits<Container>::enabled> {
874 explicit FormatValue(const detail::DefaultValueWrapper<Container, Value>& val)
877 template <class FormatCallback>
878 void format(FormatArg& arg, FormatCallback& cb) const {
879 FormatValue<typename std::decay<
880 typename detail::IndexableTraits<Container>::value_type>::type>(
881 detail::IndexableTraits<Container>::at(
884 val_.defaultValue)).format(arg, cb);
888 const detail::DefaultValueWrapper<Container, Value>& val_;
893 // Define enabled, key_type, convert from StringPiece to the key types
895 template <class T> struct KeyFromStringPiece;
899 struct KeyFromStringPiece<std::string> : public FormatTraitsBase {
900 typedef std::string key_type;
901 static std::string convert(StringPiece s) {
904 typedef void enabled;
909 struct KeyFromStringPiece<fbstring> : public FormatTraitsBase {
910 typedef fbstring key_type;
911 static fbstring convert(StringPiece s) {
912 return s.toFbstring();
918 struct KeyFromStringPiece<StringPiece> : public FormatTraitsBase {
919 typedef StringPiece key_type;
920 static StringPiece convert(StringPiece s) {
925 // Base class for associative types keyed by strings
926 template <class T> struct KeyableTraitsAssoc : public FormatTraitsBase {
927 typedef typename T::key_type key_type;
928 typedef typename T::value_type::second_type value_type;
929 static const value_type& at(const T& map, StringPiece key) {
930 return map.at(KeyFromStringPiece<key_type>::convert(key));
932 static const value_type& at(const T& map, StringPiece key,
933 const value_type& dflt) {
934 auto pos = map.find(KeyFromStringPiece<key_type>::convert(key));
935 return pos != map.end() ? pos->second : dflt;
939 // Define enabled, key_type, value_type, at() for supported string-keyed
941 template <class T, class Enabled=void> struct KeyableTraits;
943 // std::map with string key
944 template <class K, class T, class C, class A>
945 struct KeyableTraits<
946 std::map<K, T, C, A>,
947 typename KeyFromStringPiece<K>::enabled>
948 : public KeyableTraitsAssoc<std::map<K, T, C, A>> {
951 // std::unordered_map with string key
952 template <class K, class T, class H, class E, class A>
953 struct KeyableTraits<
954 std::unordered_map<K, T, H, E, A>,
955 typename KeyFromStringPiece<K>::enabled>
956 : public KeyableTraitsAssoc<std::unordered_map<K, T, H, E, A>> {
959 } // namespace detail
961 // Partial specialization of FormatValue for string-keyed containers
965 typename detail::KeyableTraits<T>::enabled> {
967 explicit FormatValue(const T& val) : val_(val) { }
969 template <class FormatCallback>
970 void format(FormatArg& arg, FormatCallback& cb) const {
971 FormatValue<typename std::decay<
972 typename detail::KeyableTraits<T>::value_type>::type>(
973 detail::KeyableTraits<T>::at(
974 val_, arg.splitKey())).format(arg, cb);
981 template <class Container, class Value>
983 detail::DefaultValueWrapper<Container, Value>,
984 typename detail::KeyableTraits<Container>::enabled> {
986 explicit FormatValue(const detail::DefaultValueWrapper<Container, Value>& val)
989 template <class FormatCallback>
990 void format(FormatArg& arg, FormatCallback& cb) const {
991 FormatValue<typename std::decay<
992 typename detail::KeyableTraits<Container>::value_type>::type>(
993 detail::KeyableTraits<Container>::at(
996 val_.defaultValue)).format(arg, cb);
1000 const detail::DefaultValueWrapper<Container, Value>& val_;
1003 // Partial specialization of FormatValue for pairs
1004 template <class A, class B>
1005 class FormatValue<std::pair<A, B>> {
1007 explicit FormatValue(const std::pair<A, B>& val) : val_(val) { }
1009 template <class FormatCallback>
1010 void format(FormatArg& arg, FormatCallback& cb) const {
1011 int key = arg.splitIntKey();
1014 FormatValue<typename std::decay<A>::type>(val_.first).format(arg, cb);
1017 FormatValue<typename std::decay<B>::type>(val_.second).format(arg, cb);
1020 arg.error("invalid index for pair");
1025 const std::pair<A, B>& val_;
1028 // Partial specialization of FormatValue for tuples
1029 template <class... Args>
1030 class FormatValue<std::tuple<Args...>> {
1031 typedef std::tuple<Args...> Tuple;
1033 explicit FormatValue(const Tuple& val) : val_(val) { }
1035 template <class FormatCallback>
1036 void format(FormatArg& arg, FormatCallback& cb) const {
1037 int key = arg.splitIntKey();
1038 arg.enforce(key >= 0, "tuple index must be non-negative");
1039 doFormat(key, arg, cb);
1043 static constexpr size_t valueCount = std::tuple_size<Tuple>::value;
1045 template <size_t K, class Callback>
1046 typename std::enable_if<K == valueCount>::type
1047 doFormatFrom(size_t i, FormatArg& arg, Callback& cb) const {
1048 arg.enforce("tuple index out of range, max=", i);
1051 template <size_t K, class Callback>
1052 typename std::enable_if<(K < valueCount)>::type
1053 doFormatFrom(size_t i, FormatArg& arg, Callback& cb) const {
1055 FormatValue<typename std::decay<
1056 typename std::tuple_element<K, Tuple>::type>::type>(
1057 std::get<K>(val_)).format(arg, cb);
1059 doFormatFrom<K+1>(i, arg, cb);
1063 template <class Callback>
1064 void doFormat(size_t i, FormatArg& arg, Callback& cb) const {
1065 return doFormatFrom<0>(i, arg, cb);
1071 // Partial specialization of FormatValue for nested Formatters
1072 template <bool containerMode, class... Args,
1073 template <bool, class...> class F>
1074 class FormatValue<F<containerMode, Args...>,
1075 typename std::enable_if<detail::IsFormatter<
1076 F<containerMode, Args...>>::value>::type> {
1077 typedef typename F<containerMode, Args...>::BaseType FormatterValue;
1080 explicit FormatValue(const FormatterValue& f) : f_(f) { }
1082 template <class FormatCallback>
1083 void format(FormatArg& arg, FormatCallback& cb) const {
1084 format_value::formatFormatter(f_, arg, cb);
1087 const FormatterValue& f_;
1091 * Formatter objects can be appended to strings, and therefore they're
1092 * compatible with folly::toAppend and folly::to.
1094 template <class Tgt, class Derived, bool containerMode, class... Args>
1095 typename std::enable_if<IsSomeString<Tgt>::value>::type toAppend(
1096 const BaseFormatter<Derived, containerMode, Args...>& value, Tgt* result) {
1097 value.appendTo(*result);
1100 } // namespace folly
1102 #pragma GCC diagnostic pop