2 * Copyright 2016 Facebook, Inc.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 #ifndef FOLLY_FORMAT_H_
18 #error This file may only be included from Format.h.
25 #include <unordered_map>
28 #include <folly/Exception.h>
29 #include <folly/FormatTraits.h>
30 #include <folly/Traits.h>
32 // Ignore -Wformat-nonliteral warnings within this file
33 #pragma GCC diagnostic push
34 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
40 // Updates the end of the buffer after the comma separators have been added.
41 void insertThousandsGroupingUnsafe(char* start_buffer, char** end_buffer);
43 extern const char formatHexUpper[256][2];
44 extern const char formatHexLower[256][2];
45 extern const char formatOctal[512][3];
46 extern const char formatBinary[256][8];
48 const size_t kMaxHexLength = 2 * sizeof(uintmax_t);
49 const size_t kMaxOctalLength = 3 * sizeof(uintmax_t);
50 const size_t kMaxBinaryLength = 8 * sizeof(uintmax_t);
53 * Convert an unsigned to hex, using repr (which maps from each possible
54 * 2-hex-bytes value to the 2-character representation).
56 * Just like folly::detail::uintToBuffer in Conv.h, writes at the *end* of
57 * the supplied buffer and returns the offset of the beginning of the string
58 * from the start of the buffer. The formatted string will be in range
59 * [buf+begin, buf+bufLen).
62 size_t uintToHex(char* buffer, size_t bufLen, Uint v,
63 const char (&repr)[256][2]) {
64 // 'v >>= 7, v >>= 1' is no more than a work around to get rid of shift size
65 // warning when Uint = uint8_t (it's false as v >= 256 implies sizeof(v) > 1).
66 for (; !less_than<unsigned, 256>(v); v >>= 7, v >>= 1) {
69 buffer[bufLen] = repr[b][0];
70 buffer[bufLen + 1] = repr[b][1];
72 buffer[--bufLen] = repr[v][1];
74 buffer[--bufLen] = repr[v][0];
80 * Convert an unsigned to hex, using lower-case letters for the digits
81 * above 9. See the comments for uintToHex.
84 inline size_t uintToHexLower(char* buffer, size_t bufLen, Uint v) {
85 return uintToHex(buffer, bufLen, v, formatHexLower);
89 * Convert an unsigned to hex, using upper-case letters for the digits
90 * above 9. See the comments for uintToHex.
93 inline size_t uintToHexUpper(char* buffer, size_t bufLen, Uint v) {
94 return uintToHex(buffer, bufLen, v, formatHexUpper);
98 * Convert an unsigned to octal.
100 * Just like folly::detail::uintToBuffer in Conv.h, writes at the *end* of
101 * the supplied buffer and returns the offset of the beginning of the string
102 * from the start of the buffer. The formatted string will be in range
103 * [buf+begin, buf+bufLen).
105 template <class Uint>
106 size_t uintToOctal(char* buffer, size_t bufLen, Uint v) {
107 auto& repr = formatOctal;
108 // 'v >>= 7, v >>= 2' is no more than a work around to get rid of shift size
109 // warning when Uint = uint8_t (it's false as v >= 512 implies sizeof(v) > 1).
110 for (; !less_than<unsigned, 512>(v); v >>= 7, v >>= 2) {
113 buffer[bufLen] = repr[b][0];
114 buffer[bufLen + 1] = repr[b][1];
115 buffer[bufLen + 2] = repr[b][2];
117 buffer[--bufLen] = repr[v][2];
119 buffer[--bufLen] = repr[v][1];
122 buffer[--bufLen] = repr[v][0];
128 * Convert an unsigned to binary.
130 * Just like folly::detail::uintToBuffer in Conv.h, writes at the *end* of
131 * the supplied buffer and returns the offset of the beginning of the string
132 * from the start of the buffer. The formatted string will be in range
133 * [buf+begin, buf+bufLen).
135 template <class Uint>
136 size_t uintToBinary(char* buffer, size_t bufLen, Uint v) {
137 auto& repr = formatBinary;
139 buffer[--bufLen] = '0';
142 for (; v; v >>= 7, v >>= 1) {
145 memcpy(buffer + bufLen, &(repr[b][0]), 8);
147 while (buffer[bufLen] == '0') {
153 } // namespace detail
155 template <class Derived, bool containerMode, class... Args>
156 BaseFormatter<Derived, containerMode, Args...>::BaseFormatter(StringPiece str,
159 values_(FormatValue<typename std::decay<Args>::type>(
160 std::forward<Args>(args))...) {
161 static_assert(!containerMode || sizeof...(Args) == 1,
162 "Exactly one argument required in container mode");
165 template <class Derived, bool containerMode, class... Args>
166 template <class Output>
167 void BaseFormatter<Derived, containerMode, Args...>::operator()(Output& out)
169 // Copy raw string (without format specifiers) to output;
170 // not as simple as we'd like, as we still need to translate "}}" to "}"
171 // and throw if we see any lone "}"
172 auto outputString = [&out] (StringPiece s) {
176 auto q = static_cast<const char*>(memchr(p, '}', end - p));
178 out(StringPiece(p, end));
182 out(StringPiece(p, q));
185 if (p == end || *p != '}') {
186 throw BadFormatArg("folly::format: single '}' in format string");
192 auto p = str_.begin();
193 auto end = str_.end();
196 bool hasDefaultArgIndex = false;
197 bool hasExplicitArgIndex = false;
199 auto q = static_cast<const char*>(memchr(p, '{', end - p));
201 outputString(StringPiece(p, end));
204 outputString(StringPiece(p, q));
208 throw BadFormatArg("folly::format: '}' at end of format string");
213 out(StringPiece(p, 1));
219 q = static_cast<const char*>(memchr(p, '}', end - p));
221 throw BadFormatArg("folly::format: missing ending '}'");
223 FormatArg arg(StringPiece(p, q));
227 auto piece = arg.splitKey<true>(); // empty key component is okay
228 if (containerMode) { // static
229 arg.enforce(arg.width != FormatArg::kDynamicWidth,
230 "dynamic field width not supported in vformat()");
232 arg.setNextIntKey(nextArg++);
233 hasDefaultArgIndex = true;
235 arg.setNextKey(piece);
236 hasExplicitArgIndex = true;
240 if (arg.width == FormatArg::kDynamicWidth) {
241 arg.enforce(arg.widthIndex == FormatArg::kNoIndex,
242 "cannot provide width arg index without value arg index");
243 int sizeArg = nextArg++;
244 arg.width = getSizeArg(sizeArg, arg);
247 argIndex = nextArg++;
248 hasDefaultArgIndex = true;
250 if (arg.width == FormatArg::kDynamicWidth) {
251 arg.enforce(arg.widthIndex != FormatArg::kNoIndex,
252 "cannot provide value arg index without width arg index");
253 arg.width = getSizeArg(arg.widthIndex, arg);
257 argIndex = to<int>(piece);
258 } catch (const std::out_of_range& e) {
259 arg.error("argument index must be integer");
261 arg.enforce(argIndex >= 0, "argument index must be non-negative");
262 hasExplicitArgIndex = true;
266 if (hasDefaultArgIndex && hasExplicitArgIndex) {
268 "folly::format: may not have both default and explicit arg indexes");
271 doFormat(argIndex, arg, out);
275 template <class Derived, bool containerMode, class... Args>
276 void writeTo(FILE* fp,
277 const BaseFormatter<Derived, containerMode, Args...>& formatter) {
278 auto writer = [fp] (StringPiece sp) {
279 size_t n = fwrite(sp.data(), 1, sp.size(), fp);
281 throwSystemError("Formatter writeTo", "fwrite failed");
287 namespace format_value {
289 template <class FormatCallback>
290 void formatString(StringPiece val, FormatArg& arg, FormatCallback& cb) {
291 if (arg.width != FormatArg::kDefaultWidth && arg.width < 0) {
292 throw BadFormatArg("folly::format: invalid width");
294 if (arg.precision != FormatArg::kDefaultPrecision && arg.precision < 0) {
295 throw BadFormatArg("folly::format: invalid precision");
298 // XXX: clang should be smart enough to not need the two static_cast<size_t>
299 // uses below given the above checks. If clang ever becomes that smart, we
300 // should remove the otherwise unnecessary warts.
302 if (arg.precision != FormatArg::kDefaultPrecision &&
303 val.size() > static_cast<size_t>(arg.precision)) {
304 val.reset(val.data(), arg.precision);
307 constexpr int padBufSize = 128;
308 char padBuf[padBufSize];
310 // Output padding, no more than padBufSize at once
311 auto pad = [&padBuf, &cb, padBufSize] (int chars) {
313 int n = std::min(chars, padBufSize);
314 cb(StringPiece(padBuf, n));
319 int padRemaining = 0;
320 if (arg.width != FormatArg::kDefaultWidth &&
321 val.size() < static_cast<size_t>(arg.width)) {
322 char fill = arg.fill == FormatArg::kDefaultFill ? ' ' : arg.fill;
323 int padChars = static_cast<int> (arg.width - val.size());
324 memset(padBuf, fill, std::min(padBufSize, padChars));
327 case FormatArg::Align::DEFAULT:
328 case FormatArg::Align::LEFT:
329 padRemaining = padChars;
331 case FormatArg::Align::CENTER:
333 padRemaining = padChars - padChars / 2;
335 case FormatArg::Align::RIGHT:
336 case FormatArg::Align::PAD_AFTER_SIGN:
352 template <class FormatCallback>
353 void formatNumber(StringPiece val, int prefixLen, FormatArg& arg,
354 FormatCallback& cb) {
355 // precision means something different for numbers
356 arg.precision = FormatArg::kDefaultPrecision;
357 if (arg.align == FormatArg::Align::DEFAULT) {
358 arg.align = FormatArg::Align::RIGHT;
359 } else if (prefixLen && arg.align == FormatArg::Align::PAD_AFTER_SIGN) {
360 // Split off the prefix, then do any padding if necessary
361 cb(val.subpiece(0, prefixLen));
362 val.advance(prefixLen);
363 arg.width = std::max(arg.width - prefixLen, 0);
365 format_value::formatString(val, arg, cb);
368 template <class FormatCallback,
372 void formatFormatter(
373 const BaseFormatter<Derived, containerMode, Args...>& formatter,
375 FormatCallback& cb) {
376 if (arg.width == FormatArg::kDefaultWidth &&
377 arg.precision == FormatArg::kDefaultPrecision) {
380 } else if (arg.align != FormatArg::Align::LEFT &&
381 arg.align != FormatArg::Align::DEFAULT) {
382 // We can only avoid creating a temporary string if we align left,
383 // as we'd need to know the size beforehand otherwise
384 format_value::formatString(formatter.fbstr(), arg, cb);
386 auto fn = [&arg, &cb] (StringPiece sp) mutable {
387 int sz = static_cast<int>(sp.size());
388 if (arg.precision != FormatArg::kDefaultPrecision) {
389 sz = std::min(arg.precision, sz);
390 sp.reset(sp.data(), sz);
395 if (arg.width != FormatArg::kDefaultWidth) {
396 arg.width = std::max(arg.width - sz, 0);
401 if (arg.width != FormatArg::kDefaultWidth && arg.width != 0) {
402 // Rely on formatString to do appropriate padding
403 format_value::formatString(StringPiece(), arg, cb);
408 } // namespace format_value
410 // Definitions for default FormatValue classes
412 // Integral types (except bool)
415 T, typename std::enable_if<
416 std::is_integral<T>::value &&
417 !std::is_same<T, bool>::value>::type>
420 explicit FormatValue(T val) : val_(val) { }
426 template <class FormatCallback>
427 void format(FormatArg& arg, FormatCallback& cb) const {
428 arg.validate(FormatArg::Type::INTEGER);
432 template <class FormatCallback>
433 void doFormat(FormatArg& arg, FormatCallback& cb) const {
434 char presentation = arg.presentation;
435 if (presentation == FormatArg::kDefaultPresentation) {
436 presentation = std::is_same<T, char>::value ? 'c' : 'd';
439 // Do all work as unsigned, we'll add the prefix ('0' or '0x' if necessary)
440 // and sign ourselves.
441 typedef typename std::make_unsigned<T>::type UT;
444 if (std::is_signed<T>::value) {
445 if (folly::is_negative(val_)) {
446 uval = static_cast<UT>(-val_);
449 uval = static_cast<UT>(val_);
451 case FormatArg::Sign::PLUS_OR_MINUS:
454 case FormatArg::Sign::SPACE_OR_MINUS:
466 arg.enforce(arg.sign == FormatArg::Sign::DEFAULT,
467 "sign specifications not allowed for unsigned values");
471 // #x: 0x prefix + 16 bytes = 18 bytes
472 // #o: 0 prefix + 22 bytes = 23 bytes
473 // #b: 0b prefix + 64 bytes = 65 bytes
474 // ,d: 26 bytes (including thousands separators!)
476 // + 3 for sign and prefix shenanigans (see below)
477 constexpr size_t valBufSize = 69;
478 char valBuf[valBufSize];
479 char* valBufBegin = nullptr;
480 char* valBufEnd = nullptr;
483 switch (presentation) {
485 arg.enforce(!arg.basePrefix,
486 "base prefix not allowed with '", presentation,
489 arg.enforce(!arg.thousandsSeparator,
490 "cannot use ',' with the '", presentation,
493 valBufBegin = valBuf + 3; // room for sign and base prefix
495 char valBuf2[valBufSize];
496 snprintf(valBuf2, valBufSize, "%ju", static_cast<uintmax_t>(uval));
497 int len = GetNumberFormat(
503 (int)((valBuf + valBufSize) - valBufBegin)
505 #elif defined(__ANDROID__)
506 int len = snprintf(valBufBegin, (valBuf + valBufSize) - valBufBegin,
507 "%" PRIuMAX, static_cast<uintmax_t>(uval));
509 int len = snprintf(valBufBegin, (valBuf + valBufSize) - valBufBegin,
510 "%'ju", static_cast<uintmax_t>(uval));
512 // valBufSize should always be big enough, so this should never
514 assert(len < valBuf + valBufSize - valBufBegin);
515 valBufEnd = valBufBegin + len;
519 arg.enforce(!arg.basePrefix,
520 "base prefix not allowed with '", presentation,
522 valBufBegin = valBuf + 3; // room for sign and base prefix
524 // Use uintToBuffer, faster than sprintf
525 valBufEnd = valBufBegin + uint64ToBufferUnsafe(uval, valBufBegin);
526 if (arg.thousandsSeparator) {
527 detail::insertThousandsGroupingUnsafe(valBufBegin, &valBufEnd);
531 arg.enforce(!arg.basePrefix,
532 "base prefix not allowed with '", presentation,
534 arg.enforce(!arg.thousandsSeparator,
535 "thousands separator (',') not allowed with '",
536 presentation, "' specifier");
537 valBufBegin = valBuf + 3;
538 *valBufBegin = static_cast<char>(uval);
539 valBufEnd = valBufBegin + 1;
543 arg.enforce(!arg.thousandsSeparator,
544 "thousands separator (',') not allowed with '",
545 presentation, "' specifier");
546 valBufEnd = valBuf + valBufSize - 1;
547 valBufBegin = valBuf + detail::uintToOctal(valBuf, valBufSize - 1, uval);
548 if (arg.basePrefix) {
549 *--valBufBegin = '0';
554 arg.enforce(!arg.thousandsSeparator,
555 "thousands separator (',') not allowed with '",
556 presentation, "' specifier");
557 valBufEnd = valBuf + valBufSize - 1;
558 valBufBegin = valBuf + detail::uintToHexLower(valBuf, valBufSize - 1,
560 if (arg.basePrefix) {
561 *--valBufBegin = 'x';
562 *--valBufBegin = '0';
567 arg.enforce(!arg.thousandsSeparator,
568 "thousands separator (',') not allowed with '",
569 presentation, "' specifier");
570 valBufEnd = valBuf + valBufSize - 1;
571 valBufBegin = valBuf + detail::uintToHexUpper(valBuf, valBufSize - 1,
573 if (arg.basePrefix) {
574 *--valBufBegin = 'X';
575 *--valBufBegin = '0';
581 arg.enforce(!arg.thousandsSeparator,
582 "thousands separator (',') not allowed with '",
583 presentation, "' specifier");
584 valBufEnd = valBuf + valBufSize - 1;
585 valBufBegin = valBuf + detail::uintToBinary(valBuf, valBufSize - 1,
587 if (arg.basePrefix) {
588 *--valBufBegin = presentation; // 0b or 0B
589 *--valBufBegin = '0';
594 arg.error("invalid specifier '", presentation, "'");
598 *--valBufBegin = sign;
602 format_value::formatNumber(StringPiece(valBufBegin, valBufEnd), prefixLen,
612 class FormatValue<bool> {
614 explicit FormatValue(bool val) : val_(val) { }
616 template <class FormatCallback>
617 void format(FormatArg& arg, FormatCallback& cb) const {
618 if (arg.presentation == FormatArg::kDefaultPresentation) {
619 arg.validate(FormatArg::Type::OTHER);
620 format_value::formatString(val_ ? "true" : "false", arg, cb);
622 FormatValue<int>(val_).format(arg, cb);
632 class FormatValue<double> {
634 explicit FormatValue(double val) : val_(val) { }
636 template <class FormatCallback>
637 void format(FormatArg& arg, FormatCallback& cb) const {
640 formatHelper(piece, prefixLen, arg);
641 format_value::formatNumber(piece, prefixLen, arg, cb);
645 void formatHelper(fbstring& piece, int& prefixLen, FormatArg& arg) const;
650 // float (defer to double)
652 class FormatValue<float> {
654 explicit FormatValue(float val) : val_(val) { }
656 template <class FormatCallback>
657 void format(FormatArg& arg, FormatCallback& cb) const {
658 FormatValue<double>(val_).format(arg, cb);
665 // Sring-y types (implicitly convertible to StringPiece, except char*)
668 T, typename std::enable_if<
669 (!std::is_pointer<T>::value ||
670 !std::is_same<char, typename std::decay<
671 typename std::remove_pointer<T>::type>::type>::value) &&
672 std::is_convertible<T, StringPiece>::value>::type>
675 explicit FormatValue(StringPiece val) : val_(val) { }
677 template <class FormatCallback>
678 void format(FormatArg& arg, FormatCallback& cb) const {
679 if (arg.keyEmpty()) {
680 arg.validate(FormatArg::Type::OTHER);
681 arg.enforce(arg.presentation == FormatArg::kDefaultPresentation ||
682 arg.presentation == 's',
683 "invalid specifier '", arg.presentation, "'");
684 format_value::formatString(val_, arg, cb);
686 FormatValue<char>(val_.at(arg.splitIntKey())).format(arg, cb);
696 class FormatValue<std::nullptr_t> {
698 explicit FormatValue(std::nullptr_t) { }
700 template <class FormatCallback>
701 void format(FormatArg& arg, FormatCallback& cb) const {
702 arg.validate(FormatArg::Type::OTHER);
703 arg.enforce(arg.presentation == FormatArg::kDefaultPresentation,
704 "invalid specifier '", arg.presentation, "'");
705 format_value::formatString("(null)", arg, cb);
709 // Partial specialization of FormatValue for char*
713 typename std::enable_if<
714 std::is_same<char, typename std::decay<T>::type>::value>::type>
717 explicit FormatValue(T* val) : val_(val) { }
719 template <class FormatCallback>
720 void format(FormatArg& arg, FormatCallback& cb) const {
721 if (arg.keyEmpty()) {
723 FormatValue<std::nullptr_t>(nullptr).format(arg, cb);
725 FormatValue<StringPiece>(val_).format(arg, cb);
728 FormatValue<typename std::decay<T>::type>(
729 val_[arg.splitIntKey()]).format(arg, cb);
737 // Partial specialization of FormatValue for void*
741 typename std::enable_if<
742 std::is_same<void, typename std::decay<T>::type>::value>::type>
745 explicit FormatValue(T* val) : val_(val) { }
747 template <class FormatCallback>
748 void format(FormatArg& arg, FormatCallback& cb) const {
750 FormatValue<std::nullptr_t>(nullptr).format(arg, cb);
752 // Print as a pointer, in hex.
753 arg.validate(FormatArg::Type::OTHER);
754 arg.enforce(arg.presentation == FormatArg::kDefaultPresentation,
755 "invalid specifier '", arg.presentation, "'");
756 arg.basePrefix = true;
757 arg.presentation = 'x';
758 if (arg.align == FormatArg::Align::DEFAULT) {
759 arg.align = FormatArg::Align::LEFT;
761 FormatValue<uintptr_t>(
762 reinterpret_cast<uintptr_t>(val_)).doFormat(arg, cb);
770 template <class T, class = void>
771 class TryFormatValue {
773 template <class FormatCallback>
774 static void formatOrFail(T& /* value */,
776 FormatCallback& /* cb */) {
777 arg.error("No formatter available for this type");
782 class TryFormatValue<
784 typename std::enable_if<
785 0 < sizeof(FormatValue<typename std::decay<T>::type>)>::type>
788 template <class FormatCallback>
789 static void formatOrFail(T& value, FormatArg& arg, FormatCallback& cb) {
790 FormatValue<typename std::decay<T>::type>(value).format(arg, cb);
794 // Partial specialization of FormatValue for other pointers
798 typename std::enable_if<
799 !std::is_same<char, typename std::decay<T>::type>::value &&
800 !std::is_same<void, typename std::decay<T>::type>::value>::type>
803 explicit FormatValue(T* val) : val_(val) { }
805 template <class FormatCallback>
806 void format(FormatArg& arg, FormatCallback& cb) const {
807 if (arg.keyEmpty()) {
808 FormatValue<void*>((void*)val_).format(arg, cb);
810 TryFormatValue<T>::formatOrFail(val_[arg.splitIntKey()], arg, cb);
820 template <class T, size_t N>
821 struct IndexableTraits<std::array<T, N>>
822 : public IndexableTraitsSeq<std::array<T, N>> {
826 template <class T, class A>
827 struct IndexableTraits<std::vector<T, A>>
828 : public IndexableTraitsSeq<std::vector<T, A>> {
832 template <class T, class A>
833 struct IndexableTraits<std::deque<T, A>>
834 : public IndexableTraitsSeq<std::deque<T, A>> {
837 // std::map with integral keys
838 template <class K, class T, class C, class A>
839 struct IndexableTraits<
840 std::map<K, T, C, A>,
841 typename std::enable_if<std::is_integral<K>::value>::type>
842 : public IndexableTraitsAssoc<std::map<K, T, C, A>> {
845 // std::unordered_map with integral keys
846 template <class K, class T, class H, class E, class A>
847 struct IndexableTraits<
848 std::unordered_map<K, T, H, E, A>,
849 typename std::enable_if<std::is_integral<K>::value>::type>
850 : public IndexableTraitsAssoc<std::unordered_map<K, T, H, E, A>> {
853 } // namespace detail
855 // Partial specialization of FormatValue for integer-indexable containers
859 typename detail::IndexableTraits<T>::enabled> {
861 explicit FormatValue(const T& val) : val_(val) { }
863 template <class FormatCallback>
864 void format(FormatArg& arg, FormatCallback& cb) const {
865 FormatValue<typename std::decay<
866 typename detail::IndexableTraits<T>::value_type>::type>(
867 detail::IndexableTraits<T>::at(
868 val_, arg.splitIntKey())).format(arg, cb);
875 template <class Container, class Value>
877 detail::DefaultValueWrapper<Container, Value>,
878 typename detail::IndexableTraits<Container>::enabled> {
880 explicit FormatValue(const detail::DefaultValueWrapper<Container, Value>& val)
883 template <class FormatCallback>
884 void format(FormatArg& arg, FormatCallback& cb) const {
885 FormatValue<typename std::decay<
886 typename detail::IndexableTraits<Container>::value_type>::type>(
887 detail::IndexableTraits<Container>::at(
890 val_.defaultValue)).format(arg, cb);
894 const detail::DefaultValueWrapper<Container, Value>& val_;
899 // Define enabled, key_type, convert from StringPiece to the key types
901 template <class T> struct KeyFromStringPiece;
905 struct KeyFromStringPiece<std::string> : public FormatTraitsBase {
906 typedef std::string key_type;
907 static std::string convert(StringPiece s) {
910 typedef void enabled;
915 struct KeyFromStringPiece<fbstring> : public FormatTraitsBase {
916 typedef fbstring key_type;
917 static fbstring convert(StringPiece s) {
918 return s.toFbstring();
924 struct KeyFromStringPiece<StringPiece> : public FormatTraitsBase {
925 typedef StringPiece key_type;
926 static StringPiece convert(StringPiece s) {
931 // Base class for associative types keyed by strings
932 template <class T> struct KeyableTraitsAssoc : public FormatTraitsBase {
933 typedef typename T::key_type key_type;
934 typedef typename T::value_type::second_type value_type;
935 static const value_type& at(const T& map, StringPiece key) {
936 return map.at(KeyFromStringPiece<key_type>::convert(key));
938 static const value_type& at(const T& map, StringPiece key,
939 const value_type& dflt) {
940 auto pos = map.find(KeyFromStringPiece<key_type>::convert(key));
941 return pos != map.end() ? pos->second : dflt;
945 // Define enabled, key_type, value_type, at() for supported string-keyed
947 template <class T, class Enabled=void> struct KeyableTraits;
949 // std::map with string key
950 template <class K, class T, class C, class A>
951 struct KeyableTraits<
952 std::map<K, T, C, A>,
953 typename KeyFromStringPiece<K>::enabled>
954 : public KeyableTraitsAssoc<std::map<K, T, C, A>> {
957 // std::unordered_map with string key
958 template <class K, class T, class H, class E, class A>
959 struct KeyableTraits<
960 std::unordered_map<K, T, H, E, A>,
961 typename KeyFromStringPiece<K>::enabled>
962 : public KeyableTraitsAssoc<std::unordered_map<K, T, H, E, A>> {
965 } // namespace detail
967 // Partial specialization of FormatValue for string-keyed containers
971 typename detail::KeyableTraits<T>::enabled> {
973 explicit FormatValue(const T& val) : val_(val) { }
975 template <class FormatCallback>
976 void format(FormatArg& arg, FormatCallback& cb) const {
977 FormatValue<typename std::decay<
978 typename detail::KeyableTraits<T>::value_type>::type>(
979 detail::KeyableTraits<T>::at(
980 val_, arg.splitKey())).format(arg, cb);
987 template <class Container, class Value>
989 detail::DefaultValueWrapper<Container, Value>,
990 typename detail::KeyableTraits<Container>::enabled> {
992 explicit FormatValue(const detail::DefaultValueWrapper<Container, Value>& val)
995 template <class FormatCallback>
996 void format(FormatArg& arg, FormatCallback& cb) const {
997 FormatValue<typename std::decay<
998 typename detail::KeyableTraits<Container>::value_type>::type>(
999 detail::KeyableTraits<Container>::at(
1002 val_.defaultValue)).format(arg, cb);
1006 const detail::DefaultValueWrapper<Container, Value>& val_;
1009 // Partial specialization of FormatValue for pairs
1010 template <class A, class B>
1011 class FormatValue<std::pair<A, B>> {
1013 explicit FormatValue(const std::pair<A, B>& val) : val_(val) { }
1015 template <class FormatCallback>
1016 void format(FormatArg& arg, FormatCallback& cb) const {
1017 int key = arg.splitIntKey();
1020 FormatValue<typename std::decay<A>::type>(val_.first).format(arg, cb);
1023 FormatValue<typename std::decay<B>::type>(val_.second).format(arg, cb);
1026 arg.error("invalid index for pair");
1031 const std::pair<A, B>& val_;
1034 // Partial specialization of FormatValue for tuples
1035 template <class... Args>
1036 class FormatValue<std::tuple<Args...>> {
1037 typedef std::tuple<Args...> Tuple;
1039 explicit FormatValue(const Tuple& val) : val_(val) { }
1041 template <class FormatCallback>
1042 void format(FormatArg& arg, FormatCallback& cb) const {
1043 int key = arg.splitIntKey();
1044 arg.enforce(key >= 0, "tuple index must be non-negative");
1045 doFormat(key, arg, cb);
1049 static constexpr size_t valueCount = std::tuple_size<Tuple>::value;
1051 template <size_t K, class Callback>
1052 typename std::enable_if<K == valueCount>::type doFormatFrom(
1053 size_t i, FormatArg& arg, Callback& /* cb */) const {
1054 arg.enforce("tuple index out of range, max=", i);
1057 template <size_t K, class Callback>
1058 typename std::enable_if<(K < valueCount)>::type
1059 doFormatFrom(size_t i, FormatArg& arg, Callback& cb) const {
1061 FormatValue<typename std::decay<
1062 typename std::tuple_element<K, Tuple>::type>::type>(
1063 std::get<K>(val_)).format(arg, cb);
1065 doFormatFrom<K+1>(i, arg, cb);
1069 template <class Callback>
1070 void doFormat(size_t i, FormatArg& arg, Callback& cb) const {
1071 return doFormatFrom<0>(i, arg, cb);
1077 // Partial specialization of FormatValue for nested Formatters
1078 template <bool containerMode, class... Args,
1079 template <bool, class...> class F>
1080 class FormatValue<F<containerMode, Args...>,
1081 typename std::enable_if<detail::IsFormatter<
1082 F<containerMode, Args...>>::value>::type> {
1083 typedef typename F<containerMode, Args...>::BaseType FormatterValue;
1086 explicit FormatValue(const FormatterValue& f) : f_(f) { }
1088 template <class FormatCallback>
1089 void format(FormatArg& arg, FormatCallback& cb) const {
1090 format_value::formatFormatter(f_, arg, cb);
1093 const FormatterValue& f_;
1097 * Formatter objects can be appended to strings, and therefore they're
1098 * compatible with folly::toAppend and folly::to.
1100 template <class Tgt, class Derived, bool containerMode, class... Args>
1101 typename std::enable_if<IsSomeString<Tgt>::value>::type toAppend(
1102 const BaseFormatter<Derived, containerMode, Args...>& value, Tgt* result) {
1103 value.appendTo(*result);
1106 } // namespace folly
1108 #pragma GCC diagnostic pop