17 #ifndef FOLLY_FORMAT_H_ 18 #error This file may only be included from Format.h. 25 #include <unordered_map> 48 extern const std::array<std::array<char, 3>, 512>
formatOctal;
49 extern const std::array<std::array<char, 8>, 256>
formatBinary;
69 std::array<std::array<char, 2>, 256>
const& repr) {
72 for (; !less_than<unsigned, 256>(
v); v >>= 7, v >>= 1) {
75 buffer[bufLen] = repr[
b][0];
76 buffer[bufLen + 1] = repr[
b][1];
78 buffer[--bufLen] = repr[
v][1];
80 buffer[--bufLen] = repr[
v][0];
91 return uintToHex(buffer, bufLen, v, formatHexLower);
100 return uintToHex(buffer, bufLen, v, formatHexUpper);
111 template <
class U
int>
116 for (; !less_than<unsigned, 512>(
v); v >>= 7, v >>= 2) {
119 buffer[bufLen] = repr[
b][0];
120 buffer[bufLen + 1] = repr[
b][1];
121 buffer[bufLen + 2] = repr[
b][2];
123 buffer[--bufLen] = repr[
v][2];
125 buffer[--bufLen] = repr[
v][1];
128 buffer[--bufLen] = repr[
v][0];
141 template <
class U
int>
145 buffer[--bufLen] =
'0';
148 for (;
v; v >>= 7, v >>= 1) {
151 memcpy(buffer + bufLen, &(repr[
b][0]), 8);
153 while (buffer[bufLen] ==
'0') {
161 template <
class Derived,
bool containerMode,
class...
Args>
165 : str_(str), values_(std::forward<Args>(args)...) {}
167 template <
class Derived,
bool containerMode,
class...
Args>
168 template <
class Output>
178 auto q =
static_cast<const char*
>(memchr(p,
'}',
size_t(
end - p)));
187 if (p ==
end || *p !=
'}') {
188 throw_exception<BadFormatArg>(
189 "folly::format: single '}' in format string");
195 auto p = str_.begin();
196 auto end = str_.end();
199 bool hasDefaultArgIndex =
false;
200 bool hasExplicitArgIndex =
false;
202 auto q =
static_cast<const char*
>(memchr(p,
'{',
size_t(
end - p)));
211 throw_exception<BadFormatArg>(
212 "folly::format: '}' at end of format string");
223 q =
static_cast<const char*
>(memchr(p,
'}',
size_t(
end - p)));
225 throw_exception<BadFormatArg>(
"folly::format: missing ending '}'");
231 auto piece = arg.splitKey<
true>();
234 arg.width != FormatArg::kDynamicWidth,
235 "dynamic field width not supported in vformat()");
237 arg.setNextIntKey(nextArg++);
238 hasDefaultArgIndex =
true;
240 arg.setNextKey(piece);
241 hasExplicitArgIndex =
true;
245 if (arg.width == FormatArg::kDynamicWidth) {
247 arg.widthIndex == FormatArg::kNoIndex,
248 "cannot provide width arg index without value arg index");
249 int sizeArg = nextArg++;
250 arg.width = asDerived().getSizeArg(
size_t(sizeArg), arg);
253 argIndex = nextArg++;
254 hasDefaultArgIndex =
true;
256 if (arg.width == FormatArg::kDynamicWidth) {
258 arg.widthIndex != FormatArg::kNoIndex,
259 "cannot provide value arg index without width arg index");
260 arg.width = asDerived().getSizeArg(
size_t(arg.widthIndex), arg);
264 argIndex = to<int>(piece);
265 }
catch (
const std::out_of_range&) {
266 arg.error(
"argument index must be integer");
268 arg.enforce(argIndex >= 0,
"argument index must be non-negative");
269 hasExplicitArgIndex =
true;
273 if (hasDefaultArgIndex && hasExplicitArgIndex) {
274 throw_exception<BadFormatArg>(
275 "folly::format: may not have both default and explicit arg indexes");
278 asDerived().doFormat(
size_t(argIndex), arg, out);
282 template <
class Derived,
bool containerMode,
class...
Args>
287 size_t n = fwrite(sp.data(), 1, sp.size(), fp);
295 namespace format_value {
297 template <
class FormatCallback>
299 if (arg.
width != FormatArg::kDefaultWidth && arg.
width < 0) {
300 throw_exception<BadFormatArg>(
"folly::format: invalid width");
303 throw_exception<BadFormatArg>(
"folly::format: invalid precision");
306 if (arg.
precision != FormatArg::kDefaultPrecision &&
311 constexpr
int padBufSize = 128;
312 char padBuf[padBufSize];
315 auto pad = [&padBuf, &cb, padBufSize](
int chars) {
317 int n =
std::min(chars, padBufSize);
323 int padRemaining = 0;
324 if (arg.
width != FormatArg::kDefaultWidth &&
325 val.
size() <
static_cast<size_t>(arg.
width)) {
326 char fill = arg.
fill == FormatArg::kDefaultFill ?
' ' : arg.
fill;
327 int padChars =
static_cast<int>(arg.
width - val.
size());
328 memset(padBuf, fill,
size_t(
std::min(padBufSize, padChars)));
331 case FormatArg::Align::DEFAULT:
332 case FormatArg::Align::LEFT:
333 padRemaining = padChars;
335 case FormatArg::Align::CENTER:
337 padRemaining = padChars - padChars / 2;
339 case FormatArg::Align::RIGHT:
340 case FormatArg::Align::PAD_AFTER_SIGN:
356 template <
class FormatCallback>
361 FormatCallback& cb) {
363 arg.
precision = FormatArg::kDefaultPrecision;
364 if (arg.
align == FormatArg::Align::DEFAULT) {
365 arg.
align = FormatArg::Align::RIGHT;
366 }
else if (prefixLen && arg.
align == FormatArg::Align::PAD_AFTER_SIGN) {
368 cb(val.
subpiece(0,
size_t(prefixLen)));
369 val.
advance(
size_t(prefixLen));
376 class FormatCallback,
383 FormatCallback& cb) {
384 if (arg.
width == FormatArg::kDefaultWidth &&
385 arg.
precision == FormatArg::kDefaultPrecision) {
389 arg.
align != FormatArg::Align::LEFT &&
390 arg.
align != FormatArg::Align::DEFAULT) {
396 int sz =
static_cast<int>(sp.size());
397 if (arg.
precision != FormatArg::kDefaultPrecision) {
399 sp.reset(sp.data(), size_t(sz));
404 if (arg.
width != FormatArg::kDefaultWidth) {
410 if (arg.
width != FormatArg::kDefaultWidth && arg.
width != 0) {
425 typename
std::enable_if<
426 std::is_integral<T>::value && !std::is_same<T, bool>::value>
::type> {
434 template <
class FormatCallback>
436 arg.
validate(FormatArg::Type::INTEGER);
440 template <
class FormatCallback>
443 if (presentation == FormatArg::kDefaultPresentation) {
454 uval = UT(-static_cast<UT>(val_));
457 uval =
static_cast<UT
>(val_);
459 case FormatArg::Sign::PLUS_OR_MINUS:
462 case FormatArg::Sign::SPACE_OR_MINUS:
471 uval =
static_cast<UT
>(val_);
475 arg.
sign == FormatArg::Sign::DEFAULT,
476 "sign specifications not allowed for unsigned values");
486 constexpr
size_t valBufSize = 69;
487 char valBuf[valBufSize];
488 char* valBufBegin =
nullptr;
489 char* valBufEnd =
nullptr;
492 switch (presentation) {
496 "base prefix not allowed with '",
502 "cannot use ',' with the '",
506 valBufBegin = valBuf + 3;
507 #if defined(__ANDROID__) 510 (valBuf + valBufSize) - valBufBegin,
512 static_cast<uintmax_t>(uval));
516 size_t((valBuf + valBufSize) - valBufBegin),
518 static_cast<uintmax_t>(uval));
522 assert(len < valBuf + valBufSize - valBufBegin);
523 valBufEnd = valBufBegin + len;
529 "base prefix not allowed with '",
532 valBufBegin = valBuf + 3;
543 "base prefix not allowed with '",
548 "thousands separator (',') not allowed with '",
551 valBufBegin = valBuf + 3;
552 *valBufBegin =
static_cast<char>(uval);
553 valBufEnd = valBufBegin + 1;
559 "thousands separator (',') not allowed with '",
562 valBufEnd = valBuf + valBufSize - 1;
566 *--valBufBegin =
'0';
573 "thousands separator (',') not allowed with '",
576 valBufEnd = valBuf + valBufSize - 1;
580 *--valBufBegin =
'x';
581 *--valBufBegin =
'0';
588 "thousands separator (',') not allowed with '",
591 valBufEnd = valBuf + valBufSize - 1;
595 *--valBufBegin =
'X';
596 *--valBufBegin =
'0';
604 "thousands separator (',') not allowed with '",
607 valBufEnd = valBuf + valBufSize - 1;
611 *--valBufBegin = presentation;
612 *--valBufBegin =
'0';
617 arg.
error(
"invalid specifier '", presentation,
"'");
621 *--valBufBegin = sign;
626 StringPiece(valBufBegin, valBufEnd), prefixLen, arg, cb);
639 template <
class FormatCallback>
641 if (arg.
presentation == FormatArg::kDefaultPresentation) {
642 arg.
validate(FormatArg::Type::OTHER);
659 template <
class FormatCallback>
663 formatHelper(piece, prefixLen, arg);
679 template <
class FormatCallback>
692 typename
std::enable_if<
693 (!std::is_pointer<T>::value ||
696 typename std::decay<typename std::remove_pointer<T>::type>::type>::
698 std::is_convertible<T, StringPiece>::value>
::type> {
702 template <
class FormatCallback>
705 arg.
validate(FormatArg::Type::OTHER);
709 "invalid specifier '",
728 template <
class FormatCallback>
730 arg.
validate(FormatArg::Type::OTHER);
733 "invalid specifier '",
744 typename std::enable_if<
749 template <
class FormatCallback>
771 typename std::enable_if<
776 template <
class FormatCallback>
782 arg.
validate(FormatArg::Type::OTHER);
785 "invalid specifier '",
790 if (arg.
align == FormatArg::Align::DEFAULT) {
791 arg.
align = FormatArg::Align::LEFT;
802 template <
class T,
class =
void>
803 class TryFormatValue {
805 template <
class FormatCallback>
807 formatOrFail(T& ,
FormatArg& arg, FormatCallback& ) {
808 arg.
error(
"No formatter available for this type");
813 class TryFormatValue<
815 typename std::enable_if<
816 0 < sizeof(FormatValue<typename std::decay<T>::type>)>::type> {
818 template <
class FormatCallback>
819 static void formatOrFail(T&
value,
FormatArg& arg, FormatCallback& cb) {
828 typename std::enable_if<
834 template <
class FormatCallback>
839 TryFormatValue<T>::formatOrFail(val_[arg.
splitIntKey()], arg, cb);
850 template <
class T,
size_t N>
855 template <
class T,
class A>
860 template <
class T,
class A>
865 template <
class K,
class T,
class C,
class A>
867 std::
map<K, T, C, A>,
868 typename std::enable_if<std::is_integral<K>::value>
::type>
872 template <
class K,
class T,
class H,
class E,
class A>
874 std::unordered_map<K, T, H, E, A>,
875 typename std::enable_if<std::is_integral<K>::value>
::type>
886 template <
class FormatCallback>
898 template <
class Container,
class Value>
906 template <
class FormatCallback>
911 val_.container, arg.
splitIntKey(), val_.defaultValue))
924 struct KeyFromStringPiece;
933 typedef void enabled;
939 typedef fbstring key_type;
941 return s.
to<fbstring>();
948 typedef StringPiece key_type;
949 static StringPiece convert(StringPiece
s) {
957 typedef typename T::key_type key_type;
958 typedef typename T::value_type::second_type value_type;
959 static const value_type& at(
const T&
map, StringPiece key) {
960 if (
auto ptr =
get_ptr(map, KeyFromStringPiece<key_type>::convert(key))) {
963 throw_exception<FormatKeyNotFoundException>(key);
965 static const value_type&
966 at(
const T& map, StringPiece key,
const value_type& dflt) {
967 auto pos = map.find(KeyFromStringPiece<key_type>::convert(key));
968 return pos != map.end() ? pos->second : dflt;
974 template <
class T,
class Enabled =
void>
975 struct KeyableTraits;
978 template <
class K,
class T,
class C,
class A>
979 struct KeyableTraits<
980 std::
map<K, T, C, A>,
981 typename KeyFromStringPiece<K>::enabled>
982 :
public KeyableTraitsAssoc<std::map<K, T, C, A>> {};
985 template <
class K,
class T,
class H,
class E,
class A>
986 struct KeyableTraits<
987 std::unordered_map<K, T, H, E, A>,
988 typename KeyFromStringPiece<K>::enabled>
989 :
public KeyableTraitsAssoc<std::unordered_map<K, T, H, E, A>> {};
995 class FormatValue<T, typename detail::KeyableTraits<T>::enabled> {
999 template <
class FormatCallback>
1002 typename detail::KeyableTraits<T>::value_type>
::type>(
1003 detail::KeyableTraits<T>::at(val_, arg.
splitKey()))
1011 template <
class Container,
class Value>
1014 typename detail::KeyableTraits<Container>::enabled> {
1019 template <
class FormatCallback>
1022 typename detail::KeyableTraits<Container>::value_type>
::type>(
1023 detail::KeyableTraits<Container>::at(
1024 val_.container, arg.
splitKey(), val_.defaultValue))
1033 template <
class A,
class B>
1038 template <
class FormatCallback>
1049 arg.
error(
"invalid index for pair");
1054 const std::pair<A, B>& val_;
1058 template <
class...
Args>
1060 typedef std::tuple<
Args...> Tuple;
1065 template <
class FormatCallback>
1068 arg.
enforce(key >= 0,
"tuple index must be non-negative");
1069 doFormat(
size_t(key), arg, cb);
1075 template <
size_t K,
class Callback>
1077 doFormatFrom(
size_t i,
FormatArg& arg, Callback& )
const {
1078 arg.
error(
"tuple index out of range, max=", i);
1081 template <
size_t K,
class Callback>
1083 doFormatFrom(
size_t i,
FormatArg& arg, Callback& cb)
const {
1089 doFormatFrom<K + 1>(
i, arg, cb);
1093 template <
class Callback>
1094 void doFormat(
size_t i,
FormatArg& arg, Callback& cb)
const {
1095 return doFormatFrom<0>(
i, arg, cb);
1102 template <
bool containerMode,
class...
Args,
template <bool,
class...>
class F>
1104 F<containerMode, Args...>,
1105 typename std::enable_if<
1106 detail::IsFormatter<F<containerMode, Args...>>::value>
::type> {
1107 typedef typename F<containerMode, Args...>::BaseType FormatterValue;
1110 explicit FormatValue(
const FormatterValue&
f) : f_(f) {}
1112 template <
class FormatCallback>
1118 const FormatterValue& f_;
1125 template <
class Tgt,
class Derived,
bool containerMode,
class... Args>
const Map::mapped_type * get_ptr(const Map &map, const Key &key)
std::vector< uint8_t > buffer(kBufferSize+16)
#define FOLLY_GNU_DISABLE_WARNING(warningName)
#define FOLLY_POP_WARNING
uint32_t uint64ToBufferUnsafe(uint64_t v, char *const buffer)
#define FOLLY_PUSH_WARNING
const std::array< std::array< char, 3 >, 512 > formatOctal
size_t uintToBinary(char *buffer, size_t bufLen, Uint v)
size_t uintToHexLower(char *buffer, size_t bufLen, Uint v)
void advance(size_type n)
constexpr size_type size() const
size_t uintToOctal(char *buffer, size_t bufLen, Uint v)
internal::ArgsMatcher< InnerMatcher > Args(const InnerMatcher &matcher)
—— Concurrent Priority Queue Implementation ——
void writeTo(FILE *fp, const BaseFormatter< Derived, containerMode, Args... > &formatter)
const std::array< std::array< char, 8 >, 256 > formatBinary
const size_t kMaxHexLength
auto end(TestAdlIterable &instance)
constexpr Iter data() const
Range subpiece(size_type first, size_type length=npos) const
const std::array< std::array< char, 2 >, 256 > formatHexUpper
size_t uintToHex(char *buffer, size_t bufLen, Uint v, std::array< std::array< char, 2 >, 256 > const &repr)
const std::array< std::array< char, 2 >, 256 > formatHexLower
static const char *const value
constexpr std::enable_if_t< std::is_constructible< Tgt, Iter const &, size_type >::value, Tgt > to(Args &&...args) const noexcept(std::is_nothrow_constructible< Tgt, Iter const &, size_type, Args &&... >::value)
void toAppend(char value, Tgt *result)
void insertThousandsGroupingUnsafe(char *start_buffer, char **end_buffer)
std::string toString() const
constexpr bool is_negative(T x)
size_t uintToHexUpper(char *buffer, size_t bufLen, Uint v)
Formatter< false, Args... > format(StringPiece fmt, Args &&...args)
void throwSystemError(Args &&...args)
const size_t kMaxBinaryLength
Range< const char * > StringPiece
GMockOutputTest ExpectedCall FILE
void reset(Iter start, size_type size)
const size_t kMaxOctalLength