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)
203 // Copy raw string (without format specifiers) to output;
204 // not as simple as we'd like, as we still need to translate "}}" to "}"
205 // and throw if we see any lone "}"
206 auto outputString = [&out] (StringPiece s) {
210 auto q = static_cast<const char*>(memchr(p, '}', end - p));
212 out(StringPiece(p, end));
216 out(StringPiece(p, q));
219 if (p == end || *p != '}') {
220 throw BadFormatArg("folly::format: single '}' in format string");
226 auto p = str_.begin();
227 auto end = str_.end();
230 bool hasDefaultArgIndex = false;
231 bool hasExplicitArgIndex = false;
233 auto q = static_cast<const char*>(memchr(p, '{', end - p));
235 outputString(StringPiece(p, end));
238 outputString(StringPiece(p, q));
242 throw BadFormatArg("folly::format: '}' at end of format string");
247 out(StringPiece(p, 1));
253 q = static_cast<const char*>(memchr(p, '}', end - p));
255 throw BadFormatArg("folly::format: missing ending '}'");
257 FormatArg arg(StringPiece(p, q));
261 auto piece = arg.splitKey<true>(); // empty key component is okay
262 if (containerMode) { // static
264 arg.setNextIntKey(nextArg++);
265 hasDefaultArgIndex = true;
267 arg.setNextKey(piece);
268 hasExplicitArgIndex = true;
272 argIndex = nextArg++;
273 hasDefaultArgIndex = true;
276 argIndex = to<int>(piece);
277 } catch (const std::out_of_range& e) {
278 arg.error("argument index must be integer");
280 arg.enforce(argIndex >= 0, "argument index must be non-negative");
281 hasExplicitArgIndex = true;
285 if (hasDefaultArgIndex && hasExplicitArgIndex) {
287 "folly::format: may not have both default and explicit arg indexes");
290 doFormat(argIndex, arg, out);
294 template <class Derived, bool containerMode, class... Args>
295 void writeTo(FILE* fp,
296 const BaseFormatter<Derived, containerMode, Args...>& formatter) {
297 auto writer = [fp] (StringPiece sp) {
298 size_t n = fwrite(sp.data(), 1, sp.size(), fp);
300 throwSystemError("Formatter writeTo", "fwrite failed");
306 namespace format_value {
308 template <class FormatCallback>
309 void formatString(StringPiece val, FormatArg& arg, FormatCallback& cb) {
310 if (arg.width != FormatArg::kDefaultWidth && arg.width < 0) {
311 throw BadFormatArg("folly::format: invalid width");
313 if (arg.precision != FormatArg::kDefaultPrecision && arg.precision < 0) {
314 throw BadFormatArg("folly::format: invalid precision");
317 // XXX: clang should be smart enough to not need the two static_cast<size_t>
318 // uses below given the above checks. If clang ever becomes that smart, we
319 // should remove the otherwise unnecessary warts.
321 if (arg.precision != FormatArg::kDefaultPrecision &&
322 val.size() > static_cast<size_t>(arg.precision)) {
323 val.reset(val.data(), arg.precision);
326 constexpr int padBufSize = 128;
327 char padBuf[padBufSize];
329 // Output padding, no more than padBufSize at once
330 auto pad = [&padBuf, &cb, padBufSize] (int chars) {
332 int n = std::min(chars, padBufSize);
333 cb(StringPiece(padBuf, n));
338 int padRemaining = 0;
339 if (arg.width != FormatArg::kDefaultWidth &&
340 val.size() < static_cast<size_t>(arg.width)) {
341 char fill = arg.fill == FormatArg::kDefaultFill ? ' ' : arg.fill;
342 int padChars = static_cast<int> (arg.width - val.size());
343 memset(padBuf, fill, std::min(padBufSize, padChars));
346 case FormatArg::Align::DEFAULT:
347 case FormatArg::Align::LEFT:
348 padRemaining = padChars;
350 case FormatArg::Align::CENTER:
352 padRemaining = padChars - padChars / 2;
354 case FormatArg::Align::RIGHT:
355 case FormatArg::Align::PAD_AFTER_SIGN:
371 template <class FormatCallback>
372 void formatNumber(StringPiece val, int prefixLen, FormatArg& arg,
373 FormatCallback& cb) {
374 // precision means something different for numbers
375 arg.precision = FormatArg::kDefaultPrecision;
376 if (arg.align == FormatArg::Align::DEFAULT) {
377 arg.align = FormatArg::Align::RIGHT;
378 } else if (prefixLen && arg.align == FormatArg::Align::PAD_AFTER_SIGN) {
379 // Split off the prefix, then do any padding if necessary
380 cb(val.subpiece(0, prefixLen));
381 val.advance(prefixLen);
382 arg.width = std::max(arg.width - prefixLen, 0);
384 format_value::formatString(val, arg, cb);
387 template <class FormatCallback,
391 void formatFormatter(
392 const BaseFormatter<Derived, containerMode, Args...>& formatter,
394 FormatCallback& cb) {
395 if (arg.width == FormatArg::kDefaultWidth &&
396 arg.precision == FormatArg::kDefaultPrecision) {
399 } else if (arg.align != FormatArg::Align::LEFT &&
400 arg.align != FormatArg::Align::DEFAULT) {
401 // We can only avoid creating a temporary string if we align left,
402 // as we'd need to know the size beforehand otherwise
403 format_value::formatString(formatter.fbstr(), arg, cb);
405 auto fn = [&arg, &cb] (StringPiece sp) mutable {
406 int sz = static_cast<int>(sp.size());
407 if (arg.precision != FormatArg::kDefaultPrecision) {
408 sz = std::min(arg.precision, sz);
409 sp.reset(sp.data(), sz);
414 if (arg.width != FormatArg::kDefaultWidth) {
415 arg.width = std::max(arg.width - sz, 0);
420 if (arg.width != FormatArg::kDefaultWidth && arg.width != 0) {
421 // Rely on formatString to do appropriate padding
422 format_value::formatString(StringPiece(), arg, cb);
427 } // namespace format_value
429 // Definitions for default FormatValue classes
431 // Integral types (except bool)
434 T, typename std::enable_if<
435 std::is_integral<T>::value &&
436 !std::is_same<T, bool>::value>::type>
439 explicit FormatValue(T val) : val_(val) { }
440 template <class FormatCallback>
441 void format(FormatArg& arg, FormatCallback& cb) const {
442 arg.validate(FormatArg::Type::INTEGER);
446 template <class FormatCallback>
447 void doFormat(FormatArg& arg, FormatCallback& cb) const {
448 char presentation = arg.presentation;
449 if (presentation == FormatArg::kDefaultPresentation) {
450 presentation = std::is_same<T, char>::value ? 'c' : 'd';
453 // Do all work as unsigned, we'll add the prefix ('0' or '0x' if necessary)
454 // and sign ourselves.
455 typedef typename std::make_unsigned<T>::type UT;
458 if (std::is_signed<T>::value) {
459 if (folly::is_negative(val_)) {
460 uval = static_cast<UT>(-val_);
463 uval = static_cast<UT>(val_);
465 case FormatArg::Sign::PLUS_OR_MINUS:
468 case FormatArg::Sign::SPACE_OR_MINUS:
480 arg.enforce(arg.sign == FormatArg::Sign::DEFAULT,
481 "sign specifications not allowed for unsigned values");
485 // #x: 0x prefix + 16 bytes = 18 bytes
486 // #o: 0 prefix + 22 bytes = 23 bytes
487 // #b: 0b prefix + 64 bytes = 65 bytes
488 // ,d: 26 bytes (including thousands separators!)
490 // + 3 for sign and prefix shenanigans (see below)
491 constexpr size_t valBufSize = 69;
492 char valBuf[valBufSize];
493 char* valBufBegin = nullptr;
494 char* valBufEnd = nullptr;
497 auto useSprintf = [&] (const char* format) mutable {
498 valBufBegin = valBuf + 3; // room for sign and base prefix
499 valBufEnd = valBufBegin + sprintf(valBufBegin, format,
500 static_cast<uintmax_t>(uval));
505 switch (presentation) {
506 case 'n': // TODO(tudorb): locale awareness?
508 arg.enforce(!arg.basePrefix,
509 "base prefix not allowed with '", presentation,
511 if (arg.thousandsSeparator) {
514 // Use uintToBuffer, faster than sprintf
515 valBufBegin = valBuf + 3;
516 valBufEnd = valBufBegin + uint64ToBufferUnsafe(uval, valBufBegin);
520 arg.enforce(!arg.basePrefix,
521 "base prefix not allowed with '", presentation,
523 arg.enforce(!arg.thousandsSeparator,
524 "thousands separator (',') not allowed with '",
525 presentation, "' specifier");
526 valBufBegin = valBuf + 3;
527 *valBufBegin = static_cast<char>(uval);
528 valBufEnd = valBufBegin + 1;
532 arg.enforce(!arg.thousandsSeparator,
533 "thousands separator (',') not allowed with '",
534 presentation, "' specifier");
535 valBufEnd = valBuf + valBufSize - 1;
536 valBufBegin = valBuf + detail::uintToOctal(valBuf, valBufSize - 1, uval);
537 if (arg.basePrefix) {
538 *--valBufBegin = '0';
543 arg.enforce(!arg.thousandsSeparator,
544 "thousands separator (',') not allowed with '",
545 presentation, "' specifier");
546 valBufEnd = valBuf + valBufSize - 1;
547 valBufBegin = valBuf + detail::uintToHexLower(valBuf, valBufSize - 1,
549 if (arg.basePrefix) {
550 *--valBufBegin = 'x';
551 *--valBufBegin = '0';
556 arg.enforce(!arg.thousandsSeparator,
557 "thousands separator (',') not allowed with '",
558 presentation, "' specifier");
559 valBufEnd = valBuf + valBufSize - 1;
560 valBufBegin = valBuf + detail::uintToHexUpper(valBuf, valBufSize - 1,
562 if (arg.basePrefix) {
563 *--valBufBegin = 'X';
564 *--valBufBegin = '0';
570 arg.enforce(!arg.thousandsSeparator,
571 "thousands separator (',') not allowed with '",
572 presentation, "' specifier");
573 valBufEnd = valBuf + valBufSize - 1;
574 valBufBegin = valBuf + detail::uintToBinary(valBuf, valBufSize - 1,
576 if (arg.basePrefix) {
577 *--valBufBegin = presentation; // 0b or 0B
578 *--valBufBegin = '0';
583 arg.error("invalid specifier '", presentation, "'");
587 *--valBufBegin = sign;
591 format_value::formatNumber(StringPiece(valBufBegin, valBufEnd), prefixLen,
601 class FormatValue<bool> {
603 explicit FormatValue(bool val) : val_(val) { }
605 template <class FormatCallback>
606 void format(FormatArg& arg, FormatCallback& cb) const {
607 if (arg.presentation == FormatArg::kDefaultPresentation) {
608 arg.validate(FormatArg::Type::OTHER);
609 format_value::formatString(val_ ? "true" : "false", arg, cb);
611 FormatValue<int>(val_).format(arg, cb);
621 class FormatValue<double> {
623 explicit FormatValue(double val) : val_(val) { }
625 template <class FormatCallback>
626 void format(FormatArg& arg, FormatCallback& cb) const {
627 using ::double_conversion::DoubleToStringConverter;
628 using ::double_conversion::StringBuilder;
630 arg.validate(FormatArg::Type::FLOAT);
632 if (arg.presentation == FormatArg::kDefaultPresentation) {
633 arg.presentation = 'g';
636 const char* infinitySymbol = isupper(arg.presentation) ? "INF" : "inf";
637 const char* nanSymbol = isupper(arg.presentation) ? "NAN" : "nan";
638 char exponentSymbol = isupper(arg.presentation) ? 'E' : 'e';
640 if (arg.precision == FormatArg::kDefaultPrecision) {
644 // 2+: for null terminator and optional sign shenanigans.
645 char buf[2 + std::max({
646 (2 + DoubleToStringConverter::kMaxFixedDigitsBeforePoint +
647 DoubleToStringConverter::kMaxFixedDigitsAfterPoint),
648 (8 + DoubleToStringConverter::kMaxExponentialDigits),
649 (7 + DoubleToStringConverter::kMaxPrecisionDigits)})];
650 StringBuilder builder(buf + 1, static_cast<int> (sizeof(buf) - 1));
654 case FormatArg::Sign::PLUS_OR_MINUS:
657 case FormatArg::Sign::SPACE_OR_MINUS:
666 DoubleToStringConverter::EMIT_POSITIVE_EXPONENT_SIGN |
667 (arg.trailingDot ? DoubleToStringConverter::EMIT_TRAILING_DECIMAL_POINT
671 switch (arg.presentation) {
678 DoubleToStringConverter::kMaxFixedDigitsAfterPoint) {
679 arg.precision = DoubleToStringConverter::kMaxFixedDigitsAfterPoint;
681 DoubleToStringConverter conv(flags,
689 arg.enforce(conv.ToFixed(val, arg.precision, &builder),
690 "fixed double conversion failed");
696 if (arg.precision > DoubleToStringConverter::kMaxExponentialDigits) {
697 arg.precision = DoubleToStringConverter::kMaxExponentialDigits;
700 DoubleToStringConverter conv(flags,
708 arg.enforce(conv.ToExponential(val, arg.precision, &builder));
711 case 'n': // should be locale-aware, but isn't
715 if (arg.precision < DoubleToStringConverter::kMinPrecisionDigits) {
716 arg.precision = DoubleToStringConverter::kMinPrecisionDigits;
717 } else if (arg.precision >
718 DoubleToStringConverter::kMaxPrecisionDigits) {
719 arg.precision = DoubleToStringConverter::kMaxPrecisionDigits;
721 DoubleToStringConverter conv(flags,
729 arg.enforce(conv.ToShortest(val, &builder));
733 arg.error("invalid specifier '", arg.presentation, "'");
736 int len = builder.position();
740 // Add '+' or ' ' sign if needed
742 // anything that's neither negative nor nan
744 if (plusSign && (*p != '-' && *p != 'n' && *p != 'N')) {
748 } else if (*p == '-') {
752 format_value::formatNumber(StringPiece(p, len), prefixLen, arg, cb);
759 // float (defer to double)
761 class FormatValue<float> {
763 explicit FormatValue(float val) : val_(val) { }
765 template <class FormatCallback>
766 void format(FormatArg& arg, FormatCallback& cb) const {
767 FormatValue<double>(val_).format(arg, cb);
774 // Sring-y types (implicitly convertible to StringPiece, except char*)
777 T, typename std::enable_if<
778 (!std::is_pointer<T>::value ||
779 !std::is_same<char, typename std::decay<
780 typename std::remove_pointer<T>::type>::type>::value) &&
781 std::is_convertible<T, StringPiece>::value>::type>
784 explicit FormatValue(StringPiece val) : val_(val) { }
786 template <class FormatCallback>
787 void format(FormatArg& arg, FormatCallback& cb) const {
788 if (arg.keyEmpty()) {
789 arg.validate(FormatArg::Type::OTHER);
790 arg.enforce(arg.presentation == FormatArg::kDefaultPresentation ||
791 arg.presentation == 's',
792 "invalid specifier '", arg.presentation, "'");
793 format_value::formatString(val_, arg, cb);
795 FormatValue<char>(val_.at(arg.splitIntKey())).format(arg, cb);
805 class FormatValue<std::nullptr_t> {
807 explicit FormatValue(std::nullptr_t) { }
809 template <class FormatCallback>
810 void format(FormatArg& arg, FormatCallback& cb) const {
811 arg.validate(FormatArg::Type::OTHER);
812 arg.enforce(arg.presentation == FormatArg::kDefaultPresentation,
813 "invalid specifier '", arg.presentation, "'");
814 format_value::formatString("(null)", arg, cb);
818 // Partial specialization of FormatValue for char*
822 typename std::enable_if<
823 std::is_same<char, 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()) {
832 FormatValue<std::nullptr_t>(nullptr).format(arg, cb);
834 FormatValue<StringPiece>(val_).format(arg, cb);
837 FormatValue<typename std::decay<T>::type>(
838 val_[arg.splitIntKey()]).format(arg, cb);
846 // Partial specialization of FormatValue for void*
850 typename std::enable_if<
851 std::is_same<void, typename std::decay<T>::type>::value>::type>
854 explicit FormatValue(T* val) : val_(val) { }
856 template <class FormatCallback>
857 void format(FormatArg& arg, FormatCallback& cb) const {
859 FormatValue<std::nullptr_t>(nullptr).format(arg, cb);
861 // Print as a pointer, in hex.
862 arg.validate(FormatArg::Type::OTHER);
863 arg.enforce(arg.presentation == FormatArg::kDefaultPresentation,
864 "invalid specifier '", arg.presentation, "'");
865 arg.basePrefix = true;
866 arg.presentation = 'x';
867 if (arg.align == FormatArg::Align::DEFAULT) {
868 arg.align = FormatArg::Align::LEFT;
870 FormatValue<uintptr_t>(
871 reinterpret_cast<uintptr_t>(val_)).doFormat(arg, cb);
879 template <class T, class = void>
880 class TryFormatValue {
882 template <class FormatCallback>
883 static void formatOrFail(T& value, FormatArg& arg, FormatCallback& cb) {
884 arg.error("No formatter available for this type");
889 class TryFormatValue<
891 typename std::enable_if<
892 0 < sizeof(FormatValue<typename std::decay<T>::type>)>::type>
895 template <class FormatCallback>
896 static void formatOrFail(T& value, FormatArg& arg, FormatCallback& cb) {
897 FormatValue<typename std::decay<T>::type>(value).format(arg, cb);
901 // Partial specialization of FormatValue for other pointers
905 typename std::enable_if<
906 !std::is_same<char, typename std::decay<T>::type>::value &&
907 !std::is_same<void, typename std::decay<T>::type>::value>::type>
910 explicit FormatValue(T* val) : val_(val) { }
912 template <class FormatCallback>
913 void format(FormatArg& arg, FormatCallback& cb) const {
914 if (arg.keyEmpty()) {
915 FormatValue<void*>((void*)val_).format(arg, cb);
917 TryFormatValue<T>::formatOrFail(val_[arg.splitIntKey()], arg, cb);
926 // Shortcut, so we don't have to use enable_if everywhere
927 struct FormatTraitsBase {
928 typedef void enabled;
931 // Traits that define enabled, value_type, and at() for anything
932 // indexable with integral keys: pointers, arrays, vectors, and maps
933 // with integral keys
934 template <class T, class Enable=void> struct IndexableTraits;
936 // Base class for sequences (vectors, deques)
938 struct IndexableTraitsSeq : public FormatTraitsBase {
939 typedef C container_type;
940 typedef typename C::value_type value_type;
941 static const value_type& at(const C& c, int idx) {
945 static const value_type& at(const C& c, int idx,
946 const value_type& dflt) {
947 return (idx >= 0 && size_t(idx) < c.size()) ? c.at(idx) : dflt;
951 // Base class for associative types (maps)
953 struct IndexableTraitsAssoc : public FormatTraitsBase {
954 typedef typename C::value_type::second_type value_type;
955 static const value_type& at(const C& c, int idx) {
956 return c.at(static_cast<typename C::key_type>(idx));
958 static const value_type& at(const C& c, int idx,
959 const value_type& dflt) {
960 auto pos = c.find(static_cast<typename C::key_type>(idx));
961 return pos != c.end() ? pos->second : dflt;
966 template <class T, size_t N>
967 struct IndexableTraits<std::array<T, N>>
968 : public IndexableTraitsSeq<std::array<T, N>> {
972 template <class T, class A>
973 struct IndexableTraits<std::vector<T, A>>
974 : public IndexableTraitsSeq<std::vector<T, A>> {
978 template <class T, class A>
979 struct IndexableTraits<std::deque<T, A>>
980 : public IndexableTraitsSeq<std::deque<T, A>> {
984 template <class T, class A>
985 struct IndexableTraits<fbvector<T, A>>
986 : public IndexableTraitsSeq<fbvector<T, A>> {
990 template <class T, size_t M, class A, class B, class C>
991 struct IndexableTraits<small_vector<T, M, A, B, C>>
992 : public IndexableTraitsSeq<small_vector<T, M, A, B, C>> {
995 // std::map with integral keys
996 template <class K, class T, class C, class A>
997 struct IndexableTraits<
998 std::map<K, T, C, A>,
999 typename std::enable_if<std::is_integral<K>::value>::type>
1000 : public IndexableTraitsAssoc<std::map<K, T, C, A>> {
1003 // std::unordered_map with integral keys
1004 template <class K, class T, class H, class E, class A>
1005 struct IndexableTraits<
1006 std::unordered_map<K, T, H, E, A>,
1007 typename std::enable_if<std::is_integral<K>::value>::type>
1008 : public IndexableTraitsAssoc<std::unordered_map<K, T, H, E, A>> {
1011 } // namespace detail
1013 // Partial specialization of FormatValue for integer-indexable containers
1017 typename detail::IndexableTraits<T>::enabled> {
1019 explicit FormatValue(const T& val) : val_(val) { }
1021 template <class FormatCallback>
1022 void format(FormatArg& arg, FormatCallback& cb) const {
1023 FormatValue<typename std::decay<
1024 typename detail::IndexableTraits<T>::value_type>::type>(
1025 detail::IndexableTraits<T>::at(
1026 val_, arg.splitIntKey())).format(arg, cb);
1033 template <class Container, class Value>
1035 detail::DefaultValueWrapper<Container, Value>,
1036 typename detail::IndexableTraits<Container>::enabled> {
1038 explicit FormatValue(const detail::DefaultValueWrapper<Container, Value>& val)
1041 template <class FormatCallback>
1042 void format(FormatArg& arg, FormatCallback& cb) const {
1043 FormatValue<typename std::decay<
1044 typename detail::IndexableTraits<Container>::value_type>::type>(
1045 detail::IndexableTraits<Container>::at(
1048 val_.defaultValue)).format(arg, cb);
1052 const detail::DefaultValueWrapper<Container, Value>& val_;
1057 // Define enabled, key_type, convert from StringPiece to the key types
1059 template <class T> struct KeyFromStringPiece;
1063 struct KeyFromStringPiece<std::string> : public FormatTraitsBase {
1064 typedef std::string key_type;
1065 static std::string convert(StringPiece s) {
1066 return s.toString();
1068 typedef void enabled;
1073 struct KeyFromStringPiece<fbstring> : public FormatTraitsBase {
1074 typedef fbstring key_type;
1075 static fbstring convert(StringPiece s) {
1076 return s.toFbstring();
1082 struct KeyFromStringPiece<StringPiece> : public FormatTraitsBase {
1083 typedef StringPiece key_type;
1084 static StringPiece convert(StringPiece s) {
1089 // Base class for associative types keyed by strings
1090 template <class T> struct KeyableTraitsAssoc : public FormatTraitsBase {
1091 typedef typename T::key_type key_type;
1092 typedef typename T::value_type::second_type value_type;
1093 static const value_type& at(const T& map, StringPiece key) {
1094 return map.at(KeyFromStringPiece<key_type>::convert(key));
1096 static const value_type& at(const T& map, StringPiece key,
1097 const value_type& dflt) {
1098 auto pos = map.find(KeyFromStringPiece<key_type>::convert(key));
1099 return pos != map.end() ? pos->second : dflt;
1103 // Define enabled, key_type, value_type, at() for supported string-keyed
1105 template <class T, class Enabled=void> struct KeyableTraits;
1107 // std::map with string key
1108 template <class K, class T, class C, class A>
1109 struct KeyableTraits<
1110 std::map<K, T, C, A>,
1111 typename KeyFromStringPiece<K>::enabled>
1112 : public KeyableTraitsAssoc<std::map<K, T, C, A>> {
1115 // std::unordered_map with string key
1116 template <class K, class T, class H, class E, class A>
1117 struct KeyableTraits<
1118 std::unordered_map<K, T, H, E, A>,
1119 typename KeyFromStringPiece<K>::enabled>
1120 : public KeyableTraitsAssoc<std::unordered_map<K, T, H, E, A>> {
1123 } // namespace detail
1125 // Partial specialization of FormatValue for string-keyed containers
1129 typename detail::KeyableTraits<T>::enabled> {
1131 explicit FormatValue(const T& val) : val_(val) { }
1133 template <class FormatCallback>
1134 void format(FormatArg& arg, FormatCallback& cb) const {
1135 FormatValue<typename std::decay<
1136 typename detail::KeyableTraits<T>::value_type>::type>(
1137 detail::KeyableTraits<T>::at(
1138 val_, arg.splitKey())).format(arg, cb);
1145 template <class Container, class Value>
1147 detail::DefaultValueWrapper<Container, Value>,
1148 typename detail::KeyableTraits<Container>::enabled> {
1150 explicit FormatValue(const detail::DefaultValueWrapper<Container, Value>& val)
1153 template <class FormatCallback>
1154 void format(FormatArg& arg, FormatCallback& cb) const {
1155 FormatValue<typename std::decay<
1156 typename detail::KeyableTraits<Container>::value_type>::type>(
1157 detail::KeyableTraits<Container>::at(
1160 val_.defaultValue)).format(arg, cb);
1164 const detail::DefaultValueWrapper<Container, Value>& val_;
1167 // Partial specialization of FormatValue for pairs
1168 template <class A, class B>
1169 class FormatValue<std::pair<A, B>> {
1171 explicit FormatValue(const std::pair<A, B>& val) : val_(val) { }
1173 template <class FormatCallback>
1174 void format(FormatArg& arg, FormatCallback& cb) const {
1175 int key = arg.splitIntKey();
1178 FormatValue<typename std::decay<A>::type>(val_.first).format(arg, cb);
1181 FormatValue<typename std::decay<B>::type>(val_.second).format(arg, cb);
1184 arg.error("invalid index for pair");
1189 const std::pair<A, B>& val_;
1192 // Partial specialization of FormatValue for tuples
1193 template <class... Args>
1194 class FormatValue<std::tuple<Args...>> {
1195 typedef std::tuple<Args...> Tuple;
1197 explicit FormatValue(const Tuple& val) : val_(val) { }
1199 template <class FormatCallback>
1200 void format(FormatArg& arg, FormatCallback& cb) const {
1201 int key = arg.splitIntKey();
1202 arg.enforce(key >= 0, "tuple index must be non-negative");
1203 doFormat(key, arg, cb);
1207 static constexpr size_t valueCount = std::tuple_size<Tuple>::value;
1209 template <size_t K, class Callback>
1210 typename std::enable_if<K == valueCount>::type
1211 doFormatFrom(size_t i, FormatArg& arg, Callback& cb) const {
1212 arg.enforce("tuple index out of range, max=", i);
1215 template <size_t K, class Callback>
1216 typename std::enable_if<(K < valueCount)>::type
1217 doFormatFrom(size_t i, FormatArg& arg, Callback& cb) const {
1219 FormatValue<typename std::decay<
1220 typename std::tuple_element<K, Tuple>::type>::type>(
1221 std::get<K>(val_)).format(arg, cb);
1223 doFormatFrom<K+1>(i, arg, cb);
1227 template <class Callback>
1228 void doFormat(size_t i, FormatArg& arg, Callback& cb) const {
1229 return doFormatFrom<0>(i, arg, cb);
1235 // Partial specialization of FormatValue for nested Formatters
1236 template <bool containerMode, class... Args,
1237 template <bool, class...> class F>
1238 class FormatValue<F<containerMode, Args...>,
1239 typename std::enable_if<detail::IsFormatter<
1240 F<containerMode, Args...>>::value>::type> {
1241 typedef typename F<containerMode, Args...>::BaseType FormatterValue;
1244 explicit FormatValue(const FormatterValue& f) : f_(f) { }
1246 template <class FormatCallback>
1247 void format(FormatArg& arg, FormatCallback& cb) const {
1248 format_value::formatFormatter(f_, arg, cb);
1251 const FormatterValue& f_;
1255 * Formatter objects can be appended to strings, and therefore they're
1256 * compatible with folly::toAppend and folly::to.
1258 template <class Tgt, class Derived, bool containerMode, class... Args>
1259 typename std::enable_if<IsSomeString<Tgt>::value>::type toAppend(
1260 const BaseFormatter<Derived, containerMode, Args...>& value, Tgt* result) {
1261 value.appendTo(*result);
1264 } // namespace folly
1266 #pragma GCC diagnostic pop