2 * Copyright 2014 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.
21 #include "folly/Exception.h"
22 #include "folly/Traits.h"
28 extern const char formatHexUpper[256][2];
29 extern const char formatHexLower[256][2];
30 extern const char formatOctal[512][3];
31 extern const char formatBinary[256][8];
33 const size_t kMaxHexLength = 2 * sizeof(uintmax_t);
34 const size_t kMaxOctalLength = 3 * sizeof(uintmax_t);
35 const size_t kMaxBinaryLength = 8 * sizeof(uintmax_t);
38 * Convert an unsigned to hex, using repr (which maps from each possible
39 * 2-hex-bytes value to the 2-character representation).
41 * Just like folly::detail::uintToBuffer in Conv.h, writes at the *end* of
42 * the supplied buffer and returns the offset of the beginning of the string
43 * from the start of the buffer. The formatted string will be in range
44 * [buf+begin, buf+bufLen).
47 size_t uintToHex(char* buffer, size_t bufLen, Uint v,
48 const char (&repr)[256][2]) {
49 // 'v >>= 7, v >>= 1' is no more than a work around to get rid of shift size
50 // warning when Uint = uint8_t (it's false as v >= 256 implies sizeof(v) > 1).
51 for (; !less_than<unsigned, 256>(v); v >>= 7, v >>= 1) {
54 buffer[bufLen] = repr[b][0];
55 buffer[bufLen + 1] = repr[b][1];
57 buffer[--bufLen] = repr[v][1];
59 buffer[--bufLen] = repr[v][0];
65 * Convert an unsigned to hex, using lower-case letters for the digits
66 * above 9. See the comments for uintToHex.
69 inline size_t uintToHexLower(char* buffer, size_t bufLen, Uint v) {
70 return uintToHex(buffer, bufLen, v, formatHexLower);
74 * Convert an unsigned to hex, using upper-case letters for the digits
75 * above 9. See the comments for uintToHex.
78 inline size_t uintToHexUpper(char* buffer, size_t bufLen, Uint v) {
79 return uintToHex(buffer, bufLen, v, formatHexUpper);
83 * Convert an unsigned to octal.
85 * Just like folly::detail::uintToBuffer in Conv.h, writes at the *end* of
86 * the supplied buffer and returns the offset of the beginning of the string
87 * from the start of the buffer. The formatted string will be in range
88 * [buf+begin, buf+bufLen).
91 size_t uintToOctal(char* buffer, size_t bufLen, Uint v) {
92 auto& repr = formatOctal;
93 // 'v >>= 7, v >>= 2' is no more than a work around to get rid of shift size
94 // warning when Uint = uint8_t (it's false as v >= 512 implies sizeof(v) > 1).
95 for (; !less_than<unsigned, 512>(v); v >>= 7, v >>= 2) {
98 buffer[bufLen] = repr[b][0];
99 buffer[bufLen + 1] = repr[b][1];
100 buffer[bufLen + 2] = repr[b][2];
102 buffer[--bufLen] = repr[v][2];
104 buffer[--bufLen] = repr[v][1];
107 buffer[--bufLen] = repr[v][0];
113 * Convert an unsigned to binary.
115 * Just like folly::detail::uintToBuffer in Conv.h, writes at the *end* of
116 * the supplied buffer and returns the offset of the beginning of the string
117 * from the start of the buffer. The formatted string will be in range
118 * [buf+begin, buf+bufLen).
120 template <class Uint>
121 size_t uintToBinary(char* buffer, size_t bufLen, Uint v) {
122 auto& repr = formatBinary;
124 buffer[--bufLen] = '0';
127 for (; v; v >>= 7, v >>= 1) {
130 memcpy(buffer + bufLen, &(repr[b][0]), 8);
132 while (buffer[bufLen] == '0') {
138 } // namespace detail
141 template <bool containerMode, class... Args>
142 Formatter<containerMode, Args...>::Formatter(StringPiece str, Args&&... args)
144 values_(FormatValue<typename std::decay<Args>::type>(
145 std::forward<Args>(args))...) {
146 static_assert(!containerMode || sizeof...(Args) == 1,
147 "Exactly one argument required in container mode");
150 template <bool containerMode, class... Args>
151 void Formatter<containerMode, Args...>::handleFormatStrError() const {
153 LOG(FATAL) << "folly::format: bad format string \"" << str_ << "\": " <<
154 folly::exceptionStr(std::current_exception());
159 template <bool containerMode, class... Args>
160 template <class Output>
161 void Formatter<containerMode, Args...>::operator()(Output& out) const {
162 // Catch BadFormatArg and range_error exceptions, and call
163 // handleFormatStrError().
165 // These exception types indicate a problem with the format string. Most
166 // format strings are string literals specified by the programmer. If they
167 // have a problem, this is usually a programmer bug. We want to crash to
168 // ensure that these are found early on during development.
170 // BadFormatArg is thrown by the Format.h code, while range_error is thrown
171 // by Conv.h, which is used in several places in our format string
174 // (Note: This behavior is slightly dangerous. If the Output object throws a
175 // BadFormatArg or a range_error, we will also crash the program, even if it
176 // wasn't an issue with the format string. This seems highly unlikely
177 // though, and none of our current Output objects can throw these errors.)
179 // We also throw out_of_range errors if the format string references an
180 // argument that isn't present (or a key that isn't present in one of the
181 // argument containers). However, at the moment we don't crash on these
182 // errors, as it is likely that the container is dynamic at runtime.
185 } catch (const BadFormatArg& ex) {
186 handleFormatStrError();
187 } catch (const std::range_error& ex) {
188 handleFormatStrError();
192 template <bool containerMode, class... Args>
193 template <class Output>
194 void Formatter<containerMode, Args...>::appendOutput(Output& out) const {
195 auto p = str_.begin();
196 auto end = str_.end();
198 // Copy raw string (without format specifiers) to output;
199 // not as simple as we'd like, as we still need to translate "}}" to "}"
200 // and throw if we see any lone "}"
201 auto outputString = [&out] (StringPiece s) {
205 auto q = static_cast<const char*>(memchr(p, '}', end - p));
207 out(StringPiece(p, end));
211 out(StringPiece(p, q));
214 if (p == end || *p != '}') {
215 throw BadFormatArg("folly::format: single '}' in format string");
222 bool hasDefaultArgIndex = false;
223 bool hasExplicitArgIndex = false;
225 auto q = static_cast<const char*>(memchr(p, '{', end - p));
227 outputString(StringPiece(p, end));
230 outputString(StringPiece(p, q));
234 throw BadFormatArg("folly::format: '}' at end of format string");
239 out(StringPiece(p, 1));
245 q = static_cast<const char*>(memchr(p, '}', end - p));
247 throw BadFormatArg("folly::format: missing ending '}'");
249 FormatArg arg(StringPiece(p, q));
253 auto piece = arg.splitKey<true>(); // empty key component is okay
254 if (containerMode) { // static
256 arg.setNextIntKey(nextArg++);
257 hasDefaultArgIndex = true;
259 arg.setNextKey(piece);
260 hasExplicitArgIndex = true;
264 argIndex = nextArg++;
265 hasDefaultArgIndex = true;
268 argIndex = to<int>(piece);
269 } catch (const std::out_of_range& e) {
270 arg.error("argument index must be integer");
272 arg.enforce(argIndex >= 0, "argument index must be non-negative");
273 hasExplicitArgIndex = true;
277 if (hasDefaultArgIndex && hasExplicitArgIndex) {
279 "folly::format: may not have both default and explicit arg indexes");
282 doFormat(argIndex, arg, out);
286 template <bool containerMode, class... Args>
287 void writeTo(FILE* fp, const Formatter<containerMode, Args...>& formatter) {
288 auto writer = [fp] (StringPiece sp) {
289 ssize_t n = fwrite(sp.data(), 1, sp.size(), fp);
291 throwSystemError("Formatter writeTo", "fwrite failed");
297 namespace format_value {
299 template <class FormatCallback>
300 void formatString(StringPiece val, FormatArg& arg, FormatCallback& cb) {
301 if (arg.precision != FormatArg::kDefaultPrecision &&
302 val.size() > 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 && val.size() < arg.width) {
320 char fill = arg.fill == FormatArg::kDefaultFill ? ' ' : arg.fill;
321 int padChars = arg.width - val.size();
322 memset(padBuf, fill, 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>
351 void formatNumber(StringPiece val, int prefixLen, FormatArg& arg,
352 FormatCallback& cb) {
353 // precision means something different for numbers
354 arg.precision = FormatArg::kDefaultPrecision;
355 if (arg.align == FormatArg::Align::DEFAULT) {
356 arg.align = FormatArg::Align::RIGHT;
357 } else if (prefixLen && arg.align == FormatArg::Align::PAD_AFTER_SIGN) {
358 // Split off the prefix, then do any padding if necessary
359 cb(val.subpiece(0, prefixLen));
360 val.advance(prefixLen);
361 arg.width = std::max(arg.width - prefixLen, 0);
363 format_value::formatString(val, arg, cb);
366 template <class FormatCallback, bool containerMode, class... Args>
367 void formatFormatter(const Formatter<containerMode, Args...>& formatter,
369 FormatCallback& cb) {
370 if (arg.width == FormatArg::kDefaultWidth &&
371 arg.precision == FormatArg::kDefaultPrecision) {
374 } else if (arg.align != FormatArg::Align::LEFT &&
375 arg.align != FormatArg::Align::DEFAULT) {
376 // We can only avoid creating a temporary string if we align left,
377 // as we'd need to know the size beforehand otherwise
378 format_value::formatString(formatter.fbstr(), arg, cb);
380 auto fn = [&arg, &cb] (StringPiece sp) mutable {
381 int sz = static_cast<int>(sp.size());
382 if (arg.precision != FormatArg::kDefaultPrecision) {
383 sz = std::min(arg.precision, sz);
384 sp.reset(sp.data(), sz);
389 if (arg.width != FormatArg::kDefaultWidth) {
390 arg.width = std::max(arg.width - sz, 0);
395 if (arg.width != FormatArg::kDefaultWidth && arg.width != 0) {
396 // Rely on formatString to do appropriate padding
397 format_value::formatString(StringPiece(), arg, cb);
402 } // namespace format_value
404 // Definitions for default FormatValue classes
406 // Integral types (except bool)
409 T, typename std::enable_if<
410 std::is_integral<T>::value &&
411 !std::is_same<T, bool>::value>::type>
414 explicit FormatValue(T val) : val_(val) { }
415 template <class FormatCallback>
416 void format(FormatArg& arg, FormatCallback& cb) const {
417 arg.validate(FormatArg::Type::INTEGER);
421 template <class FormatCallback>
422 void doFormat(FormatArg& arg, FormatCallback& cb) const {
423 char presentation = arg.presentation;
424 if (presentation == FormatArg::kDefaultPresentation) {
425 presentation = std::is_same<T, char>::value ? 'c' : 'd';
428 // Do all work as unsigned, we'll add the prefix ('0' or '0x' if necessary)
429 // and sign ourselves.
430 typedef typename std::make_unsigned<T>::type UT;
433 if (std::is_signed<T>::value) {
434 if (folly::is_negative(val_)) {
435 uval = static_cast<UT>(-val_);
438 uval = static_cast<UT>(val_);
440 case FormatArg::Sign::PLUS_OR_MINUS:
443 case FormatArg::Sign::SPACE_OR_MINUS:
455 arg.enforce(arg.sign == FormatArg::Sign::DEFAULT,
456 "sign specifications not allowed for unsigned values");
460 // #x: 0x prefix + 16 bytes = 18 bytes
461 // #o: 0 prefix + 22 bytes = 23 bytes
462 // #b: 0b prefix + 64 bytes = 65 bytes
463 // ,d: 26 bytes (including thousands separators!)
465 // + 3 for sign and prefix shenanigans (see below)
466 constexpr size_t valBufSize = 69;
467 char valBuf[valBufSize];
468 char* valBufBegin = nullptr;
469 char* valBufEnd = nullptr;
472 auto useSprintf = [&] (const char* format) mutable {
473 valBufBegin = valBuf + 3; // room for sign and base prefix
474 valBufEnd = valBufBegin + sprintf(valBufBegin, format,
475 static_cast<uintmax_t>(uval));
480 switch (presentation) {
481 case 'n': // TODO(tudorb): locale awareness?
483 arg.enforce(!arg.basePrefix,
484 "base prefix not allowed with '", presentation,
486 if (arg.thousandsSeparator) {
489 // Use uintToBuffer, faster than sprintf
490 valBufBegin = valBuf + 3;
491 valBufEnd = valBufBegin + uint64ToBufferUnsafe(uval, valBufBegin);
495 arg.enforce(!arg.basePrefix,
496 "base prefix not allowed with '", presentation,
498 arg.enforce(!arg.thousandsSeparator,
499 "thousands separator (',') not allowed with '",
500 presentation, "' specifier");
501 valBufBegin = valBuf + 3;
502 *valBufBegin = static_cast<char>(uval);
503 valBufEnd = valBufBegin + 1;
507 arg.enforce(!arg.thousandsSeparator,
508 "thousands separator (',') not allowed with '",
509 presentation, "' specifier");
510 valBufEnd = valBuf + valBufSize - 1;
511 valBufBegin = valBuf + detail::uintToOctal(valBuf, valBufSize - 1, uval);
512 if (arg.basePrefix) {
513 *--valBufBegin = '0';
518 arg.enforce(!arg.thousandsSeparator,
519 "thousands separator (',') not allowed with '",
520 presentation, "' specifier");
521 valBufEnd = valBuf + valBufSize - 1;
522 valBufBegin = valBuf + detail::uintToHexLower(valBuf, valBufSize - 1,
524 if (arg.basePrefix) {
525 *--valBufBegin = 'x';
526 *--valBufBegin = '0';
531 arg.enforce(!arg.thousandsSeparator,
532 "thousands separator (',') not allowed with '",
533 presentation, "' specifier");
534 valBufEnd = valBuf + valBufSize - 1;
535 valBufBegin = valBuf + detail::uintToHexUpper(valBuf, valBufSize - 1,
537 if (arg.basePrefix) {
538 *--valBufBegin = 'X';
539 *--valBufBegin = '0';
545 arg.enforce(!arg.thousandsSeparator,
546 "thousands separator (',') not allowed with '",
547 presentation, "' specifier");
548 valBufEnd = valBuf + valBufSize - 1;
549 valBufBegin = valBuf + detail::uintToBinary(valBuf, valBufSize - 1,
551 if (arg.basePrefix) {
552 *--valBufBegin = presentation; // 0b or 0B
553 *--valBufBegin = '0';
558 arg.error("invalid specifier '", presentation, "'");
562 *--valBufBegin = sign;
566 format_value::formatNumber(StringPiece(valBufBegin, valBufEnd), prefixLen,
576 class FormatValue<bool> {
578 explicit FormatValue(bool val) : val_(val) { }
580 template <class FormatCallback>
581 void format(FormatArg& arg, FormatCallback& cb) const {
582 if (arg.presentation == FormatArg::kDefaultPresentation) {
583 arg.validate(FormatArg::Type::OTHER);
584 format_value::formatString(val_ ? "true" : "false", arg, cb);
586 FormatValue<int>(val_).format(arg, cb);
596 class FormatValue<double> {
598 explicit FormatValue(double val) : val_(val) { }
600 template <class FormatCallback>
601 void format(FormatArg& arg, FormatCallback& cb) const {
602 using ::double_conversion::DoubleToStringConverter;
603 using ::double_conversion::StringBuilder;
605 arg.validate(FormatArg::Type::FLOAT);
607 if (arg.presentation == FormatArg::kDefaultPresentation) {
608 arg.presentation = 'g';
611 const char* infinitySymbol = isupper(arg.presentation) ? "INF" : "inf";
612 const char* nanSymbol = isupper(arg.presentation) ? "NAN" : "nan";
613 char exponentSymbol = isupper(arg.presentation) ? 'E' : 'e';
615 if (arg.precision == FormatArg::kDefaultPrecision) {
619 // 2+: for null terminator and optional sign shenanigans.
620 char buf[2 + std::max({
621 (2 + DoubleToStringConverter::kMaxFixedDigitsBeforePoint +
622 DoubleToStringConverter::kMaxFixedDigitsAfterPoint),
623 (8 + DoubleToStringConverter::kMaxExponentialDigits),
624 (7 + DoubleToStringConverter::kMaxPrecisionDigits)})];
625 StringBuilder builder(buf + 1, sizeof(buf) - 1);
629 case FormatArg::Sign::PLUS_OR_MINUS:
632 case FormatArg::Sign::SPACE_OR_MINUS:
641 switch (arg.presentation) {
648 DoubleToStringConverter::kMaxFixedDigitsAfterPoint) {
649 arg.precision = DoubleToStringConverter::kMaxFixedDigitsAfterPoint;
651 DoubleToStringConverter conv(
652 DoubleToStringConverter::EMIT_POSITIVE_EXPONENT_SIGN,
658 arg.enforce(conv.ToFixed(val, arg.precision, &builder),
659 "fixed double conversion failed");
665 if (arg.precision > DoubleToStringConverter::kMaxExponentialDigits) {
666 arg.precision = DoubleToStringConverter::kMaxExponentialDigits;
669 DoubleToStringConverter conv(
670 DoubleToStringConverter::EMIT_POSITIVE_EXPONENT_SIGN,
676 arg.enforce(conv.ToExponential(val, arg.precision, &builder));
679 case 'n': // should be locale-aware, but isn't
683 if (arg.precision < DoubleToStringConverter::kMinPrecisionDigits) {
684 arg.precision = DoubleToStringConverter::kMinPrecisionDigits;
685 } else if (arg.precision >
686 DoubleToStringConverter::kMaxPrecisionDigits) {
687 arg.precision = DoubleToStringConverter::kMaxPrecisionDigits;
689 DoubleToStringConverter conv(
690 DoubleToStringConverter::EMIT_POSITIVE_EXPONENT_SIGN,
696 arg.enforce(conv.ToShortest(val, &builder));
700 arg.error("invalid specifier '", arg.presentation, "'");
703 int len = builder.position();
707 // Add '+' or ' ' sign if needed
709 // anything that's neither negative nor nan
711 if (plusSign && (*p != '-' && *p != 'n' && *p != 'N')) {
715 } else if (*p == '-') {
719 format_value::formatNumber(StringPiece(p, len), prefixLen, arg, cb);
726 // float (defer to double)
728 class FormatValue<float> {
730 explicit FormatValue(float val) : val_(val) { }
732 template <class FormatCallback>
733 void format(FormatArg& arg, FormatCallback& cb) const {
734 FormatValue<double>(val_).format(arg, cb);
741 // Sring-y types (implicitly convertible to StringPiece, except char*)
744 T, typename std::enable_if<
745 (!std::is_pointer<T>::value ||
746 !std::is_same<char, typename std::decay<
747 typename std::remove_pointer<T>::type>::type>::value) &&
748 std::is_convertible<T, StringPiece>::value>::type>
751 explicit FormatValue(StringPiece val) : val_(val) { }
753 template <class FormatCallback>
754 void format(FormatArg& arg, FormatCallback& cb) const {
755 if (arg.keyEmpty()) {
756 arg.validate(FormatArg::Type::OTHER);
757 arg.enforce(arg.presentation == FormatArg::kDefaultPresentation ||
758 arg.presentation == 's',
759 "invalid specifier '", arg.presentation, "'");
760 format_value::formatString(val_, arg, cb);
762 FormatValue<char>(val_.at(arg.splitIntKey())).format(arg, cb);
772 class FormatValue<std::nullptr_t> {
774 explicit FormatValue(std::nullptr_t) { }
776 template <class FormatCallback>
777 void format(FormatArg& arg, FormatCallback& cb) const {
778 arg.validate(FormatArg::Type::OTHER);
779 arg.enforce(arg.presentation == FormatArg::kDefaultPresentation,
780 "invalid specifier '", arg.presentation, "'");
781 format_value::formatString("(null)", arg, cb);
785 // Partial specialization of FormatValue for char*
789 typename std::enable_if<
790 std::is_same<char, typename std::decay<T>::type>::value>::type>
793 explicit FormatValue(T* val) : val_(val) { }
795 template <class FormatCallback>
796 void format(FormatArg& arg, FormatCallback& cb) const {
797 if (arg.keyEmpty()) {
799 FormatValue<std::nullptr_t>(nullptr).format(arg, cb);
801 FormatValue<StringPiece>(val_).format(arg, cb);
804 FormatValue<typename std::decay<T>::type>(
805 val_[arg.splitIntKey()]).format(arg, cb);
813 // Partial specialization of FormatValue for void*
817 typename std::enable_if<
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 {
826 FormatValue<std::nullptr_t>(nullptr).format(arg, cb);
828 // Print as a pointer, in hex.
829 arg.validate(FormatArg::Type::OTHER);
830 arg.enforce(arg.presentation == FormatArg::kDefaultPresentation,
831 "invalid specifier '", arg.presentation, "'");
832 arg.basePrefix = true;
833 arg.presentation = 'x';
834 if (arg.align == FormatArg::Align::DEFAULT) {
835 arg.align = FormatArg::Align::LEFT;
837 FormatValue<uintptr_t>(
838 reinterpret_cast<uintptr_t>(val_)).doFormat(arg, cb);
846 template <class T, class = void>
847 class TryFormatValue {
849 template <class FormatCallback>
850 static void formatOrFail(T& value, FormatArg& arg, FormatCallback& cb) {
851 arg.error("No formatter available for this type");
856 class TryFormatValue<
858 typename std::enable_if<
859 0 < sizeof(FormatValue<typename std::decay<T>::type>)>::type>
862 template <class FormatCallback>
863 static void formatOrFail(T& value, FormatArg& arg, FormatCallback& cb) {
864 FormatValue<typename std::decay<T>::type>(value).format(arg, cb);
868 // Partial specialization of FormatValue for other pointers
872 typename std::enable_if<
873 !std::is_same<char, typename std::decay<T>::type>::value &&
874 !std::is_same<void, typename std::decay<T>::type>::value>::type>
877 explicit FormatValue(T* val) : val_(val) { }
879 template <class FormatCallback>
880 void format(FormatArg& arg, FormatCallback& cb) const {
881 if (arg.keyEmpty()) {
882 FormatValue<void*>((void*)val_).format(arg, cb);
884 TryFormatValue<T>::formatOrFail(val_[arg.splitIntKey()], arg, cb);
893 // Shortcut, so we don't have to use enable_if everywhere
894 struct FormatTraitsBase {
895 typedef void enabled;
898 // Traits that define enabled, value_type, and at() for anything
899 // indexable with integral keys: pointers, arrays, vectors, and maps
900 // with integral keys
901 template <class T, class Enable=void> struct IndexableTraits;
903 // Base class for sequences (vectors, deques)
905 struct IndexableTraitsSeq : public FormatTraitsBase {
906 typedef C container_type;
907 typedef typename C::value_type value_type;
908 static const value_type& at(const C& c, int idx) {
913 // Base class for associative types (maps)
915 struct IndexableTraitsAssoc : public FormatTraitsBase {
916 typedef typename C::value_type::second_type value_type;
917 static const value_type& at(const C& c, int idx) {
918 return c.at(static_cast<typename C::key_type>(idx));
923 template <class T, size_t N>
924 struct IndexableTraits<std::array<T, N>>
925 : public IndexableTraitsSeq<std::array<T, N>> {
929 template <class T, class A>
930 struct IndexableTraits<std::vector<T, A>>
931 : public IndexableTraitsSeq<std::vector<T, A>> {
935 template <class T, class A>
936 struct IndexableTraits<std::deque<T, A>>
937 : public IndexableTraitsSeq<std::deque<T, A>> {
941 template <class T, class A>
942 struct IndexableTraits<fbvector<T, A>>
943 : public IndexableTraitsSeq<fbvector<T, A>> {
947 template <class T, size_t M, class A, class B, class C>
948 struct IndexableTraits<small_vector<T, M, A, B, C>>
949 : public IndexableTraitsSeq<small_vector<T, M, A, B, C>> {
952 // std::map with integral keys
953 template <class K, class T, class C, class A>
954 struct IndexableTraits<
955 std::map<K, T, C, A>,
956 typename std::enable_if<std::is_integral<K>::value>::type>
957 : public IndexableTraitsAssoc<std::map<K, T, C, A>> {
960 // std::unordered_map with integral keys
961 template <class K, class T, class H, class E, class A>
962 struct IndexableTraits<
963 std::unordered_map<K, T, H, E, A>,
964 typename std::enable_if<std::is_integral<K>::value>::type>
965 : public IndexableTraitsAssoc<std::unordered_map<K, T, H, E, A>> {
968 } // namespace detail
970 // Partial specialization of FormatValue for integer-indexable containers
974 typename detail::IndexableTraits<T>::enabled> {
976 explicit FormatValue(const T& val) : val_(val) { }
978 template <class FormatCallback>
979 void format(FormatArg& arg, FormatCallback& cb) const {
980 FormatValue<typename std::decay<
981 typename detail::IndexableTraits<T>::value_type>::type>(
982 detail::IndexableTraits<T>::at(
983 val_, arg.splitIntKey())).format(arg, cb);
992 // Define enabled, key_type, convert from StringPiece to the key types
994 template <class T> struct KeyFromStringPiece;
998 struct KeyFromStringPiece<std::string> : public FormatTraitsBase {
999 typedef std::string key_type;
1000 static std::string convert(StringPiece s) {
1001 return s.toString();
1003 typedef void enabled;
1008 struct KeyFromStringPiece<fbstring> : public FormatTraitsBase {
1009 typedef fbstring key_type;
1010 static fbstring convert(StringPiece s) {
1011 return s.toFbstring();
1017 struct KeyFromStringPiece<StringPiece> : public FormatTraitsBase {
1018 typedef StringPiece key_type;
1019 static StringPiece convert(StringPiece s) {
1024 // Base class for associative types keyed by strings
1025 template <class T> struct KeyableTraitsAssoc : public FormatTraitsBase {
1026 typedef typename T::key_type key_type;
1027 typedef typename T::value_type::second_type value_type;
1028 static const value_type& at(const T& map, StringPiece key) {
1029 return map.at(KeyFromStringPiece<key_type>::convert(key));
1033 // Define enabled, key_type, value_type, at() for supported string-keyed
1035 template <class T, class Enabled=void> struct KeyableTraits;
1037 // std::map with string key
1038 template <class K, class T, class C, class A>
1039 struct KeyableTraits<
1040 std::map<K, T, C, A>,
1041 typename KeyFromStringPiece<K>::enabled>
1042 : public KeyableTraitsAssoc<std::map<K, T, C, A>> {
1045 // std::unordered_map with string key
1046 template <class K, class T, class H, class E, class A>
1047 struct KeyableTraits<
1048 std::unordered_map<K, T, H, E, A>,
1049 typename KeyFromStringPiece<K>::enabled>
1050 : public KeyableTraitsAssoc<std::unordered_map<K, T, H, E, A>> {
1053 } // namespace detail
1055 // Partial specialization of FormatValue for string-keyed containers
1059 typename detail::KeyableTraits<T>::enabled> {
1061 explicit FormatValue(const T& val) : val_(val) { }
1063 template <class FormatCallback>
1064 void format(FormatArg& arg, FormatCallback& cb) const {
1065 FormatValue<typename std::decay<
1066 typename detail::KeyableTraits<T>::value_type>::type>(
1067 detail::KeyableTraits<T>::at(
1068 val_, arg.splitKey())).format(arg, cb);
1075 // Partial specialization of FormatValue for pairs
1076 template <class A, class B>
1077 class FormatValue<std::pair<A, B>> {
1079 explicit FormatValue(const std::pair<A, B>& val) : val_(val) { }
1081 template <class FormatCallback>
1082 void format(FormatArg& arg, FormatCallback& cb) const {
1083 int key = arg.splitIntKey();
1086 FormatValue<typename std::decay<A>::type>(val_.first).format(arg, cb);
1089 FormatValue<typename std::decay<B>::type>(val_.second).format(arg, cb);
1092 arg.error("invalid index for pair");
1097 const std::pair<A, B>& val_;
1100 // Partial specialization of FormatValue for tuples
1101 template <class... Args>
1102 class FormatValue<std::tuple<Args...>> {
1103 typedef std::tuple<Args...> Tuple;
1105 explicit FormatValue(const Tuple& val) : val_(val) { }
1107 template <class FormatCallback>
1108 void format(FormatArg& arg, FormatCallback& cb) const {
1109 int key = arg.splitIntKey();
1110 arg.enforce(key >= 0, "tuple index must be non-negative");
1111 doFormat(key, arg, cb);
1115 static constexpr size_t valueCount = std::tuple_size<Tuple>::value;
1117 template <size_t K, class Callback>
1118 typename std::enable_if<K == valueCount>::type
1119 doFormatFrom(size_t i, FormatArg& arg, Callback& cb) const {
1120 arg.enforce("tuple index out of range, max=", i);
1123 template <size_t K, class Callback>
1124 typename std::enable_if<(K < valueCount)>::type
1125 doFormatFrom(size_t i, FormatArg& arg, Callback& cb) const {
1127 FormatValue<typename std::decay<
1128 typename std::tuple_element<K, Tuple>::type>::type>(
1129 std::get<K>(val_)).format(arg, cb);
1131 doFormatFrom<K+1>(i, arg, cb);
1135 template <class Callback>
1136 void doFormat(size_t i, FormatArg& arg, Callback& cb) const {
1137 return doFormatFrom<0>(i, arg, cb);
1143 // Partial specialization of FormatValue for nested Formatters
1144 template <bool containerMode, class... Args>
1145 class FormatValue<Formatter<containerMode, Args...>, void> {
1146 typedef Formatter<containerMode, Args...> FormatterValue;
1148 explicit FormatValue(const FormatterValue& f) : f_(f) { }
1150 template <class FormatCallback>
1151 void format(FormatArg& arg, FormatCallback& cb) const {
1152 format_value::formatFormatter(f_, arg, cb);
1155 const FormatterValue& f_;
1159 * Formatter objects can be appended to strings, and therefore they're
1160 * compatible with folly::toAppend and folly::to.
1162 template <class Tgt, bool containerMode, class... Args>
1163 typename std::enable_if<
1164 IsSomeString<Tgt>::value>::type
1165 toAppend(const Formatter<containerMode, Args...>& value, Tgt * result) {
1166 value.appendTo(*result);
1169 } // namespace folly