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>
31 #include <folly/portability/Windows.h>
33 // Ignore -Wformat-nonliteral warnings within this file
34 #pragma GCC diagnostic push
35 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
41 // Updates the end of the buffer after the comma separators have been added.
42 void insertThousandsGroupingUnsafe(char* start_buffer, char** end_buffer);
44 extern const char formatHexUpper[256][2];
45 extern const char formatHexLower[256][2];
46 extern const char formatOctal[512][3];
47 extern const char formatBinary[256][8];
49 const size_t kMaxHexLength = 2 * sizeof(uintmax_t);
50 const size_t kMaxOctalLength = 3 * sizeof(uintmax_t);
51 const size_t kMaxBinaryLength = 8 * sizeof(uintmax_t);
54 * Convert an unsigned to hex, using repr (which maps from each possible
55 * 2-hex-bytes value to the 2-character representation).
57 * Just like folly::detail::uintToBuffer in Conv.h, writes at the *end* of
58 * the supplied buffer and returns the offset of the beginning of the string
59 * from the start of the buffer. The formatted string will be in range
60 * [buf+begin, buf+bufLen).
63 size_t uintToHex(char* buffer, size_t bufLen, Uint v,
64 const char (&repr)[256][2]) {
65 // 'v >>= 7, v >>= 1' is no more than a work around to get rid of shift size
66 // warning when Uint = uint8_t (it's false as v >= 256 implies sizeof(v) > 1).
67 for (; !less_than<unsigned, 256>(v); v >>= 7, v >>= 1) {
70 buffer[bufLen] = repr[b][0];
71 buffer[bufLen + 1] = repr[b][1];
73 buffer[--bufLen] = repr[v][1];
75 buffer[--bufLen] = repr[v][0];
81 * Convert an unsigned to hex, using lower-case letters for the digits
82 * above 9. See the comments for uintToHex.
85 inline size_t uintToHexLower(char* buffer, size_t bufLen, Uint v) {
86 return uintToHex(buffer, bufLen, v, formatHexLower);
90 * Convert an unsigned to hex, using upper-case letters for the digits
91 * above 9. See the comments for uintToHex.
94 inline size_t uintToHexUpper(char* buffer, size_t bufLen, Uint v) {
95 return uintToHex(buffer, bufLen, v, formatHexUpper);
99 * Convert an unsigned to octal.
101 * Just like folly::detail::uintToBuffer in Conv.h, writes at the *end* of
102 * the supplied buffer and returns the offset of the beginning of the string
103 * from the start of the buffer. The formatted string will be in range
104 * [buf+begin, buf+bufLen).
106 template <class Uint>
107 size_t uintToOctal(char* buffer, size_t bufLen, Uint v) {
108 auto& repr = formatOctal;
109 // 'v >>= 7, v >>= 2' is no more than a work around to get rid of shift size
110 // warning when Uint = uint8_t (it's false as v >= 512 implies sizeof(v) > 1).
111 for (; !less_than<unsigned, 512>(v); v >>= 7, v >>= 2) {
114 buffer[bufLen] = repr[b][0];
115 buffer[bufLen + 1] = repr[b][1];
116 buffer[bufLen + 2] = repr[b][2];
118 buffer[--bufLen] = repr[v][2];
120 buffer[--bufLen] = repr[v][1];
123 buffer[--bufLen] = repr[v][0];
129 * Convert an unsigned to binary.
131 * Just like folly::detail::uintToBuffer in Conv.h, writes at the *end* of
132 * the supplied buffer and returns the offset of the beginning of the string
133 * from the start of the buffer. The formatted string will be in range
134 * [buf+begin, buf+bufLen).
136 template <class Uint>
137 size_t uintToBinary(char* buffer, size_t bufLen, Uint v) {
138 auto& repr = formatBinary;
140 buffer[--bufLen] = '0';
143 for (; v; v >>= 7, v >>= 1) {
146 memcpy(buffer + bufLen, &(repr[b][0]), 8);
148 while (buffer[bufLen] == '0') {
154 } // namespace detail
156 template <class Derived, bool containerMode, class... Args>
157 BaseFormatter<Derived, containerMode, Args...>::BaseFormatter(StringPiece str,
160 values_(FormatValue<typename std::decay<Args>::type>(
161 std::forward<Args>(args))...) {
162 static_assert(!containerMode || sizeof...(Args) == 1,
163 "Exactly one argument required in container mode");
166 template <class Derived, bool containerMode, class... Args>
167 template <class Output>
168 void BaseFormatter<Derived, containerMode, Args...>::operator()(Output& out)
170 // Copy raw string (without format specifiers) to output;
171 // not as simple as we'd like, as we still need to translate "}}" to "}"
172 // and throw if we see any lone "}"
173 auto outputString = [&out] (StringPiece s) {
177 auto q = static_cast<const char*>(memchr(p, '}', end - p));
179 out(StringPiece(p, end));
183 out(StringPiece(p, q));
186 if (p == end || *p != '}') {
187 throw BadFormatArg("folly::format: single '}' in format string");
193 auto p = str_.begin();
194 auto end = str_.end();
197 bool hasDefaultArgIndex = false;
198 bool hasExplicitArgIndex = false;
200 auto q = static_cast<const char*>(memchr(p, '{', end - p));
202 outputString(StringPiece(p, end));
205 outputString(StringPiece(p, q));
209 throw BadFormatArg("folly::format: '}' at end of format string");
214 out(StringPiece(p, 1));
220 q = static_cast<const char*>(memchr(p, '}', end - p));
222 throw BadFormatArg("folly::format: missing ending '}'");
224 FormatArg arg(StringPiece(p, q));
228 auto piece = arg.splitKey<true>(); // empty key component is okay
229 if (containerMode) { // static
230 arg.enforce(arg.width != FormatArg::kDynamicWidth,
231 "dynamic field width not supported in vformat()");
233 arg.setNextIntKey(nextArg++);
234 hasDefaultArgIndex = true;
236 arg.setNextKey(piece);
237 hasExplicitArgIndex = true;
241 if (arg.width == FormatArg::kDynamicWidth) {
242 arg.enforce(arg.widthIndex == FormatArg::kNoIndex,
243 "cannot provide width arg index without value arg index");
244 int sizeArg = nextArg++;
245 arg.width = getSizeArg(sizeArg, arg);
248 argIndex = nextArg++;
249 hasDefaultArgIndex = true;
251 if (arg.width == FormatArg::kDynamicWidth) {
252 arg.enforce(arg.widthIndex != FormatArg::kNoIndex,
253 "cannot provide value arg index without width arg index");
254 arg.width = getSizeArg(arg.widthIndex, arg);
258 argIndex = to<int>(piece);
259 } catch (const std::out_of_range& e) {
260 arg.error("argument index must be integer");
262 arg.enforce(argIndex >= 0, "argument index must be non-negative");
263 hasExplicitArgIndex = true;
267 if (hasDefaultArgIndex && hasExplicitArgIndex) {
269 "folly::format: may not have both default and explicit arg indexes");
272 doFormat(argIndex, arg, out);
276 template <class Derived, bool containerMode, class... Args>
277 void writeTo(FILE* fp,
278 const BaseFormatter<Derived, containerMode, Args...>& formatter) {
279 auto writer = [fp] (StringPiece sp) {
280 size_t n = fwrite(sp.data(), 1, sp.size(), fp);
282 throwSystemError("Formatter writeTo", "fwrite failed");
288 namespace format_value {
290 template <class FormatCallback>
291 void formatString(StringPiece val, FormatArg& arg, FormatCallback& cb) {
292 if (arg.width != FormatArg::kDefaultWidth && arg.width < 0) {
293 throw BadFormatArg("folly::format: invalid width");
295 if (arg.precision != FormatArg::kDefaultPrecision && arg.precision < 0) {
296 throw BadFormatArg("folly::format: invalid precision");
299 // XXX: clang should be smart enough to not need the two static_cast<size_t>
300 // uses below given the above checks. If clang ever becomes that smart, we
301 // should remove the otherwise unnecessary warts.
303 if (arg.precision != FormatArg::kDefaultPrecision &&
304 val.size() > static_cast<size_t>(arg.precision)) {
305 val.reset(val.data(), arg.precision);
308 constexpr int padBufSize = 128;
309 char padBuf[padBufSize];
311 // Output padding, no more than padBufSize at once
312 auto pad = [&padBuf, &cb, padBufSize] (int chars) {
314 int n = std::min(chars, padBufSize);
315 cb(StringPiece(padBuf, n));
320 int padRemaining = 0;
321 if (arg.width != FormatArg::kDefaultWidth &&
322 val.size() < static_cast<size_t>(arg.width)) {
323 char fill = arg.fill == FormatArg::kDefaultFill ? ' ' : arg.fill;
324 int padChars = static_cast<int> (arg.width - val.size());
325 memset(padBuf, fill, std::min(padBufSize, padChars));
328 case FormatArg::Align::DEFAULT:
329 case FormatArg::Align::LEFT:
330 padRemaining = padChars;
332 case FormatArg::Align::CENTER:
334 padRemaining = padChars - padChars / 2;
336 case FormatArg::Align::RIGHT:
337 case FormatArg::Align::PAD_AFTER_SIGN:
353 template <class FormatCallback>
354 void formatNumber(StringPiece val, int prefixLen, FormatArg& arg,
355 FormatCallback& cb) {
356 // precision means something different for numbers
357 arg.precision = FormatArg::kDefaultPrecision;
358 if (arg.align == FormatArg::Align::DEFAULT) {
359 arg.align = FormatArg::Align::RIGHT;
360 } else if (prefixLen && arg.align == FormatArg::Align::PAD_AFTER_SIGN) {
361 // Split off the prefix, then do any padding if necessary
362 cb(val.subpiece(0, prefixLen));
363 val.advance(prefixLen);
364 arg.width = std::max(arg.width - prefixLen, 0);
366 format_value::formatString(val, arg, cb);
369 template <class FormatCallback,
373 void formatFormatter(
374 const BaseFormatter<Derived, containerMode, Args...>& formatter,
376 FormatCallback& cb) {
377 if (arg.width == FormatArg::kDefaultWidth &&
378 arg.precision == FormatArg::kDefaultPrecision) {
381 } else if (arg.align != FormatArg::Align::LEFT &&
382 arg.align != FormatArg::Align::DEFAULT) {
383 // We can only avoid creating a temporary string if we align left,
384 // as we'd need to know the size beforehand otherwise
385 format_value::formatString(formatter.fbstr(), arg, cb);
387 auto fn = [&arg, &cb] (StringPiece sp) mutable {
388 int sz = static_cast<int>(sp.size());
389 if (arg.precision != FormatArg::kDefaultPrecision) {
390 sz = std::min(arg.precision, sz);
391 sp.reset(sp.data(), sz);
396 if (arg.width != FormatArg::kDefaultWidth) {
397 arg.width = std::max(arg.width - sz, 0);
402 if (arg.width != FormatArg::kDefaultWidth && arg.width != 0) {
403 // Rely on formatString to do appropriate padding
404 format_value::formatString(StringPiece(), arg, cb);
409 } // namespace format_value
411 // Definitions for default FormatValue classes
413 // Integral types (except bool)
416 T, typename std::enable_if<
417 std::is_integral<T>::value &&
418 !std::is_same<T, bool>::value>::type>
421 explicit FormatValue(T val) : val_(val) { }
427 template <class FormatCallback>
428 void format(FormatArg& arg, FormatCallback& cb) const {
429 arg.validate(FormatArg::Type::INTEGER);
433 template <class FormatCallback>
434 void doFormat(FormatArg& arg, FormatCallback& cb) const {
435 char presentation = arg.presentation;
436 if (presentation == FormatArg::kDefaultPresentation) {
437 presentation = std::is_same<T, char>::value ? 'c' : 'd';
440 // Do all work as unsigned, we'll add the prefix ('0' or '0x' if necessary)
441 // and sign ourselves.
442 typedef typename std::make_unsigned<T>::type UT;
445 if (std::is_signed<T>::value) {
446 if (folly::is_negative(val_)) {
447 uval = -static_cast<UT>(val_);
450 uval = static_cast<UT>(val_);
452 case FormatArg::Sign::PLUS_OR_MINUS:
455 case FormatArg::Sign::SPACE_OR_MINUS:
467 arg.enforce(arg.sign == FormatArg::Sign::DEFAULT,
468 "sign specifications not allowed for unsigned values");
472 // #x: 0x prefix + 16 bytes = 18 bytes
473 // #o: 0 prefix + 22 bytes = 23 bytes
474 // #b: 0b prefix + 64 bytes = 65 bytes
475 // ,d: 26 bytes (including thousands separators!)
477 // + 3 for sign and prefix shenanigans (see below)
478 constexpr size_t valBufSize = 69;
479 char valBuf[valBufSize];
480 char* valBufBegin = nullptr;
481 char* valBufEnd = nullptr;
484 switch (presentation) {
486 arg.enforce(!arg.basePrefix,
487 "base prefix not allowed with '", presentation,
490 arg.enforce(!arg.thousandsSeparator,
491 "cannot use ',' with the '", presentation,
494 valBufBegin = valBuf + 3; // room for sign and base prefix
496 char valBuf2[valBufSize];
497 snprintf(valBuf2, valBufSize, "%ju", static_cast<uintmax_t>(uval));
498 int len = GetNumberFormat(
504 (int)((valBuf + valBufSize) - valBufBegin)
506 #elif defined(__ANDROID__)
507 int len = snprintf(valBufBegin, (valBuf + valBufSize) - valBufBegin,
508 "%" PRIuMAX, static_cast<uintmax_t>(uval));
510 int len = snprintf(valBufBegin, (valBuf + valBufSize) - valBufBegin,
511 "%'ju", static_cast<uintmax_t>(uval));
513 // valBufSize should always be big enough, so this should never
515 assert(len < valBuf + valBufSize - valBufBegin);
516 valBufEnd = valBufBegin + len;
520 arg.enforce(!arg.basePrefix,
521 "base prefix not allowed with '", presentation,
523 valBufBegin = valBuf + 3; // room for sign and base prefix
525 // Use uintToBuffer, faster than sprintf
526 valBufEnd = valBufBegin + uint64ToBufferUnsafe(uval, valBufBegin);
527 if (arg.thousandsSeparator) {
528 detail::insertThousandsGroupingUnsafe(valBufBegin, &valBufEnd);
532 arg.enforce(!arg.basePrefix,
533 "base prefix not allowed with '", presentation,
535 arg.enforce(!arg.thousandsSeparator,
536 "thousands separator (',') not allowed with '",
537 presentation, "' specifier");
538 valBufBegin = valBuf + 3;
539 *valBufBegin = static_cast<char>(uval);
540 valBufEnd = valBufBegin + 1;
544 arg.enforce(!arg.thousandsSeparator,
545 "thousands separator (',') not allowed with '",
546 presentation, "' specifier");
547 valBufEnd = valBuf + valBufSize - 1;
548 valBufBegin = valBuf + detail::uintToOctal(valBuf, valBufSize - 1, uval);
549 if (arg.basePrefix) {
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::uintToHexLower(valBuf, valBufSize - 1,
561 if (arg.basePrefix) {
562 *--valBufBegin = 'x';
563 *--valBufBegin = '0';
568 arg.enforce(!arg.thousandsSeparator,
569 "thousands separator (',') not allowed with '",
570 presentation, "' specifier");
571 valBufEnd = valBuf + valBufSize - 1;
572 valBufBegin = valBuf + detail::uintToHexUpper(valBuf, valBufSize - 1,
574 if (arg.basePrefix) {
575 *--valBufBegin = 'X';
576 *--valBufBegin = '0';
582 arg.enforce(!arg.thousandsSeparator,
583 "thousands separator (',') not allowed with '",
584 presentation, "' specifier");
585 valBufEnd = valBuf + valBufSize - 1;
586 valBufBegin = valBuf + detail::uintToBinary(valBuf, valBufSize - 1,
588 if (arg.basePrefix) {
589 *--valBufBegin = presentation; // 0b or 0B
590 *--valBufBegin = '0';
595 arg.error("invalid specifier '", presentation, "'");
599 *--valBufBegin = sign;
603 format_value::formatNumber(StringPiece(valBufBegin, valBufEnd), prefixLen,
613 class FormatValue<bool> {
615 explicit FormatValue(bool val) : val_(val) { }
617 template <class FormatCallback>
618 void format(FormatArg& arg, FormatCallback& cb) const {
619 if (arg.presentation == FormatArg::kDefaultPresentation) {
620 arg.validate(FormatArg::Type::OTHER);
621 format_value::formatString(val_ ? "true" : "false", arg, cb);
623 FormatValue<int>(val_).format(arg, cb);
633 class FormatValue<double> {
635 explicit FormatValue(double val) : val_(val) { }
637 template <class FormatCallback>
638 void format(FormatArg& arg, FormatCallback& cb) const {
641 formatHelper(piece, prefixLen, arg);
642 format_value::formatNumber(piece, prefixLen, arg, cb);
646 void formatHelper(fbstring& piece, int& prefixLen, FormatArg& arg) const;
651 // float (defer to double)
653 class FormatValue<float> {
655 explicit FormatValue(float val) : val_(val) { }
657 template <class FormatCallback>
658 void format(FormatArg& arg, FormatCallback& cb) const {
659 FormatValue<double>(val_).format(arg, cb);
666 // Sring-y types (implicitly convertible to StringPiece, except char*)
669 T, typename std::enable_if<
670 (!std::is_pointer<T>::value ||
671 !std::is_same<char, typename std::decay<
672 typename std::remove_pointer<T>::type>::type>::value) &&
673 std::is_convertible<T, StringPiece>::value>::type>
676 explicit FormatValue(StringPiece val) : val_(val) { }
678 template <class FormatCallback>
679 void format(FormatArg& arg, FormatCallback& cb) const {
680 if (arg.keyEmpty()) {
681 arg.validate(FormatArg::Type::OTHER);
682 arg.enforce(arg.presentation == FormatArg::kDefaultPresentation ||
683 arg.presentation == 's',
684 "invalid specifier '", arg.presentation, "'");
685 format_value::formatString(val_, arg, cb);
687 FormatValue<char>(val_.at(arg.splitIntKey())).format(arg, cb);
697 class FormatValue<std::nullptr_t> {
699 explicit FormatValue(std::nullptr_t) { }
701 template <class FormatCallback>
702 void format(FormatArg& arg, FormatCallback& cb) const {
703 arg.validate(FormatArg::Type::OTHER);
704 arg.enforce(arg.presentation == FormatArg::kDefaultPresentation,
705 "invalid specifier '", arg.presentation, "'");
706 format_value::formatString("(null)", arg, cb);
710 // Partial specialization of FormatValue for char*
714 typename std::enable_if<
715 std::is_same<char, typename std::decay<T>::type>::value>::type>
718 explicit FormatValue(T* val) : val_(val) { }
720 template <class FormatCallback>
721 void format(FormatArg& arg, FormatCallback& cb) const {
722 if (arg.keyEmpty()) {
724 FormatValue<std::nullptr_t>(nullptr).format(arg, cb);
726 FormatValue<StringPiece>(val_).format(arg, cb);
729 FormatValue<typename std::decay<T>::type>(
730 val_[arg.splitIntKey()]).format(arg, cb);
738 // Partial specialization of FormatValue for void*
742 typename std::enable_if<
743 std::is_same<void, typename std::decay<T>::type>::value>::type>
746 explicit FormatValue(T* val) : val_(val) { }
748 template <class FormatCallback>
749 void format(FormatArg& arg, FormatCallback& cb) const {
751 FormatValue<std::nullptr_t>(nullptr).format(arg, cb);
753 // Print as a pointer, in hex.
754 arg.validate(FormatArg::Type::OTHER);
755 arg.enforce(arg.presentation == FormatArg::kDefaultPresentation,
756 "invalid specifier '", arg.presentation, "'");
757 arg.basePrefix = true;
758 arg.presentation = 'x';
759 if (arg.align == FormatArg::Align::DEFAULT) {
760 arg.align = FormatArg::Align::LEFT;
762 FormatValue<uintptr_t>(
763 reinterpret_cast<uintptr_t>(val_)).doFormat(arg, cb);
771 template <class T, class = void>
772 class TryFormatValue {
774 template <class FormatCallback>
775 static void formatOrFail(T& /* value */,
777 FormatCallback& /* cb */) {
778 arg.error("No formatter available for this type");
783 class TryFormatValue<
785 typename std::enable_if<
786 0 < sizeof(FormatValue<typename std::decay<T>::type>)>::type>
789 template <class FormatCallback>
790 static void formatOrFail(T& value, FormatArg& arg, FormatCallback& cb) {
791 FormatValue<typename std::decay<T>::type>(value).format(arg, cb);
795 // Partial specialization of FormatValue for other pointers
799 typename std::enable_if<
800 !std::is_same<char, typename std::decay<T>::type>::value &&
801 !std::is_same<void, typename std::decay<T>::type>::value>::type>
804 explicit FormatValue(T* val) : val_(val) { }
806 template <class FormatCallback>
807 void format(FormatArg& arg, FormatCallback& cb) const {
808 if (arg.keyEmpty()) {
809 FormatValue<void*>((void*)val_).format(arg, cb);
811 TryFormatValue<T>::formatOrFail(val_[arg.splitIntKey()], arg, cb);
821 template <class T, size_t N>
822 struct IndexableTraits<std::array<T, N>>
823 : public IndexableTraitsSeq<std::array<T, N>> {
827 template <class T, class A>
828 struct IndexableTraits<std::vector<T, A>>
829 : public IndexableTraitsSeq<std::vector<T, A>> {
833 template <class T, class A>
834 struct IndexableTraits<std::deque<T, A>>
835 : public IndexableTraitsSeq<std::deque<T, A>> {
838 // std::map with integral keys
839 template <class K, class T, class C, class A>
840 struct IndexableTraits<
841 std::map<K, T, C, A>,
842 typename std::enable_if<std::is_integral<K>::value>::type>
843 : public IndexableTraitsAssoc<std::map<K, T, C, A>> {
846 // std::unordered_map with integral keys
847 template <class K, class T, class H, class E, class A>
848 struct IndexableTraits<
849 std::unordered_map<K, T, H, E, A>,
850 typename std::enable_if<std::is_integral<K>::value>::type>
851 : public IndexableTraitsAssoc<std::unordered_map<K, T, H, E, A>> {
854 } // namespace detail
856 // Partial specialization of FormatValue for integer-indexable containers
860 typename detail::IndexableTraits<T>::enabled> {
862 explicit FormatValue(const T& val) : val_(val) { }
864 template <class FormatCallback>
865 void format(FormatArg& arg, FormatCallback& cb) const {
866 FormatValue<typename std::decay<
867 typename detail::IndexableTraits<T>::value_type>::type>(
868 detail::IndexableTraits<T>::at(
869 val_, arg.splitIntKey())).format(arg, cb);
876 template <class Container, class Value>
878 detail::DefaultValueWrapper<Container, Value>,
879 typename detail::IndexableTraits<Container>::enabled> {
881 explicit FormatValue(const detail::DefaultValueWrapper<Container, Value>& val)
884 template <class FormatCallback>
885 void format(FormatArg& arg, FormatCallback& cb) const {
886 FormatValue<typename std::decay<
887 typename detail::IndexableTraits<Container>::value_type>::type>(
888 detail::IndexableTraits<Container>::at(
891 val_.defaultValue)).format(arg, cb);
895 const detail::DefaultValueWrapper<Container, Value>& val_;
900 // Define enabled, key_type, convert from StringPiece to the key types
902 template <class T> struct KeyFromStringPiece;
906 struct KeyFromStringPiece<std::string> : public FormatTraitsBase {
907 typedef std::string key_type;
908 static std::string convert(StringPiece s) {
911 typedef void enabled;
916 struct KeyFromStringPiece<fbstring> : public FormatTraitsBase {
917 typedef fbstring key_type;
918 static fbstring convert(StringPiece s) {
919 return s.toFbstring();
925 struct KeyFromStringPiece<StringPiece> : public FormatTraitsBase {
926 typedef StringPiece key_type;
927 static StringPiece convert(StringPiece s) {
932 // Base class for associative types keyed by strings
933 template <class T> struct KeyableTraitsAssoc : public FormatTraitsBase {
934 typedef typename T::key_type key_type;
935 typedef typename T::value_type::second_type value_type;
936 static const value_type& at(const T& map, StringPiece key) {
937 return map.at(KeyFromStringPiece<key_type>::convert(key));
939 static const value_type& at(const T& map, StringPiece key,
940 const value_type& dflt) {
941 auto pos = map.find(KeyFromStringPiece<key_type>::convert(key));
942 return pos != map.end() ? pos->second : dflt;
946 // Define enabled, key_type, value_type, at() for supported string-keyed
948 template <class T, class Enabled=void> struct KeyableTraits;
950 // std::map with string key
951 template <class K, class T, class C, class A>
952 struct KeyableTraits<
953 std::map<K, T, C, A>,
954 typename KeyFromStringPiece<K>::enabled>
955 : public KeyableTraitsAssoc<std::map<K, T, C, A>> {
958 // std::unordered_map with string key
959 template <class K, class T, class H, class E, class A>
960 struct KeyableTraits<
961 std::unordered_map<K, T, H, E, A>,
962 typename KeyFromStringPiece<K>::enabled>
963 : public KeyableTraitsAssoc<std::unordered_map<K, T, H, E, A>> {
966 } // namespace detail
968 // Partial specialization of FormatValue for string-keyed containers
972 typename detail::KeyableTraits<T>::enabled> {
974 explicit FormatValue(const T& val) : val_(val) { }
976 template <class FormatCallback>
977 void format(FormatArg& arg, FormatCallback& cb) const {
978 FormatValue<typename std::decay<
979 typename detail::KeyableTraits<T>::value_type>::type>(
980 detail::KeyableTraits<T>::at(
981 val_, arg.splitKey())).format(arg, cb);
988 template <class Container, class Value>
990 detail::DefaultValueWrapper<Container, Value>,
991 typename detail::KeyableTraits<Container>::enabled> {
993 explicit FormatValue(const detail::DefaultValueWrapper<Container, Value>& val)
996 template <class FormatCallback>
997 void format(FormatArg& arg, FormatCallback& cb) const {
998 FormatValue<typename std::decay<
999 typename detail::KeyableTraits<Container>::value_type>::type>(
1000 detail::KeyableTraits<Container>::at(
1003 val_.defaultValue)).format(arg, cb);
1007 const detail::DefaultValueWrapper<Container, Value>& val_;
1010 // Partial specialization of FormatValue for pairs
1011 template <class A, class B>
1012 class FormatValue<std::pair<A, B>> {
1014 explicit FormatValue(const std::pair<A, B>& val) : val_(val) { }
1016 template <class FormatCallback>
1017 void format(FormatArg& arg, FormatCallback& cb) const {
1018 int key = arg.splitIntKey();
1021 FormatValue<typename std::decay<A>::type>(val_.first).format(arg, cb);
1024 FormatValue<typename std::decay<B>::type>(val_.second).format(arg, cb);
1027 arg.error("invalid index for pair");
1032 const std::pair<A, B>& val_;
1035 // Partial specialization of FormatValue for tuples
1036 template <class... Args>
1037 class FormatValue<std::tuple<Args...>> {
1038 typedef std::tuple<Args...> Tuple;
1040 explicit FormatValue(const Tuple& val) : val_(val) { }
1042 template <class FormatCallback>
1043 void format(FormatArg& arg, FormatCallback& cb) const {
1044 int key = arg.splitIntKey();
1045 arg.enforce(key >= 0, "tuple index must be non-negative");
1046 doFormat(key, arg, cb);
1050 static constexpr size_t valueCount = std::tuple_size<Tuple>::value;
1052 template <size_t K, class Callback>
1053 typename std::enable_if<K == valueCount>::type doFormatFrom(
1054 size_t i, FormatArg& arg, Callback& /* cb */) const {
1055 arg.enforce("tuple index out of range, max=", i);
1058 template <size_t K, class Callback>
1059 typename std::enable_if<(K < valueCount)>::type
1060 doFormatFrom(size_t i, FormatArg& arg, Callback& cb) const {
1062 FormatValue<typename std::decay<
1063 typename std::tuple_element<K, Tuple>::type>::type>(
1064 std::get<K>(val_)).format(arg, cb);
1066 doFormatFrom<K+1>(i, arg, cb);
1070 template <class Callback>
1071 void doFormat(size_t i, FormatArg& arg, Callback& cb) const {
1072 return doFormatFrom<0>(i, arg, cb);
1078 // Partial specialization of FormatValue for nested Formatters
1079 template <bool containerMode, class... Args,
1080 template <bool, class...> class F>
1081 class FormatValue<F<containerMode, Args...>,
1082 typename std::enable_if<detail::IsFormatter<
1083 F<containerMode, Args...>>::value>::type> {
1084 typedef typename F<containerMode, Args...>::BaseType FormatterValue;
1087 explicit FormatValue(const FormatterValue& f) : f_(f) { }
1089 template <class FormatCallback>
1090 void format(FormatArg& arg, FormatCallback& cb) const {
1091 format_value::formatFormatter(f_, arg, cb);
1094 const FormatterValue& f_;
1098 * Formatter objects can be appended to strings, and therefore they're
1099 * compatible with folly::toAppend and folly::to.
1101 template <class Tgt, class Derived, bool containerMode, class... Args>
1102 typename std::enable_if<IsSomeString<Tgt>::value>::type toAppend(
1103 const BaseFormatter<Derived, containerMode, Args...>& value, Tgt* result) {
1104 value.appendTo(*result);
1107 } // namespace folly
1109 #pragma GCC diagnostic pop