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>
24 // Ignore -Wformat-nonliteral warnings within this file
25 #pragma GCC diagnostic push
26 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
32 extern const char formatHexUpper[256][2];
33 extern const char formatHexLower[256][2];
34 extern const char formatOctal[512][3];
35 extern const char formatBinary[256][8];
37 const size_t kMaxHexLength = 2 * sizeof(uintmax_t);
38 const size_t kMaxOctalLength = 3 * sizeof(uintmax_t);
39 const size_t kMaxBinaryLength = 8 * sizeof(uintmax_t);
42 * Convert an unsigned to hex, using repr (which maps from each possible
43 * 2-hex-bytes value to the 2-character representation).
45 * Just like folly::detail::uintToBuffer in Conv.h, writes at the *end* of
46 * the supplied buffer and returns the offset of the beginning of the string
47 * from the start of the buffer. The formatted string will be in range
48 * [buf+begin, buf+bufLen).
51 size_t uintToHex(char* buffer, size_t bufLen, Uint v,
52 const char (&repr)[256][2]) {
53 // 'v >>= 7, v >>= 1' is no more than a work around to get rid of shift size
54 // warning when Uint = uint8_t (it's false as v >= 256 implies sizeof(v) > 1).
55 for (; !less_than<unsigned, 256>(v); v >>= 7, v >>= 1) {
58 buffer[bufLen] = repr[b][0];
59 buffer[bufLen + 1] = repr[b][1];
61 buffer[--bufLen] = repr[v][1];
63 buffer[--bufLen] = repr[v][0];
69 * Convert an unsigned to hex, using lower-case letters for the digits
70 * above 9. See the comments for uintToHex.
73 inline size_t uintToHexLower(char* buffer, size_t bufLen, Uint v) {
74 return uintToHex(buffer, bufLen, v, formatHexLower);
78 * Convert an unsigned to hex, using upper-case letters for the digits
79 * above 9. See the comments for uintToHex.
82 inline size_t uintToHexUpper(char* buffer, size_t bufLen, Uint v) {
83 return uintToHex(buffer, bufLen, v, formatHexUpper);
87 * Convert an unsigned to octal.
89 * Just like folly::detail::uintToBuffer in Conv.h, writes at the *end* of
90 * the supplied buffer and returns the offset of the beginning of the string
91 * from the start of the buffer. The formatted string will be in range
92 * [buf+begin, buf+bufLen).
95 size_t uintToOctal(char* buffer, size_t bufLen, Uint v) {
96 auto& repr = formatOctal;
97 // 'v >>= 7, v >>= 2' is no more than a work around to get rid of shift size
98 // warning when Uint = uint8_t (it's false as v >= 512 implies sizeof(v) > 1).
99 for (; !less_than<unsigned, 512>(v); v >>= 7, v >>= 2) {
102 buffer[bufLen] = repr[b][0];
103 buffer[bufLen + 1] = repr[b][1];
104 buffer[bufLen + 2] = repr[b][2];
106 buffer[--bufLen] = repr[v][2];
108 buffer[--bufLen] = repr[v][1];
111 buffer[--bufLen] = repr[v][0];
117 * Convert an unsigned to binary.
119 * Just like folly::detail::uintToBuffer in Conv.h, writes at the *end* of
120 * the supplied buffer and returns the offset of the beginning of the string
121 * from the start of the buffer. The formatted string will be in range
122 * [buf+begin, buf+bufLen).
124 template <class Uint>
125 size_t uintToBinary(char* buffer, size_t bufLen, Uint v) {
126 auto& repr = formatBinary;
128 buffer[--bufLen] = '0';
131 for (; v; v >>= 7, v >>= 1) {
134 memcpy(buffer + bufLen, &(repr[b][0]), 8);
136 while (buffer[bufLen] == '0') {
142 } // namespace detail
144 template <class Derived, bool containerMode, class... Args>
145 BaseFormatter<Derived, containerMode, Args...>::BaseFormatter(StringPiece str,
148 values_(FormatValue<typename std::decay<Args>::type>(
149 std::forward<Args>(args))...) {
150 static_assert(!containerMode || sizeof...(Args) == 1,
151 "Exactly one argument required in container mode");
154 template <class Derived, bool containerMode, class... Args>
155 void BaseFormatter<Derived, containerMode, Args...>::handleFormatStrError()
158 LOG(FATAL) << "folly::format: bad format string \"" << str_ << "\": " <<
159 folly::exceptionStr(std::current_exception());
164 template <class Derived, bool containerMode, class... Args>
165 template <class Output>
166 void BaseFormatter<Derived, containerMode, Args...>::operator()(Output& out)
168 // Catch BadFormatArg and range_error exceptions, and call
169 // handleFormatStrError().
171 // These exception types indicate a problem with the format string. Most
172 // format strings are string literals specified by the programmer. If they
173 // have a problem, this is usually a programmer bug. We want to crash to
174 // ensure that these are found early on during development.
176 // BadFormatArg is thrown by the Format.h code, while range_error is thrown
177 // by Conv.h, which is used in several places in our format string
180 // (Note: This behavior is slightly dangerous. If the Output object throws a
181 // BadFormatArg or a range_error, we will also crash the program, even if it
182 // wasn't an issue with the format string. This seems highly unlikely
183 // though, and none of our current Output objects can throw these errors.)
185 // We also throw out_of_range errors if the format string references an
186 // argument that isn't present (or a key that isn't present in one of the
187 // argument containers). However, at the moment we don't crash on these
188 // errors, as it is likely that the container is dynamic at runtime.
191 } catch (const BadFormatArg& ex) {
192 handleFormatStrError();
193 } catch (const std::range_error& ex) {
194 handleFormatStrError();
198 template <class Derived, bool containerMode, class... Args>
199 template <class Output>
200 void BaseFormatter<Derived, containerMode, Args...>::appendOutput(Output& out)
202 auto p = str_.begin();
203 auto end = str_.end();
205 // Copy raw string (without format specifiers) to output;
206 // not as simple as we'd like, as we still need to translate "}}" to "}"
207 // and throw if we see any lone "}"
208 auto outputString = [&out] (StringPiece s) {
212 auto q = static_cast<const char*>(memchr(p, '}', end - p));
214 out(StringPiece(p, end));
218 out(StringPiece(p, q));
221 if (p == end || *p != '}') {
222 throw BadFormatArg("folly::format: single '}' in format string");
229 bool hasDefaultArgIndex = false;
230 bool hasExplicitArgIndex = false;
232 auto q = static_cast<const char*>(memchr(p, '{', end - p));
234 outputString(StringPiece(p, end));
237 outputString(StringPiece(p, q));
241 throw BadFormatArg("folly::format: '}' at end of format string");
246 out(StringPiece(p, 1));
252 q = static_cast<const char*>(memchr(p, '}', end - p));
254 throw BadFormatArg("folly::format: missing ending '}'");
256 FormatArg arg(StringPiece(p, q));
260 auto piece = arg.splitKey<true>(); // empty key component is okay
261 if (containerMode) { // static
263 arg.setNextIntKey(nextArg++);
264 hasDefaultArgIndex = true;
266 arg.setNextKey(piece);
267 hasExplicitArgIndex = true;
271 argIndex = nextArg++;
272 hasDefaultArgIndex = true;
275 argIndex = to<int>(piece);
276 } catch (const std::out_of_range& e) {
277 arg.error("argument index must be integer");
279 arg.enforce(argIndex >= 0, "argument index must be non-negative");
280 hasExplicitArgIndex = true;
284 if (hasDefaultArgIndex && hasExplicitArgIndex) {
286 "folly::format: may not have both default and explicit arg indexes");
289 doFormat(argIndex, arg, out);
293 template <class Derived, bool containerMode, class... Args>
294 void writeTo(FILE* fp,
295 const BaseFormatter<Derived, containerMode, Args...>& formatter) {
296 auto writer = [fp] (StringPiece sp) {
297 ssize_t n = fwrite(sp.data(), 1, sp.size(), fp);
299 throwSystemError("Formatter writeTo", "fwrite failed");
305 namespace format_value {
307 template <class FormatCallback>
308 void formatString(StringPiece val, FormatArg& arg, FormatCallback& cb) {
309 if (arg.width != FormatArg::kDefaultWidth && arg.width < 0) {
310 throw BadFormatArg("folly::format: invalid width");
312 if (arg.precision != FormatArg::kDefaultPrecision && arg.precision < 0) {
313 throw BadFormatArg("folly::format: invalid precision");
316 // XXX: clang should be smart enough to not need the two static_cast<size_t>
317 // uses below given the above checks. If clang ever becomes that smart, we
318 // should remove the otherwise unnecessary warts.
320 if (arg.precision != FormatArg::kDefaultPrecision &&
321 val.size() > static_cast<size_t>(arg.precision)) {
322 val.reset(val.data(), arg.precision);
325 constexpr int padBufSize = 128;
326 char padBuf[padBufSize];
328 // Output padding, no more than padBufSize at once
329 auto pad = [&padBuf, &cb, padBufSize] (int chars) {
331 int n = std::min(chars, padBufSize);
332 cb(StringPiece(padBuf, n));
337 int padRemaining = 0;
338 if (arg.width != FormatArg::kDefaultWidth &&
339 val.size() < static_cast<size_t>(arg.width)) {
340 char fill = arg.fill == FormatArg::kDefaultFill ? ' ' : arg.fill;
341 int padChars = static_cast<int> (arg.width - val.size());
342 memset(padBuf, fill, std::min(padBufSize, padChars));
345 case FormatArg::Align::DEFAULT:
346 case FormatArg::Align::LEFT:
347 padRemaining = padChars;
349 case FormatArg::Align::CENTER:
351 padRemaining = padChars - padChars / 2;
353 case FormatArg::Align::RIGHT:
354 case FormatArg::Align::PAD_AFTER_SIGN:
370 template <class FormatCallback>
371 void formatNumber(StringPiece val, int prefixLen, FormatArg& arg,
372 FormatCallback& cb) {
373 // precision means something different for numbers
374 arg.precision = FormatArg::kDefaultPrecision;
375 if (arg.align == FormatArg::Align::DEFAULT) {
376 arg.align = FormatArg::Align::RIGHT;
377 } else if (prefixLen && arg.align == FormatArg::Align::PAD_AFTER_SIGN) {
378 // Split off the prefix, then do any padding if necessary
379 cb(val.subpiece(0, prefixLen));
380 val.advance(prefixLen);
381 arg.width = std::max(arg.width - prefixLen, 0);
383 format_value::formatString(val, arg, cb);
386 template <class FormatCallback,
390 void formatFormatter(
391 const BaseFormatter<Derived, containerMode, Args...>& formatter,
393 FormatCallback& cb) {
394 if (arg.width == FormatArg::kDefaultWidth &&
395 arg.precision == FormatArg::kDefaultPrecision) {
398 } else if (arg.align != FormatArg::Align::LEFT &&
399 arg.align != FormatArg::Align::DEFAULT) {
400 // We can only avoid creating a temporary string if we align left,
401 // as we'd need to know the size beforehand otherwise
402 format_value::formatString(formatter.fbstr(), arg, cb);
404 auto fn = [&arg, &cb] (StringPiece sp) mutable {
405 int sz = static_cast<int>(sp.size());
406 if (arg.precision != FormatArg::kDefaultPrecision) {
407 sz = std::min(arg.precision, sz);
408 sp.reset(sp.data(), sz);
413 if (arg.width != FormatArg::kDefaultWidth) {
414 arg.width = std::max(arg.width - sz, 0);
419 if (arg.width != FormatArg::kDefaultWidth && arg.width != 0) {
420 // Rely on formatString to do appropriate padding
421 format_value::formatString(StringPiece(), arg, cb);
426 } // namespace format_value
428 // Definitions for default FormatValue classes
430 // Integral types (except bool)
433 T, typename std::enable_if<
434 std::is_integral<T>::value &&
435 !std::is_same<T, bool>::value>::type>
438 explicit FormatValue(T val) : val_(val) { }
439 template <class FormatCallback>
440 void format(FormatArg& arg, FormatCallback& cb) const {
441 arg.validate(FormatArg::Type::INTEGER);
445 template <class FormatCallback>
446 void doFormat(FormatArg& arg, FormatCallback& cb) const {
447 char presentation = arg.presentation;
448 if (presentation == FormatArg::kDefaultPresentation) {
449 presentation = std::is_same<T, char>::value ? 'c' : 'd';
452 // Do all work as unsigned, we'll add the prefix ('0' or '0x' if necessary)
453 // and sign ourselves.
454 typedef typename std::make_unsigned<T>::type UT;
457 if (std::is_signed<T>::value) {
458 if (folly::is_negative(val_)) {
459 uval = static_cast<UT>(-val_);
462 uval = static_cast<UT>(val_);
464 case FormatArg::Sign::PLUS_OR_MINUS:
467 case FormatArg::Sign::SPACE_OR_MINUS:
479 arg.enforce(arg.sign == FormatArg::Sign::DEFAULT,
480 "sign specifications not allowed for unsigned values");
484 // #x: 0x prefix + 16 bytes = 18 bytes
485 // #o: 0 prefix + 22 bytes = 23 bytes
486 // #b: 0b prefix + 64 bytes = 65 bytes
487 // ,d: 26 bytes (including thousands separators!)
489 // + 3 for sign and prefix shenanigans (see below)
490 constexpr size_t valBufSize = 69;
491 char valBuf[valBufSize];
492 char* valBufBegin = nullptr;
493 char* valBufEnd = nullptr;
496 auto useSprintf = [&] (const char* format) mutable {
497 valBufBegin = valBuf + 3; // room for sign and base prefix
498 valBufEnd = valBufBegin + sprintf(valBufBegin, format,
499 static_cast<uintmax_t>(uval));
504 switch (presentation) {
505 case 'n': // TODO(tudorb): locale awareness?
507 arg.enforce(!arg.basePrefix,
508 "base prefix not allowed with '", presentation,
510 if (arg.thousandsSeparator) {
513 // Use uintToBuffer, faster than sprintf
514 valBufBegin = valBuf + 3;
515 valBufEnd = valBufBegin + uint64ToBufferUnsafe(uval, valBufBegin);
519 arg.enforce(!arg.basePrefix,
520 "base prefix not allowed with '", presentation,
522 arg.enforce(!arg.thousandsSeparator,
523 "thousands separator (',') not allowed with '",
524 presentation, "' specifier");
525 valBufBegin = valBuf + 3;
526 *valBufBegin = static_cast<char>(uval);
527 valBufEnd = valBufBegin + 1;
531 arg.enforce(!arg.thousandsSeparator,
532 "thousands separator (',') not allowed with '",
533 presentation, "' specifier");
534 valBufEnd = valBuf + valBufSize - 1;
535 valBufBegin = valBuf + detail::uintToOctal(valBuf, valBufSize - 1, uval);
536 if (arg.basePrefix) {
537 *--valBufBegin = '0';
542 arg.enforce(!arg.thousandsSeparator,
543 "thousands separator (',') not allowed with '",
544 presentation, "' specifier");
545 valBufEnd = valBuf + valBufSize - 1;
546 valBufBegin = valBuf + detail::uintToHexLower(valBuf, valBufSize - 1,
548 if (arg.basePrefix) {
549 *--valBufBegin = 'x';
550 *--valBufBegin = '0';
555 arg.enforce(!arg.thousandsSeparator,
556 "thousands separator (',') not allowed with '",
557 presentation, "' specifier");
558 valBufEnd = valBuf + valBufSize - 1;
559 valBufBegin = valBuf + detail::uintToHexUpper(valBuf, valBufSize - 1,
561 if (arg.basePrefix) {
562 *--valBufBegin = 'X';
563 *--valBufBegin = '0';
569 arg.enforce(!arg.thousandsSeparator,
570 "thousands separator (',') not allowed with '",
571 presentation, "' specifier");
572 valBufEnd = valBuf + valBufSize - 1;
573 valBufBegin = valBuf + detail::uintToBinary(valBuf, valBufSize - 1,
575 if (arg.basePrefix) {
576 *--valBufBegin = presentation; // 0b or 0B
577 *--valBufBegin = '0';
582 arg.error("invalid specifier '", presentation, "'");
586 *--valBufBegin = sign;
590 format_value::formatNumber(StringPiece(valBufBegin, valBufEnd), prefixLen,
600 class FormatValue<bool> {
602 explicit FormatValue(bool val) : val_(val) { }
604 template <class FormatCallback>
605 void format(FormatArg& arg, FormatCallback& cb) const {
606 if (arg.presentation == FormatArg::kDefaultPresentation) {
607 arg.validate(FormatArg::Type::OTHER);
608 format_value::formatString(val_ ? "true" : "false", arg, cb);
610 FormatValue<int>(val_).format(arg, cb);
620 class FormatValue<double> {
622 explicit FormatValue(double val) : val_(val) { }
624 template <class FormatCallback>
625 void format(FormatArg& arg, FormatCallback& cb) const {
626 using ::double_conversion::DoubleToStringConverter;
627 using ::double_conversion::StringBuilder;
629 arg.validate(FormatArg::Type::FLOAT);
631 if (arg.presentation == FormatArg::kDefaultPresentation) {
632 arg.presentation = 'g';
635 const char* infinitySymbol = isupper(arg.presentation) ? "INF" : "inf";
636 const char* nanSymbol = isupper(arg.presentation) ? "NAN" : "nan";
637 char exponentSymbol = isupper(arg.presentation) ? 'E' : 'e';
639 if (arg.precision == FormatArg::kDefaultPrecision) {
643 // 2+: for null terminator and optional sign shenanigans.
644 char buf[2 + std::max({
645 (2 + DoubleToStringConverter::kMaxFixedDigitsBeforePoint +
646 DoubleToStringConverter::kMaxFixedDigitsAfterPoint),
647 (8 + DoubleToStringConverter::kMaxExponentialDigits),
648 (7 + DoubleToStringConverter::kMaxPrecisionDigits)})];
649 StringBuilder builder(buf + 1, static_cast<int> (sizeof(buf) - 1));
653 case FormatArg::Sign::PLUS_OR_MINUS:
656 case FormatArg::Sign::SPACE_OR_MINUS:
665 DoubleToStringConverter::EMIT_POSITIVE_EXPONENT_SIGN |
666 (arg.trailingDot ? DoubleToStringConverter::EMIT_TRAILING_DECIMAL_POINT
670 switch (arg.presentation) {
677 DoubleToStringConverter::kMaxFixedDigitsAfterPoint) {
678 arg.precision = DoubleToStringConverter::kMaxFixedDigitsAfterPoint;
680 DoubleToStringConverter conv(flags,
688 arg.enforce(conv.ToFixed(val, arg.precision, &builder),
689 "fixed double conversion failed");
695 if (arg.precision > DoubleToStringConverter::kMaxExponentialDigits) {
696 arg.precision = DoubleToStringConverter::kMaxExponentialDigits;
699 DoubleToStringConverter conv(flags,
707 arg.enforce(conv.ToExponential(val, arg.precision, &builder));
710 case 'n': // should be locale-aware, but isn't
714 if (arg.precision < DoubleToStringConverter::kMinPrecisionDigits) {
715 arg.precision = DoubleToStringConverter::kMinPrecisionDigits;
716 } else if (arg.precision >
717 DoubleToStringConverter::kMaxPrecisionDigits) {
718 arg.precision = DoubleToStringConverter::kMaxPrecisionDigits;
720 DoubleToStringConverter conv(flags,
728 arg.enforce(conv.ToShortest(val, &builder));
732 arg.error("invalid specifier '", arg.presentation, "'");
735 int len = builder.position();
739 // Add '+' or ' ' sign if needed
741 // anything that's neither negative nor nan
743 if (plusSign && (*p != '-' && *p != 'n' && *p != 'N')) {
747 } else if (*p == '-') {
751 format_value::formatNumber(StringPiece(p, len), prefixLen, arg, cb);
758 // float (defer to double)
760 class FormatValue<float> {
762 explicit FormatValue(float val) : val_(val) { }
764 template <class FormatCallback>
765 void format(FormatArg& arg, FormatCallback& cb) const {
766 FormatValue<double>(val_).format(arg, cb);
773 // Sring-y types (implicitly convertible to StringPiece, except char*)
776 T, typename std::enable_if<
777 (!std::is_pointer<T>::value ||
778 !std::is_same<char, typename std::decay<
779 typename std::remove_pointer<T>::type>::type>::value) &&
780 std::is_convertible<T, StringPiece>::value>::type>
783 explicit FormatValue(StringPiece val) : val_(val) { }
785 template <class FormatCallback>
786 void format(FormatArg& arg, FormatCallback& cb) const {
787 if (arg.keyEmpty()) {
788 arg.validate(FormatArg::Type::OTHER);
789 arg.enforce(arg.presentation == FormatArg::kDefaultPresentation ||
790 arg.presentation == 's',
791 "invalid specifier '", arg.presentation, "'");
792 format_value::formatString(val_, arg, cb);
794 FormatValue<char>(val_.at(arg.splitIntKey())).format(arg, cb);
804 class FormatValue<std::nullptr_t> {
806 explicit FormatValue(std::nullptr_t) { }
808 template <class FormatCallback>
809 void format(FormatArg& arg, FormatCallback& cb) const {
810 arg.validate(FormatArg::Type::OTHER);
811 arg.enforce(arg.presentation == FormatArg::kDefaultPresentation,
812 "invalid specifier '", arg.presentation, "'");
813 format_value::formatString("(null)", arg, cb);
817 // Partial specialization of FormatValue for char*
821 typename std::enable_if<
822 std::is_same<char, typename std::decay<T>::type>::value>::type>
825 explicit FormatValue(T* val) : val_(val) { }
827 template <class FormatCallback>
828 void format(FormatArg& arg, FormatCallback& cb) const {
829 if (arg.keyEmpty()) {
831 FormatValue<std::nullptr_t>(nullptr).format(arg, cb);
833 FormatValue<StringPiece>(val_).format(arg, cb);
836 FormatValue<typename std::decay<T>::type>(
837 val_[arg.splitIntKey()]).format(arg, cb);
845 // Partial specialization of FormatValue for void*
849 typename std::enable_if<
850 std::is_same<void, typename std::decay<T>::type>::value>::type>
853 explicit FormatValue(T* val) : val_(val) { }
855 template <class FormatCallback>
856 void format(FormatArg& arg, FormatCallback& cb) const {
858 FormatValue<std::nullptr_t>(nullptr).format(arg, cb);
860 // Print as a pointer, in hex.
861 arg.validate(FormatArg::Type::OTHER);
862 arg.enforce(arg.presentation == FormatArg::kDefaultPresentation,
863 "invalid specifier '", arg.presentation, "'");
864 arg.basePrefix = true;
865 arg.presentation = 'x';
866 if (arg.align == FormatArg::Align::DEFAULT) {
867 arg.align = FormatArg::Align::LEFT;
869 FormatValue<uintptr_t>(
870 reinterpret_cast<uintptr_t>(val_)).doFormat(arg, cb);
878 template <class T, class = void>
879 class TryFormatValue {
881 template <class FormatCallback>
882 static void formatOrFail(T& value, FormatArg& arg, FormatCallback& cb) {
883 arg.error("No formatter available for this type");
888 class TryFormatValue<
890 typename std::enable_if<
891 0 < sizeof(FormatValue<typename std::decay<T>::type>)>::type>
894 template <class FormatCallback>
895 static void formatOrFail(T& value, FormatArg& arg, FormatCallback& cb) {
896 FormatValue<typename std::decay<T>::type>(value).format(arg, cb);
900 // Partial specialization of FormatValue for other pointers
904 typename std::enable_if<
905 !std::is_same<char, typename std::decay<T>::type>::value &&
906 !std::is_same<void, typename std::decay<T>::type>::value>::type>
909 explicit FormatValue(T* val) : val_(val) { }
911 template <class FormatCallback>
912 void format(FormatArg& arg, FormatCallback& cb) const {
913 if (arg.keyEmpty()) {
914 FormatValue<void*>((void*)val_).format(arg, cb);
916 TryFormatValue<T>::formatOrFail(val_[arg.splitIntKey()], arg, cb);
925 // Shortcut, so we don't have to use enable_if everywhere
926 struct FormatTraitsBase {
927 typedef void enabled;
930 // Traits that define enabled, value_type, and at() for anything
931 // indexable with integral keys: pointers, arrays, vectors, and maps
932 // with integral keys
933 template <class T, class Enable=void> struct IndexableTraits;
935 // Base class for sequences (vectors, deques)
937 struct IndexableTraitsSeq : public FormatTraitsBase {
938 typedef C container_type;
939 typedef typename C::value_type value_type;
940 static const value_type& at(const C& c, int idx) {
944 static const value_type& at(const C& c, int idx,
945 const value_type& dflt) {
946 return (idx >= 0 && idx < c.size()) ? c.at(idx) : dflt;
950 // Base class for associative types (maps)
952 struct IndexableTraitsAssoc : public FormatTraitsBase {
953 typedef typename C::value_type::second_type value_type;
954 static const value_type& at(const C& c, int idx) {
955 return c.at(static_cast<typename C::key_type>(idx));
957 static const value_type& at(const C& c, int idx,
958 const value_type& dflt) {
959 auto pos = c.find(static_cast<typename C::key_type>(idx));
960 return pos != c.end() ? pos->second : dflt;
965 template <class T, size_t N>
966 struct IndexableTraits<std::array<T, N>>
967 : public IndexableTraitsSeq<std::array<T, N>> {
971 template <class T, class A>
972 struct IndexableTraits<std::vector<T, A>>
973 : public IndexableTraitsSeq<std::vector<T, A>> {
977 template <class T, class A>
978 struct IndexableTraits<std::deque<T, A>>
979 : public IndexableTraitsSeq<std::deque<T, A>> {
983 template <class T, class A>
984 struct IndexableTraits<fbvector<T, A>>
985 : public IndexableTraitsSeq<fbvector<T, A>> {
989 template <class T, size_t M, class A, class B, class C>
990 struct IndexableTraits<small_vector<T, M, A, B, C>>
991 : public IndexableTraitsSeq<small_vector<T, M, A, B, C>> {
994 // std::map with integral keys
995 template <class K, class T, class C, class A>
996 struct IndexableTraits<
997 std::map<K, T, C, A>,
998 typename std::enable_if<std::is_integral<K>::value>::type>
999 : public IndexableTraitsAssoc<std::map<K, T, C, A>> {
1002 // std::unordered_map with integral keys
1003 template <class K, class T, class H, class E, class A>
1004 struct IndexableTraits<
1005 std::unordered_map<K, T, H, E, A>,
1006 typename std::enable_if<std::is_integral<K>::value>::type>
1007 : public IndexableTraitsAssoc<std::unordered_map<K, T, H, E, A>> {
1010 } // namespace detail
1012 // Partial specialization of FormatValue for integer-indexable containers
1016 typename detail::IndexableTraits<T>::enabled> {
1018 explicit FormatValue(const T& val) : val_(val) { }
1020 template <class FormatCallback>
1021 void format(FormatArg& arg, FormatCallback& cb) const {
1022 FormatValue<typename std::decay<
1023 typename detail::IndexableTraits<T>::value_type>::type>(
1024 detail::IndexableTraits<T>::at(
1025 val_, arg.splitIntKey())).format(arg, cb);
1032 template <class Container, class Value>
1034 detail::DefaultValueWrapper<Container, Value>,
1035 typename detail::IndexableTraits<Container>::enabled> {
1037 explicit FormatValue(const detail::DefaultValueWrapper<Container, Value>& val)
1040 template <class FormatCallback>
1041 void format(FormatArg& arg, FormatCallback& cb) const {
1042 FormatValue<typename std::decay<
1043 typename detail::IndexableTraits<Container>::value_type>::type>(
1044 detail::IndexableTraits<Container>::at(
1047 val_.defaultValue)).format(arg, cb);
1051 const detail::DefaultValueWrapper<Container, Value>& val_;
1056 // Define enabled, key_type, convert from StringPiece to the key types
1058 template <class T> struct KeyFromStringPiece;
1062 struct KeyFromStringPiece<std::string> : public FormatTraitsBase {
1063 typedef std::string key_type;
1064 static std::string convert(StringPiece s) {
1065 return s.toString();
1067 typedef void enabled;
1072 struct KeyFromStringPiece<fbstring> : public FormatTraitsBase {
1073 typedef fbstring key_type;
1074 static fbstring convert(StringPiece s) {
1075 return s.toFbstring();
1081 struct KeyFromStringPiece<StringPiece> : public FormatTraitsBase {
1082 typedef StringPiece key_type;
1083 static StringPiece convert(StringPiece s) {
1088 // Base class for associative types keyed by strings
1089 template <class T> struct KeyableTraitsAssoc : public FormatTraitsBase {
1090 typedef typename T::key_type key_type;
1091 typedef typename T::value_type::second_type value_type;
1092 static const value_type& at(const T& map, StringPiece key) {
1093 return map.at(KeyFromStringPiece<key_type>::convert(key));
1095 static const value_type& at(const T& map, StringPiece key,
1096 const value_type& dflt) {
1097 auto pos = map.find(KeyFromStringPiece<key_type>::convert(key));
1098 return pos != map.end() ? pos->second : dflt;
1102 // Define enabled, key_type, value_type, at() for supported string-keyed
1104 template <class T, class Enabled=void> struct KeyableTraits;
1106 // std::map with string key
1107 template <class K, class T, class C, class A>
1108 struct KeyableTraits<
1109 std::map<K, T, C, A>,
1110 typename KeyFromStringPiece<K>::enabled>
1111 : public KeyableTraitsAssoc<std::map<K, T, C, A>> {
1114 // std::unordered_map with string key
1115 template <class K, class T, class H, class E, class A>
1116 struct KeyableTraits<
1117 std::unordered_map<K, T, H, E, A>,
1118 typename KeyFromStringPiece<K>::enabled>
1119 : public KeyableTraitsAssoc<std::unordered_map<K, T, H, E, A>> {
1122 } // namespace detail
1124 // Partial specialization of FormatValue for string-keyed containers
1128 typename detail::KeyableTraits<T>::enabled> {
1130 explicit FormatValue(const T& val) : val_(val) { }
1132 template <class FormatCallback>
1133 void format(FormatArg& arg, FormatCallback& cb) const {
1134 FormatValue<typename std::decay<
1135 typename detail::KeyableTraits<T>::value_type>::type>(
1136 detail::KeyableTraits<T>::at(
1137 val_, arg.splitKey())).format(arg, cb);
1144 template <class Container, class Value>
1146 detail::DefaultValueWrapper<Container, Value>,
1147 typename detail::KeyableTraits<Container>::enabled> {
1149 explicit FormatValue(const detail::DefaultValueWrapper<Container, Value>& val)
1152 template <class FormatCallback>
1153 void format(FormatArg& arg, FormatCallback& cb) const {
1154 FormatValue<typename std::decay<
1155 typename detail::KeyableTraits<Container>::value_type>::type>(
1156 detail::KeyableTraits<Container>::at(
1159 val_.defaultValue)).format(arg, cb);
1163 const detail::DefaultValueWrapper<Container, Value>& val_;
1166 // Partial specialization of FormatValue for pairs
1167 template <class A, class B>
1168 class FormatValue<std::pair<A, B>> {
1170 explicit FormatValue(const std::pair<A, B>& val) : val_(val) { }
1172 template <class FormatCallback>
1173 void format(FormatArg& arg, FormatCallback& cb) const {
1174 int key = arg.splitIntKey();
1177 FormatValue<typename std::decay<A>::type>(val_.first).format(arg, cb);
1180 FormatValue<typename std::decay<B>::type>(val_.second).format(arg, cb);
1183 arg.error("invalid index for pair");
1188 const std::pair<A, B>& val_;
1191 // Partial specialization of FormatValue for tuples
1192 template <class... Args>
1193 class FormatValue<std::tuple<Args...>> {
1194 typedef std::tuple<Args...> Tuple;
1196 explicit FormatValue(const Tuple& val) : val_(val) { }
1198 template <class FormatCallback>
1199 void format(FormatArg& arg, FormatCallback& cb) const {
1200 int key = arg.splitIntKey();
1201 arg.enforce(key >= 0, "tuple index must be non-negative");
1202 doFormat(key, arg, cb);
1206 static constexpr size_t valueCount = std::tuple_size<Tuple>::value;
1208 template <size_t K, class Callback>
1209 typename std::enable_if<K == valueCount>::type
1210 doFormatFrom(size_t i, FormatArg& arg, Callback& cb) const {
1211 arg.enforce("tuple index out of range, max=", i);
1214 template <size_t K, class Callback>
1215 typename std::enable_if<(K < valueCount)>::type
1216 doFormatFrom(size_t i, FormatArg& arg, Callback& cb) const {
1218 FormatValue<typename std::decay<
1219 typename std::tuple_element<K, Tuple>::type>::type>(
1220 std::get<K>(val_)).format(arg, cb);
1222 doFormatFrom<K+1>(i, arg, cb);
1226 template <class Callback>
1227 void doFormat(size_t i, FormatArg& arg, Callback& cb) const {
1228 return doFormatFrom<0>(i, arg, cb);
1234 // Partial specialization of FormatValue for nested Formatters
1235 template <bool containerMode, class... Args,
1236 template <bool, class...> class F>
1237 class FormatValue<F<containerMode, Args...>,
1238 typename std::enable_if<detail::IsFormatter<
1239 F<containerMode, Args...>>::value>::type> {
1240 typedef typename F<containerMode, Args...>::BaseType FormatterValue;
1243 explicit FormatValue(const FormatterValue& f) : f_(f) { }
1245 template <class FormatCallback>
1246 void format(FormatArg& arg, FormatCallback& cb) const {
1247 format_value::formatFormatter(f_, arg, cb);
1250 const FormatterValue& f_;
1254 * Formatter objects can be appended to strings, and therefore they're
1255 * compatible with folly::toAppend and folly::to.
1257 template <class Tgt, class Derived, bool containerMode, class... Args>
1258 typename std::enable_if<IsSomeString<Tgt>::value>::type toAppend(
1259 const BaseFormatter<Derived, containerMode, Args...>& value, Tgt* result) {
1260 value.appendTo(*result);
1263 } // namespace folly
1265 #pragma GCC diagnostic pop