2 * Copyright 2015 Facebook, Inc.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 #ifndef FOLLY_FORMAT_H_
18 #error This file may only be included from Format.h.
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 // Updates the end of the buffer after the comma separators have been added.
33 void insertThousandsGroupingUnsafe(char* start_buffer, char** end_buffer);
35 extern const char formatHexUpper[256][2];
36 extern const char formatHexLower[256][2];
37 extern const char formatOctal[512][3];
38 extern const char formatBinary[256][8];
40 const size_t kMaxHexLength = 2 * sizeof(uintmax_t);
41 const size_t kMaxOctalLength = 3 * sizeof(uintmax_t);
42 const size_t kMaxBinaryLength = 8 * sizeof(uintmax_t);
45 * Convert an unsigned to hex, using repr (which maps from each possible
46 * 2-hex-bytes value to the 2-character representation).
48 * Just like folly::detail::uintToBuffer in Conv.h, writes at the *end* of
49 * the supplied buffer and returns the offset of the beginning of the string
50 * from the start of the buffer. The formatted string will be in range
51 * [buf+begin, buf+bufLen).
54 size_t uintToHex(char* buffer, size_t bufLen, Uint v,
55 const char (&repr)[256][2]) {
56 // 'v >>= 7, v >>= 1' is no more than a work around to get rid of shift size
57 // warning when Uint = uint8_t (it's false as v >= 256 implies sizeof(v) > 1).
58 for (; !less_than<unsigned, 256>(v); v >>= 7, v >>= 1) {
61 buffer[bufLen] = repr[b][0];
62 buffer[bufLen + 1] = repr[b][1];
64 buffer[--bufLen] = repr[v][1];
66 buffer[--bufLen] = repr[v][0];
72 * Convert an unsigned to hex, using lower-case letters for the digits
73 * above 9. See the comments for uintToHex.
76 inline size_t uintToHexLower(char* buffer, size_t bufLen, Uint v) {
77 return uintToHex(buffer, bufLen, v, formatHexLower);
81 * Convert an unsigned to hex, using upper-case letters for the digits
82 * above 9. See the comments for uintToHex.
85 inline size_t uintToHexUpper(char* buffer, size_t bufLen, Uint v) {
86 return uintToHex(buffer, bufLen, v, formatHexUpper);
90 * Convert an unsigned to octal.
92 * Just like folly::detail::uintToBuffer in Conv.h, writes at the *end* of
93 * the supplied buffer and returns the offset of the beginning of the string
94 * from the start of the buffer. The formatted string will be in range
95 * [buf+begin, buf+bufLen).
98 size_t uintToOctal(char* buffer, size_t bufLen, Uint v) {
99 auto& repr = formatOctal;
100 // 'v >>= 7, v >>= 2' is no more than a work around to get rid of shift size
101 // warning when Uint = uint8_t (it's false as v >= 512 implies sizeof(v) > 1).
102 for (; !less_than<unsigned, 512>(v); v >>= 7, v >>= 2) {
105 buffer[bufLen] = repr[b][0];
106 buffer[bufLen + 1] = repr[b][1];
107 buffer[bufLen + 2] = repr[b][2];
109 buffer[--bufLen] = repr[v][2];
111 buffer[--bufLen] = repr[v][1];
114 buffer[--bufLen] = repr[v][0];
120 * Convert an unsigned to binary.
122 * Just like folly::detail::uintToBuffer in Conv.h, writes at the *end* of
123 * the supplied buffer and returns the offset of the beginning of the string
124 * from the start of the buffer. The formatted string will be in range
125 * [buf+begin, buf+bufLen).
127 template <class Uint>
128 size_t uintToBinary(char* buffer, size_t bufLen, Uint v) {
129 auto& repr = formatBinary;
131 buffer[--bufLen] = '0';
134 for (; v; v >>= 7, v >>= 1) {
137 memcpy(buffer + bufLen, &(repr[b][0]), 8);
139 while (buffer[bufLen] == '0') {
145 } // namespace detail
147 template <class Derived, bool containerMode, class... Args>
148 BaseFormatter<Derived, containerMode, Args...>::BaseFormatter(StringPiece str,
151 values_(FormatValue<typename std::decay<Args>::type>(
152 std::forward<Args>(args))...) {
153 static_assert(!containerMode || sizeof...(Args) == 1,
154 "Exactly one argument required in container mode");
157 template <class Derived, bool containerMode, class... Args>
158 template <class Output>
159 void BaseFormatter<Derived, containerMode, Args...>::operator()(Output& out)
161 // Copy raw string (without format specifiers) to output;
162 // not as simple as we'd like, as we still need to translate "}}" to "}"
163 // and throw if we see any lone "}"
164 auto outputString = [&out] (StringPiece s) {
168 auto q = static_cast<const char*>(memchr(p, '}', end - p));
170 out(StringPiece(p, end));
174 out(StringPiece(p, q));
177 if (p == end || *p != '}') {
178 throw BadFormatArg("folly::format: single '}' in format string");
184 auto p = str_.begin();
185 auto end = str_.end();
188 bool hasDefaultArgIndex = false;
189 bool hasExplicitArgIndex = false;
191 auto q = static_cast<const char*>(memchr(p, '{', end - p));
193 outputString(StringPiece(p, end));
196 outputString(StringPiece(p, q));
200 throw BadFormatArg("folly::format: '}' at end of format string");
205 out(StringPiece(p, 1));
211 q = static_cast<const char*>(memchr(p, '}', end - p));
213 throw BadFormatArg("folly::format: missing ending '}'");
215 FormatArg arg(StringPiece(p, q));
219 auto piece = arg.splitKey<true>(); // empty key component is okay
220 if (containerMode) { // static
222 arg.setNextIntKey(nextArg++);
223 hasDefaultArgIndex = true;
225 arg.setNextKey(piece);
226 hasExplicitArgIndex = true;
230 argIndex = nextArg++;
231 hasDefaultArgIndex = true;
234 argIndex = to<int>(piece);
235 } catch (const std::out_of_range& e) {
236 arg.error("argument index must be integer");
238 arg.enforce(argIndex >= 0, "argument index must be non-negative");
239 hasExplicitArgIndex = true;
243 if (hasDefaultArgIndex && hasExplicitArgIndex) {
245 "folly::format: may not have both default and explicit arg indexes");
248 doFormat(argIndex, arg, out);
252 template <class Derived, bool containerMode, class... Args>
253 void writeTo(FILE* fp,
254 const BaseFormatter<Derived, containerMode, Args...>& formatter) {
255 auto writer = [fp] (StringPiece sp) {
256 size_t n = fwrite(sp.data(), 1, sp.size(), fp);
258 throwSystemError("Formatter writeTo", "fwrite failed");
264 namespace format_value {
266 template <class FormatCallback>
267 void formatString(StringPiece val, FormatArg& arg, FormatCallback& cb) {
268 if (arg.width != FormatArg::kDefaultWidth && arg.width < 0) {
269 throw BadFormatArg("folly::format: invalid width");
271 if (arg.precision != FormatArg::kDefaultPrecision && arg.precision < 0) {
272 throw BadFormatArg("folly::format: invalid precision");
275 // XXX: clang should be smart enough to not need the two static_cast<size_t>
276 // uses below given the above checks. If clang ever becomes that smart, we
277 // should remove the otherwise unnecessary warts.
279 if (arg.precision != FormatArg::kDefaultPrecision &&
280 val.size() > static_cast<size_t>(arg.precision)) {
281 val.reset(val.data(), arg.precision);
284 constexpr int padBufSize = 128;
285 char padBuf[padBufSize];
287 // Output padding, no more than padBufSize at once
288 auto pad = [&padBuf, &cb, padBufSize] (int chars) {
290 int n = std::min(chars, padBufSize);
291 cb(StringPiece(padBuf, n));
296 int padRemaining = 0;
297 if (arg.width != FormatArg::kDefaultWidth &&
298 val.size() < static_cast<size_t>(arg.width)) {
299 char fill = arg.fill == FormatArg::kDefaultFill ? ' ' : arg.fill;
300 int padChars = static_cast<int> (arg.width - val.size());
301 memset(padBuf, fill, std::min(padBufSize, padChars));
304 case FormatArg::Align::DEFAULT:
305 case FormatArg::Align::LEFT:
306 padRemaining = padChars;
308 case FormatArg::Align::CENTER:
310 padRemaining = padChars - padChars / 2;
312 case FormatArg::Align::RIGHT:
313 case FormatArg::Align::PAD_AFTER_SIGN:
329 template <class FormatCallback>
330 void formatNumber(StringPiece val, int prefixLen, FormatArg& arg,
331 FormatCallback& cb) {
332 // precision means something different for numbers
333 arg.precision = FormatArg::kDefaultPrecision;
334 if (arg.align == FormatArg::Align::DEFAULT) {
335 arg.align = FormatArg::Align::RIGHT;
336 } else if (prefixLen && arg.align == FormatArg::Align::PAD_AFTER_SIGN) {
337 // Split off the prefix, then do any padding if necessary
338 cb(val.subpiece(0, prefixLen));
339 val.advance(prefixLen);
340 arg.width = std::max(arg.width - prefixLen, 0);
342 format_value::formatString(val, arg, cb);
345 template <class FormatCallback,
349 void formatFormatter(
350 const BaseFormatter<Derived, containerMode, Args...>& formatter,
352 FormatCallback& cb) {
353 if (arg.width == FormatArg::kDefaultWidth &&
354 arg.precision == FormatArg::kDefaultPrecision) {
357 } else if (arg.align != FormatArg::Align::LEFT &&
358 arg.align != FormatArg::Align::DEFAULT) {
359 // We can only avoid creating a temporary string if we align left,
360 // as we'd need to know the size beforehand otherwise
361 format_value::formatString(formatter.fbstr(), arg, cb);
363 auto fn = [&arg, &cb] (StringPiece sp) mutable {
364 int sz = static_cast<int>(sp.size());
365 if (arg.precision != FormatArg::kDefaultPrecision) {
366 sz = std::min(arg.precision, sz);
367 sp.reset(sp.data(), sz);
372 if (arg.width != FormatArg::kDefaultWidth) {
373 arg.width = std::max(arg.width - sz, 0);
378 if (arg.width != FormatArg::kDefaultWidth && arg.width != 0) {
379 // Rely on formatString to do appropriate padding
380 format_value::formatString(StringPiece(), arg, cb);
385 } // namespace format_value
387 // Definitions for default FormatValue classes
389 // Integral types (except bool)
392 T, typename std::enable_if<
393 std::is_integral<T>::value &&
394 !std::is_same<T, bool>::value>::type>
397 explicit FormatValue(T val) : val_(val) { }
398 template <class FormatCallback>
399 void format(FormatArg& arg, FormatCallback& cb) const {
400 arg.validate(FormatArg::Type::INTEGER);
404 template <class FormatCallback>
405 void doFormat(FormatArg& arg, FormatCallback& cb) const {
406 char presentation = arg.presentation;
407 if (presentation == FormatArg::kDefaultPresentation) {
408 presentation = std::is_same<T, char>::value ? 'c' : 'd';
411 // Do all work as unsigned, we'll add the prefix ('0' or '0x' if necessary)
412 // and sign ourselves.
413 typedef typename std::make_unsigned<T>::type UT;
416 if (std::is_signed<T>::value) {
417 if (folly::is_negative(val_)) {
418 uval = static_cast<UT>(-val_);
421 uval = static_cast<UT>(val_);
423 case FormatArg::Sign::PLUS_OR_MINUS:
426 case FormatArg::Sign::SPACE_OR_MINUS:
438 arg.enforce(arg.sign == FormatArg::Sign::DEFAULT,
439 "sign specifications not allowed for unsigned values");
443 // #x: 0x prefix + 16 bytes = 18 bytes
444 // #o: 0 prefix + 22 bytes = 23 bytes
445 // #b: 0b prefix + 64 bytes = 65 bytes
446 // ,d: 26 bytes (including thousands separators!)
448 // + 3 for sign and prefix shenanigans (see below)
449 constexpr size_t valBufSize = 69;
450 char valBuf[valBufSize];
451 char* valBufBegin = nullptr;
452 char* valBufEnd = nullptr;
455 switch (presentation) {
457 arg.enforce(!arg.basePrefix,
458 "base prefix not allowed with '", presentation,
461 arg.enforce(!arg.thousandsSeparator,
462 "cannot use ',' with the '", presentation,
465 valBufBegin = valBuf + 3; // room for sign and base prefix
466 int len = snprintf(valBufBegin, (valBuf + valBufSize) - valBufBegin,
467 "%'ju", static_cast<uintmax_t>(uval));
468 // valBufSize should always be big enough, so this should never
470 assert(len < valBuf + valBufSize - valBufBegin);
471 valBufEnd = valBufBegin + len;
475 arg.enforce(!arg.basePrefix,
476 "base prefix not allowed with '", presentation,
478 valBufBegin = valBuf + 3; // room for sign and base prefix
480 // Use uintToBuffer, faster than sprintf
481 valBufEnd = valBufBegin + uint64ToBufferUnsafe(uval, valBufBegin);
482 if (arg.thousandsSeparator) {
483 detail::insertThousandsGroupingUnsafe(valBufBegin, &valBufEnd);
487 arg.enforce(!arg.basePrefix,
488 "base prefix not allowed with '", presentation,
490 arg.enforce(!arg.thousandsSeparator,
491 "thousands separator (',') not allowed with '",
492 presentation, "' specifier");
493 valBufBegin = valBuf + 3;
494 *valBufBegin = static_cast<char>(uval);
495 valBufEnd = valBufBegin + 1;
499 arg.enforce(!arg.thousandsSeparator,
500 "thousands separator (',') not allowed with '",
501 presentation, "' specifier");
502 valBufEnd = valBuf + valBufSize - 1;
503 valBufBegin = valBuf + detail::uintToOctal(valBuf, valBufSize - 1, uval);
504 if (arg.basePrefix) {
505 *--valBufBegin = '0';
510 arg.enforce(!arg.thousandsSeparator,
511 "thousands separator (',') not allowed with '",
512 presentation, "' specifier");
513 valBufEnd = valBuf + valBufSize - 1;
514 valBufBegin = valBuf + detail::uintToHexLower(valBuf, valBufSize - 1,
516 if (arg.basePrefix) {
517 *--valBufBegin = 'x';
518 *--valBufBegin = '0';
523 arg.enforce(!arg.thousandsSeparator,
524 "thousands separator (',') not allowed with '",
525 presentation, "' specifier");
526 valBufEnd = valBuf + valBufSize - 1;
527 valBufBegin = valBuf + detail::uintToHexUpper(valBuf, valBufSize - 1,
529 if (arg.basePrefix) {
530 *--valBufBegin = 'X';
531 *--valBufBegin = '0';
537 arg.enforce(!arg.thousandsSeparator,
538 "thousands separator (',') not allowed with '",
539 presentation, "' specifier");
540 valBufEnd = valBuf + valBufSize - 1;
541 valBufBegin = valBuf + detail::uintToBinary(valBuf, valBufSize - 1,
543 if (arg.basePrefix) {
544 *--valBufBegin = presentation; // 0b or 0B
545 *--valBufBegin = '0';
550 arg.error("invalid specifier '", presentation, "'");
554 *--valBufBegin = sign;
558 format_value::formatNumber(StringPiece(valBufBegin, valBufEnd), prefixLen,
568 class FormatValue<bool> {
570 explicit FormatValue(bool val) : val_(val) { }
572 template <class FormatCallback>
573 void format(FormatArg& arg, FormatCallback& cb) const {
574 if (arg.presentation == FormatArg::kDefaultPresentation) {
575 arg.validate(FormatArg::Type::OTHER);
576 format_value::formatString(val_ ? "true" : "false", arg, cb);
578 FormatValue<int>(val_).format(arg, cb);
588 class FormatValue<double> {
590 explicit FormatValue(double val) : val_(val) { }
592 template <class FormatCallback>
593 void format(FormatArg& arg, FormatCallback& cb) const {
596 formatHelper(piece, prefixLen, arg);
597 format_value::formatNumber(piece, prefixLen, arg, cb);
601 void formatHelper(fbstring& piece, int& prefixLen, FormatArg& arg) const;
606 // float (defer to double)
608 class FormatValue<float> {
610 explicit FormatValue(float val) : val_(val) { }
612 template <class FormatCallback>
613 void format(FormatArg& arg, FormatCallback& cb) const {
614 FormatValue<double>(val_).format(arg, cb);
621 // Sring-y types (implicitly convertible to StringPiece, except char*)
624 T, typename std::enable_if<
625 (!std::is_pointer<T>::value ||
626 !std::is_same<char, typename std::decay<
627 typename std::remove_pointer<T>::type>::type>::value) &&
628 std::is_convertible<T, StringPiece>::value>::type>
631 explicit FormatValue(StringPiece val) : val_(val) { }
633 template <class FormatCallback>
634 void format(FormatArg& arg, FormatCallback& cb) const {
635 if (arg.keyEmpty()) {
636 arg.validate(FormatArg::Type::OTHER);
637 arg.enforce(arg.presentation == FormatArg::kDefaultPresentation ||
638 arg.presentation == 's',
639 "invalid specifier '", arg.presentation, "'");
640 format_value::formatString(val_, arg, cb);
642 FormatValue<char>(val_.at(arg.splitIntKey())).format(arg, cb);
652 class FormatValue<std::nullptr_t> {
654 explicit FormatValue(std::nullptr_t) { }
656 template <class FormatCallback>
657 void format(FormatArg& arg, FormatCallback& cb) const {
658 arg.validate(FormatArg::Type::OTHER);
659 arg.enforce(arg.presentation == FormatArg::kDefaultPresentation,
660 "invalid specifier '", arg.presentation, "'");
661 format_value::formatString("(null)", arg, cb);
665 // Partial specialization of FormatValue for char*
669 typename std::enable_if<
670 std::is_same<char, typename std::decay<T>::type>::value>::type>
673 explicit FormatValue(T* val) : val_(val) { }
675 template <class FormatCallback>
676 void format(FormatArg& arg, FormatCallback& cb) const {
677 if (arg.keyEmpty()) {
679 FormatValue<std::nullptr_t>(nullptr).format(arg, cb);
681 FormatValue<StringPiece>(val_).format(arg, cb);
684 FormatValue<typename std::decay<T>::type>(
685 val_[arg.splitIntKey()]).format(arg, cb);
693 // Partial specialization of FormatValue for void*
697 typename std::enable_if<
698 std::is_same<void, typename std::decay<T>::type>::value>::type>
701 explicit FormatValue(T* val) : val_(val) { }
703 template <class FormatCallback>
704 void format(FormatArg& arg, FormatCallback& cb) const {
706 FormatValue<std::nullptr_t>(nullptr).format(arg, cb);
708 // Print as a pointer, in hex.
709 arg.validate(FormatArg::Type::OTHER);
710 arg.enforce(arg.presentation == FormatArg::kDefaultPresentation,
711 "invalid specifier '", arg.presentation, "'");
712 arg.basePrefix = true;
713 arg.presentation = 'x';
714 if (arg.align == FormatArg::Align::DEFAULT) {
715 arg.align = FormatArg::Align::LEFT;
717 FormatValue<uintptr_t>(
718 reinterpret_cast<uintptr_t>(val_)).doFormat(arg, cb);
726 template <class T, class = void>
727 class TryFormatValue {
729 template <class FormatCallback>
730 static void formatOrFail(T& value, FormatArg& arg, FormatCallback& cb) {
731 arg.error("No formatter available for this type");
736 class TryFormatValue<
738 typename std::enable_if<
739 0 < sizeof(FormatValue<typename std::decay<T>::type>)>::type>
742 template <class FormatCallback>
743 static void formatOrFail(T& value, FormatArg& arg, FormatCallback& cb) {
744 FormatValue<typename std::decay<T>::type>(value).format(arg, cb);
748 // Partial specialization of FormatValue for other pointers
752 typename std::enable_if<
753 !std::is_same<char, typename std::decay<T>::type>::value &&
754 !std::is_same<void, typename std::decay<T>::type>::value>::type>
757 explicit FormatValue(T* val) : val_(val) { }
759 template <class FormatCallback>
760 void format(FormatArg& arg, FormatCallback& cb) const {
761 if (arg.keyEmpty()) {
762 FormatValue<void*>((void*)val_).format(arg, cb);
764 TryFormatValue<T>::formatOrFail(val_[arg.splitIntKey()], arg, cb);
773 // Shortcut, so we don't have to use enable_if everywhere
774 struct FormatTraitsBase {
775 typedef void enabled;
778 // Traits that define enabled, value_type, and at() for anything
779 // indexable with integral keys: pointers, arrays, vectors, and maps
780 // with integral keys
781 template <class T, class Enable=void> struct IndexableTraits;
783 // Base class for sequences (vectors, deques)
785 struct IndexableTraitsSeq : public FormatTraitsBase {
786 typedef C container_type;
787 typedef typename C::value_type value_type;
788 static const value_type& at(const C& c, int idx) {
792 static const value_type& at(const C& c, int idx,
793 const value_type& dflt) {
794 return (idx >= 0 && size_t(idx) < c.size()) ? c.at(idx) : dflt;
798 // Base class for associative types (maps)
800 struct IndexableTraitsAssoc : public FormatTraitsBase {
801 typedef typename C::value_type::second_type value_type;
802 static const value_type& at(const C& c, int idx) {
803 return c.at(static_cast<typename C::key_type>(idx));
805 static const value_type& at(const C& c, int idx,
806 const value_type& dflt) {
807 auto pos = c.find(static_cast<typename C::key_type>(idx));
808 return pos != c.end() ? pos->second : dflt;
813 template <class T, size_t N>
814 struct IndexableTraits<std::array<T, N>>
815 : public IndexableTraitsSeq<std::array<T, N>> {
819 template <class T, class A>
820 struct IndexableTraits<std::vector<T, A>>
821 : public IndexableTraitsSeq<std::vector<T, A>> {
825 template <class T, class A>
826 struct IndexableTraits<std::deque<T, A>>
827 : public IndexableTraitsSeq<std::deque<T, A>> {
831 template <class T, class A>
832 struct IndexableTraits<fbvector<T, A>>
833 : public IndexableTraitsSeq<fbvector<T, A>> {
837 template <class T, size_t M, class A, class B, class C>
838 struct IndexableTraits<small_vector<T, M, A, B, C>>
839 : public IndexableTraitsSeq<small_vector<T, M, A, B, C>> {
842 // std::map with integral keys
843 template <class K, class T, class C, class A>
844 struct IndexableTraits<
845 std::map<K, T, C, A>,
846 typename std::enable_if<std::is_integral<K>::value>::type>
847 : public IndexableTraitsAssoc<std::map<K, T, C, A>> {
850 // std::unordered_map with integral keys
851 template <class K, class T, class H, class E, class A>
852 struct IndexableTraits<
853 std::unordered_map<K, T, H, E, A>,
854 typename std::enable_if<std::is_integral<K>::value>::type>
855 : public IndexableTraitsAssoc<std::unordered_map<K, T, H, E, A>> {
858 } // namespace detail
860 // Partial specialization of FormatValue for integer-indexable containers
864 typename detail::IndexableTraits<T>::enabled> {
866 explicit FormatValue(const T& val) : val_(val) { }
868 template <class FormatCallback>
869 void format(FormatArg& arg, FormatCallback& cb) const {
870 FormatValue<typename std::decay<
871 typename detail::IndexableTraits<T>::value_type>::type>(
872 detail::IndexableTraits<T>::at(
873 val_, arg.splitIntKey())).format(arg, cb);
880 template <class Container, class Value>
882 detail::DefaultValueWrapper<Container, Value>,
883 typename detail::IndexableTraits<Container>::enabled> {
885 explicit FormatValue(const detail::DefaultValueWrapper<Container, Value>& val)
888 template <class FormatCallback>
889 void format(FormatArg& arg, FormatCallback& cb) const {
890 FormatValue<typename std::decay<
891 typename detail::IndexableTraits<Container>::value_type>::type>(
892 detail::IndexableTraits<Container>::at(
895 val_.defaultValue)).format(arg, cb);
899 const detail::DefaultValueWrapper<Container, Value>& val_;
904 // Define enabled, key_type, convert from StringPiece to the key types
906 template <class T> struct KeyFromStringPiece;
910 struct KeyFromStringPiece<std::string> : public FormatTraitsBase {
911 typedef std::string key_type;
912 static std::string convert(StringPiece s) {
915 typedef void enabled;
920 struct KeyFromStringPiece<fbstring> : public FormatTraitsBase {
921 typedef fbstring key_type;
922 static fbstring convert(StringPiece s) {
923 return s.toFbstring();
929 struct KeyFromStringPiece<StringPiece> : public FormatTraitsBase {
930 typedef StringPiece key_type;
931 static StringPiece convert(StringPiece s) {
936 // Base class for associative types keyed by strings
937 template <class T> struct KeyableTraitsAssoc : public FormatTraitsBase {
938 typedef typename T::key_type key_type;
939 typedef typename T::value_type::second_type value_type;
940 static const value_type& at(const T& map, StringPiece key) {
941 return map.at(KeyFromStringPiece<key_type>::convert(key));
943 static const value_type& at(const T& map, StringPiece key,
944 const value_type& dflt) {
945 auto pos = map.find(KeyFromStringPiece<key_type>::convert(key));
946 return pos != map.end() ? pos->second : dflt;
950 // Define enabled, key_type, value_type, at() for supported string-keyed
952 template <class T, class Enabled=void> struct KeyableTraits;
954 // std::map with string key
955 template <class K, class T, class C, class A>
956 struct KeyableTraits<
957 std::map<K, T, C, A>,
958 typename KeyFromStringPiece<K>::enabled>
959 : public KeyableTraitsAssoc<std::map<K, T, C, A>> {
962 // std::unordered_map with string key
963 template <class K, class T, class H, class E, class A>
964 struct KeyableTraits<
965 std::unordered_map<K, T, H, E, A>,
966 typename KeyFromStringPiece<K>::enabled>
967 : public KeyableTraitsAssoc<std::unordered_map<K, T, H, E, A>> {
970 } // namespace detail
972 // Partial specialization of FormatValue for string-keyed containers
976 typename detail::KeyableTraits<T>::enabled> {
978 explicit FormatValue(const T& val) : val_(val) { }
980 template <class FormatCallback>
981 void format(FormatArg& arg, FormatCallback& cb) const {
982 FormatValue<typename std::decay<
983 typename detail::KeyableTraits<T>::value_type>::type>(
984 detail::KeyableTraits<T>::at(
985 val_, arg.splitKey())).format(arg, cb);
992 template <class Container, class Value>
994 detail::DefaultValueWrapper<Container, Value>,
995 typename detail::KeyableTraits<Container>::enabled> {
997 explicit FormatValue(const detail::DefaultValueWrapper<Container, Value>& val)
1000 template <class FormatCallback>
1001 void format(FormatArg& arg, FormatCallback& cb) const {
1002 FormatValue<typename std::decay<
1003 typename detail::KeyableTraits<Container>::value_type>::type>(
1004 detail::KeyableTraits<Container>::at(
1007 val_.defaultValue)).format(arg, cb);
1011 const detail::DefaultValueWrapper<Container, Value>& val_;
1014 // Partial specialization of FormatValue for pairs
1015 template <class A, class B>
1016 class FormatValue<std::pair<A, B>> {
1018 explicit FormatValue(const std::pair<A, B>& val) : val_(val) { }
1020 template <class FormatCallback>
1021 void format(FormatArg& arg, FormatCallback& cb) const {
1022 int key = arg.splitIntKey();
1025 FormatValue<typename std::decay<A>::type>(val_.first).format(arg, cb);
1028 FormatValue<typename std::decay<B>::type>(val_.second).format(arg, cb);
1031 arg.error("invalid index for pair");
1036 const std::pair<A, B>& val_;
1039 // Partial specialization of FormatValue for tuples
1040 template <class... Args>
1041 class FormatValue<std::tuple<Args...>> {
1042 typedef std::tuple<Args...> Tuple;
1044 explicit FormatValue(const Tuple& val) : val_(val) { }
1046 template <class FormatCallback>
1047 void format(FormatArg& arg, FormatCallback& cb) const {
1048 int key = arg.splitIntKey();
1049 arg.enforce(key >= 0, "tuple index must be non-negative");
1050 doFormat(key, arg, cb);
1054 static constexpr size_t valueCount = std::tuple_size<Tuple>::value;
1056 template <size_t K, class Callback>
1057 typename std::enable_if<K == valueCount>::type
1058 doFormatFrom(size_t i, FormatArg& arg, Callback& cb) const {
1059 arg.enforce("tuple index out of range, max=", i);
1062 template <size_t K, class Callback>
1063 typename std::enable_if<(K < valueCount)>::type
1064 doFormatFrom(size_t i, FormatArg& arg, Callback& cb) const {
1066 FormatValue<typename std::decay<
1067 typename std::tuple_element<K, Tuple>::type>::type>(
1068 std::get<K>(val_)).format(arg, cb);
1070 doFormatFrom<K+1>(i, arg, cb);
1074 template <class Callback>
1075 void doFormat(size_t i, FormatArg& arg, Callback& cb) const {
1076 return doFormatFrom<0>(i, arg, cb);
1082 // Partial specialization of FormatValue for nested Formatters
1083 template <bool containerMode, class... Args,
1084 template <bool, class...> class F>
1085 class FormatValue<F<containerMode, Args...>,
1086 typename std::enable_if<detail::IsFormatter<
1087 F<containerMode, Args...>>::value>::type> {
1088 typedef typename F<containerMode, Args...>::BaseType FormatterValue;
1091 explicit FormatValue(const FormatterValue& f) : f_(f) { }
1093 template <class FormatCallback>
1094 void format(FormatArg& arg, FormatCallback& cb) const {
1095 format_value::formatFormatter(f_, arg, cb);
1098 const FormatterValue& f_;
1102 * Formatter objects can be appended to strings, and therefore they're
1103 * compatible with folly::toAppend and folly::to.
1105 template <class Tgt, class Derived, bool containerMode, class... Args>
1106 typename std::enable_if<IsSomeString<Tgt>::value>::type toAppend(
1107 const BaseFormatter<Derived, containerMode, Args...>& value, Tgt* result) {
1108 value.appendTo(*result);
1111 } // namespace folly
1113 #pragma GCC diagnostic pop