From 9bb213e9200d5742d3868b217a7010d536414d96 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Thu, 25 Aug 2016 08:38:07 -0700 Subject: [PATCH 001/340] FormatError -> format_error --- fmt/format.cc | 6 +- fmt/format.h | 50 ++++---- fmt/printf.h | 12 +- fmt/time.h | 2 +- test/format-test.cc | 274 +++++++++++++++++++++---------------------- test/ostream-test.cc | 14 +-- test/printf-test.cc | 52 ++++---- 7 files changed, 205 insertions(+), 205 deletions(-) diff --git a/fmt/format.cc b/fmt/format.cc index 9f9d6ae1..7fd0308e 100644 --- a/fmt/format.cc +++ b/fmt/format.cc @@ -82,7 +82,7 @@ static inline fmt::internal::Null<> strerror_s(char *, std::size_t, ...) { namespace fmt { FMT_FUNC internal::RuntimeError::~RuntimeError() throw() {} -FMT_FUNC FormatError::~FormatError() throw() {} +FMT_FUNC format_error::~format_error() throw() {} FMT_FUNC SystemError::~SystemError() throw() {} namespace { @@ -296,10 +296,10 @@ const uint64_t internal::BasicData::POWERS_OF_10_64[] = { FMT_FUNC void internal::report_unknown_type(char code, const char *type) { (void)type; if (std::isprint(static_cast(code))) { - FMT_THROW(FormatError( + FMT_THROW(format_error( format("unknown format code '{}' for {}", code, type))); } - FMT_THROW(FormatError( + FMT_THROW(format_error( format("unknown format code '\\x{:02x}' for {}", static_cast(code), type))); } diff --git a/fmt/format.h b/fmt/format.h index 65ad328b..145de3a1 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -535,11 +535,11 @@ typedef BasicCStringRef CStringRef; typedef BasicCStringRef WCStringRef; /** A formatting error such as invalid format string. */ -class FormatError : public std::runtime_error { +class format_error : public std::runtime_error { public: - explicit FormatError(CStringRef message) + explicit format_error(CStringRef message) : std::runtime_error(message.c_str()) {} - ~FormatError() throw(); + ~format_error() throw(); }; namespace internal { @@ -1883,7 +1883,7 @@ class ArgFormatterBase : public ArgVisitor { return; } if (spec_.align_ == ALIGN_NUMERIC || spec_.flags_ != 0) - FMT_THROW(FormatError("invalid format specifier for char")); + FMT_THROW(format_error("invalid format specifier for char")); typedef typename BasicWriter::CharPtr CharPtr; Char fill = internal::CharTraits::cast(spec_.fill()); CharPtr out = CharPtr(); @@ -2647,7 +2647,7 @@ void BasicWriter::write_str( std::size_t str_size = s.size; if (str_size == 0) { if (!str_value) { - FMT_THROW(FormatError("string pointer is null")); + FMT_THROW(format_error("string pointer is null")); } } std::size_t precision = static_cast(spec.precision_); @@ -3496,7 +3496,7 @@ unsigned parse_nonnegative_int(const Char *&s) { // Convert to unsigned to prevent a warning. unsigned max_int = (std::numeric_limits::max)(); if (value > max_int) - FMT_THROW(FormatError("number is too big")); + FMT_THROW(format_error("number is too big")); return value; } @@ -3504,7 +3504,7 @@ inline void require_numeric_argument(const Arg &arg, char spec) { if (arg.type > Arg::LAST_NUMERIC_TYPE) { std::string message = fmt::format("format specifier '{}' requires numeric argument", spec); - FMT_THROW(fmt::FormatError(message)); + FMT_THROW(fmt::format_error(message)); } } @@ -3513,7 +3513,7 @@ void check_sign(const Char *&s, const Arg &arg) { char sign = static_cast(*s); require_numeric_argument(arg, sign); if (arg.type == Arg::UINT || arg.type == Arg::ULONG_LONG) { - FMT_THROW(FormatError(fmt::format( + FMT_THROW(format_error(fmt::format( "format specifier '{}' requires signed argument", sign))); } ++s; @@ -3539,7 +3539,7 @@ inline internal::Arg BasicFormatter::parse_arg_index(const Char *&s) { internal::Arg arg = *s < '0' || *s > '9' ? next_arg(error) : get_arg(internal::parse_nonnegative_int(s), error); if (error) { - FMT_THROW(FormatError( + FMT_THROW(format_error( *s != '}' && *s != ':' ? "invalid format string" : error)); } return arg; @@ -3556,7 +3556,7 @@ inline internal::Arg BasicFormatter::parse_arg_name(const Char *&s) { const char *error = 0; internal::Arg arg = get_arg(BasicStringRef(start, s - start), error); if (error) - FMT_THROW(FormatError(error)); + FMT_THROW(format_error(error)); return arg; } @@ -3595,7 +3595,7 @@ const Char *BasicFormatter::format( if (p != s) { if (c == '}') break; if (c == '{') - FMT_THROW(FormatError("invalid fill character '{'")); + FMT_THROW(format_error("invalid fill character '{'")); s += 2; spec.fill_ = c; } else ++s; @@ -3644,12 +3644,12 @@ const Char *BasicFormatter::format( Arg width_arg = internal::is_name_start(*s) ? parse_arg_name(s) : parse_arg_index(s); if (*s++ != '}') - FMT_THROW(FormatError("invalid format string")); + FMT_THROW(format_error("invalid format string")); ULongLong value = 0; switch (width_arg.type) { case Arg::INT: if (width_arg.int_value < 0) - FMT_THROW(FormatError("negative width")); + FMT_THROW(format_error("negative width")); value = width_arg.int_value; break; case Arg::UINT: @@ -3657,17 +3657,17 @@ const Char *BasicFormatter::format( break; case Arg::LONG_LONG: if (width_arg.long_long_value < 0) - FMT_THROW(FormatError("negative width")); + FMT_THROW(format_error("negative width")); value = width_arg.long_long_value; break; case Arg::ULONG_LONG: value = width_arg.ulong_long_value; break; default: - FMT_THROW(FormatError("width is not integer")); + FMT_THROW(format_error("width is not integer")); } if (value > (std::numeric_limits::max)()) - FMT_THROW(FormatError("number is too big")); + FMT_THROW(format_error("number is too big")); spec.width_ = static_cast(value); } @@ -3682,12 +3682,12 @@ const Char *BasicFormatter::format( Arg precision_arg = internal::is_name_start(*s) ? parse_arg_name(s) : parse_arg_index(s); if (*s++ != '}') - FMT_THROW(FormatError("invalid format string")); + FMT_THROW(format_error("invalid format string")); ULongLong value = 0; switch (precision_arg.type) { case Arg::INT: if (precision_arg.int_value < 0) - FMT_THROW(FormatError("negative precision")); + FMT_THROW(format_error("negative precision")); value = precision_arg.int_value; break; case Arg::UINT: @@ -3695,23 +3695,23 @@ const Char *BasicFormatter::format( break; case Arg::LONG_LONG: if (precision_arg.long_long_value < 0) - FMT_THROW(FormatError("negative precision")); + FMT_THROW(format_error("negative precision")); value = precision_arg.long_long_value; break; case Arg::ULONG_LONG: value = precision_arg.ulong_long_value; break; default: - FMT_THROW(FormatError("precision is not integer")); + FMT_THROW(format_error("precision is not integer")); } if (value > (std::numeric_limits::max)()) - FMT_THROW(FormatError("number is too big")); + FMT_THROW(format_error("number is too big")); spec.precision_ = static_cast(value); } else { - FMT_THROW(FormatError("missing precision specifier")); + FMT_THROW(format_error("missing precision specifier")); } if (arg.type <= Arg::LAST_INTEGER_TYPE || arg.type == Arg::POINTER) { - FMT_THROW(FormatError( + FMT_THROW(format_error( fmt::format("precision not allowed in {} format specifier", arg.type == Arg::POINTER ? "pointer" : "integer"))); } @@ -3723,7 +3723,7 @@ const Char *BasicFormatter::format( } if (*s++ != '}') - FMT_THROW(FormatError("missing '}' in format string")); + FMT_THROW(format_error("missing '}' in format string")); // Format argument. ArgFormatter(*this, spec, s - 1).visit(arg); @@ -3743,7 +3743,7 @@ void BasicFormatter::format(BasicCStringRef format_str) { continue; } if (c == '}') - FMT_THROW(FormatError("unmatched '}' in format string")); + FMT_THROW(format_error("unmatched '}' in format string")); write(writer_, start, s - 1); internal::Arg arg = internal::is_name_start(*s) ? parse_arg_name(s) : parse_arg_index(s); diff --git a/fmt/printf.h b/fmt/printf.h index f0c0b9a2..e83a9976 100644 --- a/fmt/printf.h +++ b/fmt/printf.h @@ -43,13 +43,13 @@ struct IntChecker { class PrecisionHandler : public ArgVisitor { public: void report_unhandled_arg() { - FMT_THROW(FormatError("precision is not integer")); + FMT_THROW(format_error("precision is not integer")); } template int visit_any_int(T value) { if (!IntChecker::is_signed>::fits_in_int(value)) - FMT_THROW(FormatError("number is too big")); + FMT_THROW(format_error("number is too big")); return static_cast(value); } }; @@ -153,7 +153,7 @@ class WidthHandler : public ArgVisitor { explicit WidthHandler(FormatSpec &spec) : spec_(spec) {} void report_unhandled_arg() { - FMT_THROW(FormatError("width is not integer")); + FMT_THROW(format_error("width is not integer")); } template @@ -166,7 +166,7 @@ class WidthHandler : public ArgVisitor { } unsigned int_max = std::numeric_limits::max(); if (width > int_max) - FMT_THROW(FormatError("number is too big")); + FMT_THROW(format_error("number is too big")); return static_cast(width); } }; @@ -345,7 +345,7 @@ internal::Arg PrintfFormatter::get_arg(const Char *s, internal::Arg arg = arg_index == std::numeric_limits::max() ? next_arg(error) : FormatterBase::get_arg(arg_index - 1, error); if (error) - FMT_THROW(FormatError(!*s ? "invalid format string" : error)); + FMT_THROW(format_error(!*s ? "invalid format string" : error)); return arg; } @@ -460,7 +460,7 @@ void PrintfFormatter::format(BasicCStringRef format_str) { // Parse type. if (!*s) - FMT_THROW(FormatError("invalid format string")); + FMT_THROW(format_error("invalid format string")); spec.type_ = static_cast(*s++); if (arg.type <= Arg::LAST_INTEGER_TYPE) { // Normalize type. diff --git a/fmt/time.h b/fmt/time.h index ccdad77f..83f742c4 100644 --- a/fmt/time.h +++ b/fmt/time.h @@ -23,7 +23,7 @@ void format_arg(BasicFormatter &f, while (*end && *end != '}') ++end; if (*end != '}') - FMT_THROW(FormatError("missing '}' in format string")); + FMT_THROW(format_error("missing '}' in format string")); internal::MemoryBuffer format; format.append(format_str, end + 1); format[format.size() - 1] = '\0'; diff --git a/test/format-test.cc b/test/format-test.cc index 6d246b93..a92d875f 100644 --- a/test/format-test.cc +++ b/test/format-test.cc @@ -72,7 +72,7 @@ using std::size_t; using fmt::BasicWriter; using fmt::format; -using fmt::FormatError; +using fmt::format_error; using fmt::StringRef; using fmt::CStringRef; using fmt::MemoryWriter; @@ -535,9 +535,9 @@ TEST(FormatterTest, Escape) { } TEST(FormatterTest, UnmatchedBraces) { - EXPECT_THROW_MSG(format("{"), FormatError, "invalid format string"); - EXPECT_THROW_MSG(format("}"), FormatError, "unmatched '}' in format string"); - EXPECT_THROW_MSG(format("{0{}"), FormatError, "invalid format string"); + EXPECT_THROW_MSG(format("{"), format_error, "invalid format string"); + EXPECT_THROW_MSG(format("}"), format_error, "unmatched '}' in format string"); + EXPECT_THROW_MSG(format("{0{}"), format_error, "invalid format string"); } TEST(FormatterTest, NoArgs) { @@ -555,22 +555,22 @@ TEST(FormatterTest, ArgsInDifferentPositions) { } TEST(FormatterTest, ArgErrors) { - EXPECT_THROW_MSG(format("{"), FormatError, "invalid format string"); - EXPECT_THROW_MSG(format("{?}"), FormatError, "invalid format string"); - EXPECT_THROW_MSG(format("{0"), FormatError, "invalid format string"); - EXPECT_THROW_MSG(format("{0}"), FormatError, "argument index out of range"); + EXPECT_THROW_MSG(format("{"), format_error, "invalid format string"); + EXPECT_THROW_MSG(format("{?}"), format_error, "invalid format string"); + EXPECT_THROW_MSG(format("{0"), format_error, "invalid format string"); + EXPECT_THROW_MSG(format("{0}"), format_error, "argument index out of range"); char format_str[BUFFER_SIZE]; safe_sprintf(format_str, "{%u", INT_MAX); - EXPECT_THROW_MSG(format(format_str), FormatError, "invalid format string"); + EXPECT_THROW_MSG(format(format_str), format_error, "invalid format string"); safe_sprintf(format_str, "{%u}", INT_MAX); - EXPECT_THROW_MSG(format(format_str), FormatError, + EXPECT_THROW_MSG(format(format_str), format_error, "argument index out of range"); safe_sprintf(format_str, "{%u", INT_MAX + 1u); - EXPECT_THROW_MSG(format(format_str), FormatError, "number is too big"); + EXPECT_THROW_MSG(format(format_str), format_error, "number is too big"); safe_sprintf(format_str, "{%u}", INT_MAX + 1u); - EXPECT_THROW_MSG(format(format_str), FormatError, "number is too big"); + EXPECT_THROW_MSG(format(format_str), format_error, "number is too big"); } #if FMT_USE_VARIADIC_TEMPLATES @@ -593,13 +593,13 @@ struct TestFormat<0> { TEST(FormatterTest, ManyArgs) { EXPECT_EQ("19", TestFormat<20>::format("{19}")); EXPECT_THROW_MSG(TestFormat<20>::format("{20}"), - FormatError, "argument index out of range"); + format_error, "argument index out of range"); EXPECT_THROW_MSG(TestFormat<21>::format("{21}"), - FormatError, "argument index out of range"); + format_error, "argument index out of range"); enum { MAX_PACKED_ARGS = fmt::ArgList::MAX_PACKED_ARGS }; std::string format_str = fmt::format("{{{}}}", MAX_PACKED_ARGS + 1); EXPECT_THROW_MSG(TestFormat::format(format_str), - FormatError, "argument index out of range"); + format_error, "argument index out of range"); } #endif @@ -609,15 +609,15 @@ TEST(FormatterTest, NamedArg) { char a = 'A', b = 'B', c = 'C'; EXPECT_EQ("BB/AA/CC", format("{1}{b}/{0}{a}/{2}{c}", FMT_CAPTURE(a, b, c))); EXPECT_EQ(" A", format("{a:>2}", FMT_CAPTURE(a))); - EXPECT_THROW_MSG(format("{a+}", FMT_CAPTURE(a)), FormatError, + EXPECT_THROW_MSG(format("{a+}", FMT_CAPTURE(a)), format_error, "missing '}' in format string"); - EXPECT_THROW_MSG(format("{a}"), FormatError, "argument not found"); - EXPECT_THROW_MSG(format("{d}", FMT_CAPTURE(a, b, c)), FormatError, + EXPECT_THROW_MSG(format("{a}"), format_error, "argument not found"); + EXPECT_THROW_MSG(format("{d}", FMT_CAPTURE(a, b, c)), format_error, "argument not found"); EXPECT_THROW_MSG(format("{a}{}", FMT_CAPTURE(a)), - FormatError, "cannot switch from manual to automatic argument indexing"); + format_error, "cannot switch from manual to automatic argument indexing"); EXPECT_THROW_MSG(format("{}{a}", FMT_CAPTURE(a)), - FormatError, "cannot switch from automatic to manual argument indexing"); + format_error, "cannot switch from automatic to manual argument indexing"); EXPECT_EQ(" -42", format("{0:{width}}", -42, fmt::arg("width", 4))); EXPECT_EQ("st", format("{0:.{precision}}", "str", fmt::arg("precision", 2))); int n = 100; @@ -627,15 +627,15 @@ TEST(FormatterTest, NamedArg) { TEST(FormatterTest, AutoArgIndex) { EXPECT_EQ("abc", format("{}{}{}", 'a', 'b', 'c')); EXPECT_THROW_MSG(format("{0}{}", 'a', 'b'), - FormatError, "cannot switch from manual to automatic argument indexing"); + format_error, "cannot switch from manual to automatic argument indexing"); EXPECT_THROW_MSG(format("{}{0}", 'a', 'b'), - FormatError, "cannot switch from automatic to manual argument indexing"); + format_error, "cannot switch from automatic to manual argument indexing"); EXPECT_EQ("1.2", format("{:.{}}", 1.2345, 2)); EXPECT_THROW_MSG(format("{0}:.{}", 1.2345, 2), - FormatError, "cannot switch from manual to automatic argument indexing"); + format_error, "cannot switch from manual to automatic argument indexing"); EXPECT_THROW_MSG(format("{:.{0}}", 1.2345, 2), - FormatError, "cannot switch from automatic to manual argument indexing"); - EXPECT_THROW_MSG(format("{}"), FormatError, "argument index out of range"); + format_error, "cannot switch from automatic to manual argument indexing"); + EXPECT_THROW_MSG(format("{}"), format_error, "argument index out of range"); } TEST(FormatterTest, EmptySpecs) { @@ -692,13 +692,13 @@ TEST(FormatterTest, NumericAlign) { EXPECT_EQ("- 42", format("{0:=5}", -42.0)); EXPECT_EQ("- 42", format("{0:=5}", -42.0l)); EXPECT_THROW_MSG(format("{0:=5", 'c'), - FormatError, "missing '}' in format string"); + format_error, "missing '}' in format string"); EXPECT_THROW_MSG(format("{0:=5}", 'c'), - FormatError, "invalid format specifier for char"); + format_error, "invalid format specifier for char"); EXPECT_THROW_MSG(format("{0:=5}", "abc"), - FormatError, "format specifier '=' requires numeric argument"); + format_error, "format specifier '=' requires numeric argument"); EXPECT_THROW_MSG(format("{0:=8}", reinterpret_cast(0xface)), - FormatError, "format specifier '=' requires numeric argument"); + format_error, "format specifier '=' requires numeric argument"); } TEST(FormatterTest, CenterAlign) { @@ -720,9 +720,9 @@ TEST(FormatterTest, CenterAlign) { TEST(FormatterTest, Fill) { EXPECT_THROW_MSG(format("{0:{<5}", 'c'), - FormatError, "invalid fill character '{'"); + format_error, "invalid fill character '{'"); EXPECT_THROW_MSG(format("{0:{<5}}", 'c'), - FormatError, "invalid fill character '{'"); + format_error, "invalid fill character '{'"); EXPECT_EQ("**42", format("{0:*>4}", 42)); EXPECT_EQ("**-42", format("{0:*>5}", -42)); EXPECT_EQ("***42", format("{0:*>5}", 42u)); @@ -742,23 +742,23 @@ TEST(FormatterTest, PlusSign) { EXPECT_EQ("-42", format("{0:+}", -42)); EXPECT_EQ("+42", format("{0:+}", 42)); EXPECT_THROW_MSG(format("{0:+}", 42u), - FormatError, "format specifier '+' requires signed argument"); + format_error, "format specifier '+' requires signed argument"); EXPECT_EQ("+42", format("{0:+}", 42l)); EXPECT_THROW_MSG(format("{0:+}", 42ul), - FormatError, "format specifier '+' requires signed argument"); + format_error, "format specifier '+' requires signed argument"); EXPECT_EQ("+42", format("{0:+}", 42ll)); EXPECT_THROW_MSG(format("{0:+}", 42ull), - FormatError, "format specifier '+' requires signed argument"); + format_error, "format specifier '+' requires signed argument"); EXPECT_EQ("+42", format("{0:+}", 42.0)); EXPECT_EQ("+42", format("{0:+}", 42.0l)); EXPECT_THROW_MSG(format("{0:+", 'c'), - FormatError, "missing '}' in format string"); + format_error, "missing '}' in format string"); EXPECT_THROW_MSG(format("{0:+}", 'c'), - FormatError, "invalid format specifier for char"); + format_error, "invalid format specifier for char"); EXPECT_THROW_MSG(format("{0:+}", "abc"), - FormatError, "format specifier '+' requires numeric argument"); + format_error, "format specifier '+' requires numeric argument"); EXPECT_THROW_MSG(format("{0:+}", reinterpret_cast(0x42)), - FormatError, "format specifier '+' requires numeric argument"); + format_error, "format specifier '+' requires numeric argument"); } TEST(FormatterTest, MinusSign) { @@ -766,23 +766,23 @@ TEST(FormatterTest, MinusSign) { EXPECT_EQ("-42", format("{0:-}", -42)); EXPECT_EQ("42", format("{0:-}", 42)); EXPECT_THROW_MSG(format("{0:-}", 42u), - FormatError, "format specifier '-' requires signed argument"); + format_error, "format specifier '-' requires signed argument"); EXPECT_EQ("42", format("{0:-}", 42l)); EXPECT_THROW_MSG(format("{0:-}", 42ul), - FormatError, "format specifier '-' requires signed argument"); + format_error, "format specifier '-' requires signed argument"); EXPECT_EQ("42", format("{0:-}", 42ll)); EXPECT_THROW_MSG(format("{0:-}", 42ull), - FormatError, "format specifier '-' requires signed argument"); + format_error, "format specifier '-' requires signed argument"); EXPECT_EQ("42", format("{0:-}", 42.0)); EXPECT_EQ("42", format("{0:-}", 42.0l)); EXPECT_THROW_MSG(format("{0:-", 'c'), - FormatError, "missing '}' in format string"); + format_error, "missing '}' in format string"); EXPECT_THROW_MSG(format("{0:-}", 'c'), - FormatError, "invalid format specifier for char"); + format_error, "invalid format specifier for char"); EXPECT_THROW_MSG(format("{0:-}", "abc"), - FormatError, "format specifier '-' requires numeric argument"); + format_error, "format specifier '-' requires numeric argument"); EXPECT_THROW_MSG(format("{0:-}", reinterpret_cast(0x42)), - FormatError, "format specifier '-' requires numeric argument"); + format_error, "format specifier '-' requires numeric argument"); } TEST(FormatterTest, SpaceSign) { @@ -790,23 +790,23 @@ TEST(FormatterTest, SpaceSign) { EXPECT_EQ("-42", format("{0: }", -42)); EXPECT_EQ(" 42", format("{0: }", 42)); EXPECT_THROW_MSG(format("{0: }", 42u), - FormatError, "format specifier ' ' requires signed argument"); + format_error, "format specifier ' ' requires signed argument"); EXPECT_EQ(" 42", format("{0: }", 42l)); EXPECT_THROW_MSG(format("{0: }", 42ul), - FormatError, "format specifier ' ' requires signed argument"); + format_error, "format specifier ' ' requires signed argument"); EXPECT_EQ(" 42", format("{0: }", 42ll)); EXPECT_THROW_MSG(format("{0: }", 42ull), - FormatError, "format specifier ' ' requires signed argument"); + format_error, "format specifier ' ' requires signed argument"); EXPECT_EQ(" 42", format("{0: }", 42.0)); EXPECT_EQ(" 42", format("{0: }", 42.0l)); EXPECT_THROW_MSG(format("{0: ", 'c'), - FormatError, "missing '}' in format string"); + format_error, "missing '}' in format string"); EXPECT_THROW_MSG(format("{0: }", 'c'), - FormatError, "invalid format specifier for char"); + format_error, "invalid format specifier for char"); EXPECT_THROW_MSG(format("{0: }", "abc"), - FormatError, "format specifier ' ' requires numeric argument"); + format_error, "format specifier ' ' requires numeric argument"); EXPECT_THROW_MSG(format("{0: }", reinterpret_cast(0x42)), - FormatError, "format specifier ' ' requires numeric argument"); + format_error, "format specifier ' ' requires numeric argument"); } TEST(FormatterTest, HashFlag) { @@ -845,13 +845,13 @@ TEST(FormatterTest, HashFlag) { EXPECT_EQ("-42.0000", format("{0:#}", -42.0)); EXPECT_EQ("-42.0000", format("{0:#}", -42.0l)); EXPECT_THROW_MSG(format("{0:#", 'c'), - FormatError, "missing '}' in format string"); + format_error, "missing '}' in format string"); EXPECT_THROW_MSG(format("{0:#}", 'c'), - FormatError, "invalid format specifier for char"); + format_error, "invalid format specifier for char"); EXPECT_THROW_MSG(format("{0:#}", "abc"), - FormatError, "format specifier '#' requires numeric argument"); + format_error, "format specifier '#' requires numeric argument"); EXPECT_THROW_MSG(format("{0:#}", reinterpret_cast(0x42)), - FormatError, "format specifier '#' requires numeric argument"); + format_error, "format specifier '#' requires numeric argument"); } TEST(FormatterTest, ZeroFlag) { @@ -865,29 +865,29 @@ TEST(FormatterTest, ZeroFlag) { EXPECT_EQ("-0042", format("{0:05}", -42.0)); EXPECT_EQ("-0042", format("{0:05}", -42.0l)); EXPECT_THROW_MSG(format("{0:0", 'c'), - FormatError, "missing '}' in format string"); + format_error, "missing '}' in format string"); EXPECT_THROW_MSG(format("{0:05}", 'c'), - FormatError, "invalid format specifier for char"); + format_error, "invalid format specifier for char"); EXPECT_THROW_MSG(format("{0:05}", "abc"), - FormatError, "format specifier '0' requires numeric argument"); + format_error, "format specifier '0' requires numeric argument"); EXPECT_THROW_MSG(format("{0:05}", reinterpret_cast(0x42)), - FormatError, "format specifier '0' requires numeric argument"); + format_error, "format specifier '0' requires numeric argument"); } TEST(FormatterTest, Width) { char format_str[BUFFER_SIZE]; safe_sprintf(format_str, "{0:%u", UINT_MAX); increment(format_str + 3); - EXPECT_THROW_MSG(format(format_str, 0), FormatError, "number is too big"); + EXPECT_THROW_MSG(format(format_str, 0), format_error, "number is too big"); std::size_t size = std::strlen(format_str); format_str[size] = '}'; format_str[size + 1] = 0; - EXPECT_THROW_MSG(format(format_str, 0), FormatError, "number is too big"); + EXPECT_THROW_MSG(format(format_str, 0), format_error, "number is too big"); safe_sprintf(format_str, "{0:%u", INT_MAX + 1u); - EXPECT_THROW_MSG(format(format_str, 0), FormatError, "number is too big"); + EXPECT_THROW_MSG(format(format_str, 0), format_error, "number is too big"); safe_sprintf(format_str, "{0:%u}", INT_MAX + 1u); - EXPECT_THROW_MSG(format(format_str, 0), FormatError, "number is too big"); + EXPECT_THROW_MSG(format(format_str, 0), format_error, "number is too big"); EXPECT_EQ(" -42", format("{0:4}", -42)); EXPECT_EQ(" 42", format("{0:5}", 42u)); EXPECT_EQ(" -42", format("{0:6}", -42l)); @@ -905,45 +905,45 @@ TEST(FormatterTest, RuntimeWidth) { char format_str[BUFFER_SIZE]; safe_sprintf(format_str, "{0:{%u", UINT_MAX); increment(format_str + 4); - EXPECT_THROW_MSG(format(format_str, 0), FormatError, "number is too big"); + EXPECT_THROW_MSG(format(format_str, 0), format_error, "number is too big"); std::size_t size = std::strlen(format_str); format_str[size] = '}'; format_str[size + 1] = 0; - EXPECT_THROW_MSG(format(format_str, 0), FormatError, "number is too big"); + EXPECT_THROW_MSG(format(format_str, 0), format_error, "number is too big"); format_str[size + 1] = '}'; format_str[size + 2] = 0; - EXPECT_THROW_MSG(format(format_str, 0), FormatError, "number is too big"); + EXPECT_THROW_MSG(format(format_str, 0), format_error, "number is too big"); EXPECT_THROW_MSG(format("{0:{", 0), - FormatError, "invalid format string"); + format_error, "invalid format string"); EXPECT_THROW_MSG(format("{0:{}", 0), - FormatError, "cannot switch from manual to automatic argument indexing"); + format_error, "cannot switch from manual to automatic argument indexing"); EXPECT_THROW_MSG(format("{0:{?}}", 0), - FormatError, "invalid format string"); + format_error, "invalid format string"); EXPECT_THROW_MSG(format("{0:{1}}", 0), - FormatError, "argument index out of range"); + format_error, "argument index out of range"); EXPECT_THROW_MSG(format("{0:{0:}}", 0), - FormatError, "invalid format string"); + format_error, "invalid format string"); EXPECT_THROW_MSG(format("{0:{1}}", 0, -1), - FormatError, "negative width"); + format_error, "negative width"); EXPECT_THROW_MSG(format("{0:{1}}", 0, (INT_MAX + 1u)), - FormatError, "number is too big"); + format_error, "number is too big"); EXPECT_THROW_MSG(format("{0:{1}}", 0, -1l), - FormatError, "negative width"); + format_error, "negative width"); if (fmt::internal::const_check(sizeof(long) > sizeof(int))) { long value = INT_MAX; EXPECT_THROW_MSG(format("{0:{1}}", 0, (value + 1)), - FormatError, "number is too big"); + format_error, "number is too big"); } EXPECT_THROW_MSG(format("{0:{1}}", 0, (INT_MAX + 1ul)), - FormatError, "number is too big"); + format_error, "number is too big"); EXPECT_THROW_MSG(format("{0:{1}}", 0, '0'), - FormatError, "width is not integer"); + format_error, "width is not integer"); EXPECT_THROW_MSG(format("{0:{1}}", 0, 0.0), - FormatError, "width is not integer"); + format_error, "width is not integer"); EXPECT_EQ(" -42", format("{0:{1}}", -42, 4)); EXPECT_EQ(" 42", format("{0:{1}}", 42u, 5)); @@ -963,57 +963,57 @@ TEST(FormatterTest, Precision) { char format_str[BUFFER_SIZE]; safe_sprintf(format_str, "{0:.%u", UINT_MAX); increment(format_str + 4); - EXPECT_THROW_MSG(format(format_str, 0), FormatError, "number is too big"); + EXPECT_THROW_MSG(format(format_str, 0), format_error, "number is too big"); std::size_t size = std::strlen(format_str); format_str[size] = '}'; format_str[size + 1] = 0; - EXPECT_THROW_MSG(format(format_str, 0), FormatError, "number is too big"); + EXPECT_THROW_MSG(format(format_str, 0), format_error, "number is too big"); safe_sprintf(format_str, "{0:.%u", INT_MAX + 1u); - EXPECT_THROW_MSG(format(format_str, 0), FormatError, "number is too big"); + EXPECT_THROW_MSG(format(format_str, 0), format_error, "number is too big"); safe_sprintf(format_str, "{0:.%u}", INT_MAX + 1u); - EXPECT_THROW_MSG(format(format_str, 0), FormatError, "number is too big"); + EXPECT_THROW_MSG(format(format_str, 0), format_error, "number is too big"); EXPECT_THROW_MSG(format("{0:.", 0), - FormatError, "missing precision specifier"); + format_error, "missing precision specifier"); EXPECT_THROW_MSG(format("{0:.}", 0), - FormatError, "missing precision specifier"); + format_error, "missing precision specifier"); EXPECT_THROW_MSG(format("{0:.2", 0), - FormatError, "precision not allowed in integer format specifier"); + format_error, "precision not allowed in integer format specifier"); EXPECT_THROW_MSG(format("{0:.2}", 42), - FormatError, "precision not allowed in integer format specifier"); + format_error, "precision not allowed in integer format specifier"); EXPECT_THROW_MSG(format("{0:.2f}", 42), - FormatError, "precision not allowed in integer format specifier"); + format_error, "precision not allowed in integer format specifier"); EXPECT_THROW_MSG(format("{0:.2}", 42u), - FormatError, "precision not allowed in integer format specifier"); + format_error, "precision not allowed in integer format specifier"); EXPECT_THROW_MSG(format("{0:.2f}", 42u), - FormatError, "precision not allowed in integer format specifier"); + format_error, "precision not allowed in integer format specifier"); EXPECT_THROW_MSG(format("{0:.2}", 42l), - FormatError, "precision not allowed in integer format specifier"); + format_error, "precision not allowed in integer format specifier"); EXPECT_THROW_MSG(format("{0:.2f}", 42l), - FormatError, "precision not allowed in integer format specifier"); + format_error, "precision not allowed in integer format specifier"); EXPECT_THROW_MSG(format("{0:.2}", 42ul), - FormatError, "precision not allowed in integer format specifier"); + format_error, "precision not allowed in integer format specifier"); EXPECT_THROW_MSG(format("{0:.2f}", 42ul), - FormatError, "precision not allowed in integer format specifier"); + format_error, "precision not allowed in integer format specifier"); EXPECT_THROW_MSG(format("{0:.2}", 42ll), - FormatError, "precision not allowed in integer format specifier"); + format_error, "precision not allowed in integer format specifier"); EXPECT_THROW_MSG(format("{0:.2f}", 42ll), - FormatError, "precision not allowed in integer format specifier"); + format_error, "precision not allowed in integer format specifier"); EXPECT_THROW_MSG(format("{0:.2}", 42ull), - FormatError, "precision not allowed in integer format specifier"); + format_error, "precision not allowed in integer format specifier"); EXPECT_THROW_MSG(format("{0:.2f}", 42ull), - FormatError, "precision not allowed in integer format specifier"); + format_error, "precision not allowed in integer format specifier"); EXPECT_THROW_MSG(format("{0:3.0}", 'x'), - FormatError, "precision not allowed in integer format specifier"); + format_error, "precision not allowed in integer format specifier"); EXPECT_EQ("1.2", format("{0:.2}", 1.2345)); EXPECT_EQ("1.2", format("{0:.2}", 1.2345l)); EXPECT_THROW_MSG(format("{0:.2}", reinterpret_cast(0xcafe)), - FormatError, "precision not allowed in pointer format specifier"); + format_error, "precision not allowed in pointer format specifier"); EXPECT_THROW_MSG(format("{0:.2f}", reinterpret_cast(0xcafe)), - FormatError, "precision not allowed in pointer format specifier"); + format_error, "precision not allowed in pointer format specifier"); EXPECT_EQ("st", format("{0:.2}", "str")); } @@ -1022,81 +1022,81 @@ TEST(FormatterTest, RuntimePrecision) { char format_str[BUFFER_SIZE]; safe_sprintf(format_str, "{0:.{%u", UINT_MAX); increment(format_str + 5); - EXPECT_THROW_MSG(format(format_str, 0), FormatError, "number is too big"); + EXPECT_THROW_MSG(format(format_str, 0), format_error, "number is too big"); std::size_t size = std::strlen(format_str); format_str[size] = '}'; format_str[size + 1] = 0; - EXPECT_THROW_MSG(format(format_str, 0), FormatError, "number is too big"); + EXPECT_THROW_MSG(format(format_str, 0), format_error, "number is too big"); format_str[size + 1] = '}'; format_str[size + 2] = 0; - EXPECT_THROW_MSG(format(format_str, 0), FormatError, "number is too big"); + EXPECT_THROW_MSG(format(format_str, 0), format_error, "number is too big"); EXPECT_THROW_MSG(format("{0:.{", 0), - FormatError, "invalid format string"); + format_error, "invalid format string"); EXPECT_THROW_MSG(format("{0:.{}", 0), - FormatError, "cannot switch from manual to automatic argument indexing"); + format_error, "cannot switch from manual to automatic argument indexing"); EXPECT_THROW_MSG(format("{0:.{?}}", 0), - FormatError, "invalid format string"); + format_error, "invalid format string"); EXPECT_THROW_MSG(format("{0:.{1}", 0, 0), - FormatError, "precision not allowed in integer format specifier"); + format_error, "precision not allowed in integer format specifier"); EXPECT_THROW_MSG(format("{0:.{1}}", 0), - FormatError, "argument index out of range"); + format_error, "argument index out of range"); EXPECT_THROW_MSG(format("{0:.{0:}}", 0), - FormatError, "invalid format string"); + format_error, "invalid format string"); EXPECT_THROW_MSG(format("{0:.{1}}", 0, -1), - FormatError, "negative precision"); + format_error, "negative precision"); EXPECT_THROW_MSG(format("{0:.{1}}", 0, (INT_MAX + 1u)), - FormatError, "number is too big"); + format_error, "number is too big"); EXPECT_THROW_MSG(format("{0:.{1}}", 0, -1l), - FormatError, "negative precision"); + format_error, "negative precision"); if (fmt::internal::const_check(sizeof(long) > sizeof(int))) { long value = INT_MAX; EXPECT_THROW_MSG(format("{0:.{1}}", 0, (value + 1)), - FormatError, "number is too big"); + format_error, "number is too big"); } EXPECT_THROW_MSG(format("{0:.{1}}", 0, (INT_MAX + 1ul)), - FormatError, "number is too big"); + format_error, "number is too big"); EXPECT_THROW_MSG(format("{0:.{1}}", 0, '0'), - FormatError, "precision is not integer"); + format_error, "precision is not integer"); EXPECT_THROW_MSG(format("{0:.{1}}", 0, 0.0), - FormatError, "precision is not integer"); + format_error, "precision is not integer"); EXPECT_THROW_MSG(format("{0:.{1}}", 42, 2), - FormatError, "precision not allowed in integer format specifier"); + format_error, "precision not allowed in integer format specifier"); EXPECT_THROW_MSG(format("{0:.{1}f}", 42, 2), - FormatError, "precision not allowed in integer format specifier"); + format_error, "precision not allowed in integer format specifier"); EXPECT_THROW_MSG(format("{0:.{1}}", 42u, 2), - FormatError, "precision not allowed in integer format specifier"); + format_error, "precision not allowed in integer format specifier"); EXPECT_THROW_MSG(format("{0:.{1}f}", 42u, 2), - FormatError, "precision not allowed in integer format specifier"); + format_error, "precision not allowed in integer format specifier"); EXPECT_THROW_MSG(format("{0:.{1}}", 42l, 2), - FormatError, "precision not allowed in integer format specifier"); + format_error, "precision not allowed in integer format specifier"); EXPECT_THROW_MSG(format("{0:.{1}f}", 42l, 2), - FormatError, "precision not allowed in integer format specifier"); + format_error, "precision not allowed in integer format specifier"); EXPECT_THROW_MSG(format("{0:.{1}}", 42ul, 2), - FormatError, "precision not allowed in integer format specifier"); + format_error, "precision not allowed in integer format specifier"); EXPECT_THROW_MSG(format("{0:.{1}f}", 42ul, 2), - FormatError, "precision not allowed in integer format specifier"); + format_error, "precision not allowed in integer format specifier"); EXPECT_THROW_MSG(format("{0:.{1}}", 42ll, 2), - FormatError, "precision not allowed in integer format specifier"); + format_error, "precision not allowed in integer format specifier"); EXPECT_THROW_MSG(format("{0:.{1}f}", 42ll, 2), - FormatError, "precision not allowed in integer format specifier"); + format_error, "precision not allowed in integer format specifier"); EXPECT_THROW_MSG(format("{0:.{1}}", 42ull, 2), - FormatError, "precision not allowed in integer format specifier"); + format_error, "precision not allowed in integer format specifier"); EXPECT_THROW_MSG(format("{0:.{1}f}", 42ull, 2), - FormatError, "precision not allowed in integer format specifier"); + format_error, "precision not allowed in integer format specifier"); EXPECT_THROW_MSG(format("{0:3.{1}}", 'x', 0), - FormatError, "precision not allowed in integer format specifier"); + format_error, "precision not allowed in integer format specifier"); EXPECT_EQ("1.2", format("{0:.{1}}", 1.2345, 2)); EXPECT_EQ("1.2", format("{1:.{0}}", 2, 1.2345l)); EXPECT_THROW_MSG(format("{0:.{1}}", reinterpret_cast(0xcafe), 2), - FormatError, "precision not allowed in pointer format specifier"); + format_error, "precision not allowed in pointer format specifier"); EXPECT_THROW_MSG(format("{0:.{1}f}", reinterpret_cast(0xcafe), 2), - FormatError, "precision not allowed in pointer format specifier"); + format_error, "precision not allowed in pointer format specifier"); EXPECT_EQ("st", format("{0:.{1}}", "str", 2)); } @@ -1116,7 +1116,7 @@ void check_unknown_types( safe_sprintf(message, "unknown format code '\\x%02x' for %s", c, type_name); } - EXPECT_THROW_MSG(format(format_str, value), FormatError, message) + EXPECT_THROW_MSG(format(format_str, value), format_error, message) << format_str << " " << message; } } @@ -1138,7 +1138,7 @@ TEST(FormatterTest, FormatShort) { TEST(FormatterTest, FormatInt) { EXPECT_THROW_MSG(format("{0:v", 42), - FormatError, "missing '}' in format string"); + format_error, "missing '}' in format string"); check_unknown_types(42, "bBdoxXn", "integer"); } @@ -1328,7 +1328,7 @@ TEST(FormatterTest, FormatCString) { char nonconst[] = "nonconst"; EXPECT_EQ("nonconst", format("{0}", nonconst)); EXPECT_THROW_MSG(format("{0}", reinterpret_cast(0)), - FormatError, "string pointer is null"); + format_error, "string pointer is null"); } TEST(FormatterTest, FormatSCharString) { @@ -1374,7 +1374,7 @@ void format_arg(fmt::BasicFormatter &f, const char *, const Date &d) { TEST(FormatterTest, FormatCustom) { Date date(2012, 12, 9); - EXPECT_THROW_MSG(fmt::format("{:s}", date), FormatError, + EXPECT_THROW_MSG(fmt::format("{:s}", date), format_error, "unmatched '}' in format string"); } @@ -1477,7 +1477,7 @@ TEST(FormatterTest, Examples) { EXPECT_EQ("The answer is 42", format("The answer is {}", 42)); EXPECT_THROW_MSG( - format("The answer is {:d}", "forty-two"), FormatError, + format("The answer is {:d}", "forty-two"), format_error, "unknown format code 'd' for string"); EXPECT_EQ(L"Cyrillic letter \x42e", diff --git a/test/ostream-test.cc b/test/ostream-test.cc index 4081b43f..fa2c40d6 100644 --- a/test/ostream-test.cc +++ b/test/ostream-test.cc @@ -33,7 +33,7 @@ #include "util.h" using fmt::format; -using fmt::FormatError; +using fmt::format_error; std::ostream &operator<<(std::ostream &os, const Date &d) { os << d.year() << '-' << d.month() << '-' << d.day(); @@ -87,19 +87,19 @@ TEST(OStreamTest, FormatSpecs) { EXPECT_EQ("def ", format("{0:<5}", TestString("def"))); EXPECT_EQ(" def", format("{0:>5}", TestString("def"))); EXPECT_THROW_MSG(format("{0:=5}", TestString("def")), - FormatError, "format specifier '=' requires numeric argument"); + format_error, "format specifier '=' requires numeric argument"); EXPECT_EQ(" def ", format("{0:^5}", TestString("def"))); EXPECT_EQ("def**", format("{0:*<5}", TestString("def"))); EXPECT_THROW_MSG(format("{0:+}", TestString()), - FormatError, "format specifier '+' requires numeric argument"); + format_error, "format specifier '+' requires numeric argument"); EXPECT_THROW_MSG(format("{0:-}", TestString()), - FormatError, "format specifier '-' requires numeric argument"); + format_error, "format specifier '-' requires numeric argument"); EXPECT_THROW_MSG(format("{0: }", TestString()), - FormatError, "format specifier ' ' requires numeric argument"); + format_error, "format specifier ' ' requires numeric argument"); EXPECT_THROW_MSG(format("{0:#}", TestString()), - FormatError, "format specifier '#' requires numeric argument"); + format_error, "format specifier '#' requires numeric argument"); EXPECT_THROW_MSG(format("{0:05}", TestString()), - FormatError, "format specifier '0' requires numeric argument"); + format_error, "format specifier '0' requires numeric argument"); EXPECT_EQ("test ", format("{0:13}", TestString("test"))); EXPECT_EQ("test ", format("{0:{1}}", TestString("test"), 13)); EXPECT_EQ("te", format("{0:.2}", TestString("test"))); diff --git a/test/printf-test.cc b/test/printf-test.cc index 6bba02e1..e8df2181 100644 --- a/test/printf-test.cc +++ b/test/printf-test.cc @@ -35,7 +35,7 @@ #include "util.h" using fmt::format; -using fmt::FormatError; +using fmt::format_error; const unsigned BIG_NUM = INT_MAX + 1u; @@ -80,45 +80,45 @@ TEST(PrintfTest, AutomaticArgIndexing) { TEST(PrintfTest, NumberIsTooBigInArgIndex) { EXPECT_THROW_MSG(fmt::sprintf(format("%{}$", BIG_NUM)), - FormatError, "number is too big"); + format_error, "number is too big"); EXPECT_THROW_MSG(fmt::sprintf(format("%{}$d", BIG_NUM)), - FormatError, "number is too big"); + format_error, "number is too big"); } TEST(PrintfTest, SwitchArgIndexing) { EXPECT_THROW_MSG(fmt::sprintf("%1$d%", 1, 2), - FormatError, "invalid format string"); + format_error, "invalid format string"); EXPECT_THROW_MSG(fmt::sprintf(format("%1$d%{}d", BIG_NUM), 1, 2), - FormatError, "number is too big"); + format_error, "number is too big"); EXPECT_THROW_MSG(fmt::sprintf("%1$d%d", 1, 2), - FormatError, "cannot switch from manual to automatic argument indexing"); + format_error, "cannot switch from manual to automatic argument indexing"); EXPECT_THROW_MSG(fmt::sprintf("%d%1$", 1, 2), - FormatError, "invalid format string"); + format_error, "invalid format string"); EXPECT_THROW_MSG(fmt::sprintf(format("%d%{}$d", BIG_NUM), 1, 2), - FormatError, "number is too big"); + format_error, "number is too big"); EXPECT_THROW_MSG(fmt::sprintf("%d%1$d", 1, 2), - FormatError, "cannot switch from automatic to manual argument indexing"); + format_error, "cannot switch from automatic to manual argument indexing"); // Indexing errors override width errors. EXPECT_THROW_MSG(fmt::sprintf(format("%d%1${}d", BIG_NUM), 1, 2), - FormatError, "number is too big"); + format_error, "number is too big"); EXPECT_THROW_MSG(fmt::sprintf(format("%1$d%{}d", BIG_NUM), 1, 2), - FormatError, "number is too big"); + format_error, "number is too big"); } TEST(PrintfTest, InvalidArgIndex) { - EXPECT_THROW_MSG(fmt::sprintf("%0$d", 42), FormatError, + EXPECT_THROW_MSG(fmt::sprintf("%0$d", 42), format_error, "argument index out of range"); - EXPECT_THROW_MSG(fmt::sprintf("%2$d", 42), FormatError, + EXPECT_THROW_MSG(fmt::sprintf("%2$d", 42), format_error, "argument index out of range"); EXPECT_THROW_MSG(fmt::sprintf(format("%{}$d", INT_MAX), 42), - FormatError, "argument index out of range"); + format_error, "argument index out of range"); EXPECT_THROW_MSG(fmt::sprintf("%2$", 42), - FormatError, "invalid format string"); + format_error, "invalid format string"); EXPECT_THROW_MSG(fmt::sprintf(format("%{}$d", BIG_NUM), 42), - FormatError, "number is too big"); + format_error, "number is too big"); } TEST(PrintfTest, DefaultAlignRight) { @@ -204,23 +204,23 @@ TEST(PrintfTest, Width) { EXPECT_PRINTF(" abc", "%5s", "abc"); // Width cannot be specified twice. - EXPECT_THROW_MSG(fmt::sprintf("%5-5d", 42), FormatError, + EXPECT_THROW_MSG(fmt::sprintf("%5-5d", 42), format_error, "unknown format code '-' for integer"); EXPECT_THROW_MSG(fmt::sprintf(format("%{}d", BIG_NUM), 42), - FormatError, "number is too big"); + format_error, "number is too big"); EXPECT_THROW_MSG(fmt::sprintf(format("%1${}d", BIG_NUM), 42), - FormatError, "number is too big"); + format_error, "number is too big"); } TEST(PrintfTest, DynamicWidth) { EXPECT_EQ(" 42", fmt::sprintf("%*d", 5, 42)); EXPECT_EQ("42 ", fmt::sprintf("%*d", -5, 42)); - EXPECT_THROW_MSG(fmt::sprintf("%*d", 5.0, 42), FormatError, + EXPECT_THROW_MSG(fmt::sprintf("%*d", 5.0, 42), format_error, "width is not integer"); - EXPECT_THROW_MSG(fmt::sprintf("%*d"), FormatError, + EXPECT_THROW_MSG(fmt::sprintf("%*d"), format_error, "argument index out of range"); - EXPECT_THROW_MSG(fmt::sprintf("%*d", BIG_NUM, 42), FormatError, + EXPECT_THROW_MSG(fmt::sprintf("%*d", BIG_NUM, 42), format_error, "number is too big"); } @@ -263,15 +263,15 @@ TEST(PrintfTest, IgnorePrecisionForNonNumericArg) { TEST(PrintfTest, DynamicPrecision) { EXPECT_EQ("00042", fmt::sprintf("%.*d", 5, 42)); EXPECT_EQ("42", fmt::sprintf("%.*d", -5, 42)); - EXPECT_THROW_MSG(fmt::sprintf("%.*d", 5.0, 42), FormatError, + EXPECT_THROW_MSG(fmt::sprintf("%.*d", 5.0, 42), format_error, "precision is not integer"); - EXPECT_THROW_MSG(fmt::sprintf("%.*d"), FormatError, + EXPECT_THROW_MSG(fmt::sprintf("%.*d"), format_error, "argument index out of range"); - EXPECT_THROW_MSG(fmt::sprintf("%.*d", BIG_NUM, 42), FormatError, + EXPECT_THROW_MSG(fmt::sprintf("%.*d", BIG_NUM, 42), format_error, "number is too big"); if (sizeof(fmt::LongLong) != sizeof(int)) { fmt::LongLong prec = static_cast(INT_MIN) - 1; - EXPECT_THROW_MSG(fmt::sprintf("%.*d", prec, 42), FormatError, + EXPECT_THROW_MSG(fmt::sprintf("%.*d", prec, 42), format_error, "number is too big"); } } From 92605eb4f704ce142eb1296b5e47fb6714e89dec Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Thu, 25 Aug 2016 08:44:53 -0700 Subject: [PATCH 002/340] Remove FMT_USE_VARIADIC_TEMPLATES --- fmt/format.h | 119 ++------------------------------------------- test/macro-test.cc | 7 --- 2 files changed, 3 insertions(+), 123 deletions(-) diff --git a/fmt/format.h b/fmt/format.h index 145de3a1..6f96e84c 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -131,15 +131,6 @@ typedef __int64 intmax_t; # define FMT_HAS_CPP_ATTRIBUTE(x) 0 #endif -#ifndef FMT_USE_VARIADIC_TEMPLATES -// Variadic templates are available in GCC since version 4.4 -// (http://gcc.gnu.org/projects/cxx0x.html) and in Visual C++ -// since version 2013. -# define FMT_USE_VARIADIC_TEMPLATES \ - (FMT_HAS_FEATURE(cxx_variadic_templates) || \ - (FMT_GCC_VERSION >= 404 && FMT_HAS_GXX_CXX11) || FMT_MSC_VER >= 1800) -#endif - #ifndef FMT_USE_RVALUE_REFERENCES // Don't use rvalue references when compiling with clang and an old libstdc++ // as the latter doesn't provide std::move. @@ -219,7 +210,7 @@ typedef __int64 intmax_t; // for variadic templates is added here just in case. // For Intel's compiler both it and the system gcc/msc must support UDLs. # define FMT_USE_USER_DEFINED_LITERALS \ - FMT_USE_VARIADIC_TEMPLATES && FMT_USE_RVALUE_REFERENCES && \ + FMT_USE_RVALUE_REFERENCES && \ (FMT_HAS_FEATURE(cxx_user_literals) || \ (FMT_GCC_VERSION >= 407 && FMT_HAS_GXX_CXX11) || FMT_MSC_VER >= 1900) && \ (!defined(FMT_ICC_VERSION) || FMT_ICC_VERSION >= 1500) @@ -841,7 +832,7 @@ struct FMT_API BasicData { #ifndef FMT_USE_EXTERN_TEMPLATES // Clang doesn't have a feature check for extern templates so we check // for variadic templates which were introduced in the same version. -# define FMT_USE_EXTERN_TEMPLATES (__clang__ && FMT_USE_VARIADIC_TEMPLATES) +# define FMT_USE_EXTERN_TEMPLATES (__clang__) #endif #if FMT_USE_EXTERN_TEMPLATES && !defined(FMT_HEADER_ONLY) @@ -2131,32 +2122,10 @@ struct ArgArray { static Arg make(const T &value) { return MakeArg(value); } }; -#if FMT_USE_VARIADIC_TEMPLATES template inline uint64_t make_type(const Arg &first, const Args & ... tail) { return make_type(first) | (make_type(tail...) << 4); } - -#else - -struct ArgType { - uint64_t type; - - ArgType() : type(0) {} - - template - ArgType(const T &arg) : type(make_type(arg)) {} -}; - -# define FMT_ARG_TYPE_DEFAULT(n) ArgType t##n = ArgType() - -inline uint64_t make_type(FMT_GEN15(FMT_ARG_TYPE_DEFAULT)) { - return t0.type | (t1.type << 4) | (t2.type << 8) | (t3.type << 12) | - (t4.type << 16) | (t5.type << 20) | (t6.type << 24) | (t7.type << 28) | - (t8.type << 32) | (t9.type << 36) | (t10.type << 40) | (t11.type << 44) | - (t12.type << 48) | (t13.type << 52) | (t14.type << 56); -} -#endif } // namespace internal # define FMT_MAKE_TEMPLATE_ARG(n) typename T##n @@ -2167,7 +2136,6 @@ inline uint64_t make_type(FMT_GEN15(FMT_ARG_TYPE_DEFAULT)) { # define FMT_ASSIGN_wchar_t(n) \ arr[n] = fmt::internal::MakeValue< fmt::BasicFormatter >(v##n) -#if FMT_USE_VARIADIC_TEMPLATES // Defines a variadic function returning void. # define FMT_VARIADIC_VOID(func, arg_type) \ template \ @@ -2188,53 +2156,6 @@ inline uint64_t make_type(FMT_GEN15(FMT_ARG_TYPE_DEFAULT)) { func(arg0, arg1, fmt::ArgList(fmt::internal::make_type(args...), array)); \ } -#else - -# define FMT_MAKE_REF(n) \ - fmt::internal::MakeValue< fmt::BasicFormatter >(v##n) -# define FMT_MAKE_REF2(n) v##n - -// Defines a wrapper for a function taking one argument of type arg_type -// and n additional arguments of arbitrary types. -# define FMT_WRAP1(func, arg_type, n) \ - template \ - inline void func(arg_type arg1, FMT_GEN(n, FMT_MAKE_ARG)) { \ - const fmt::internal::ArgArray::Type array = {FMT_GEN(n, FMT_MAKE_REF)}; \ - func(arg1, fmt::ArgList( \ - fmt::internal::make_type(FMT_GEN(n, FMT_MAKE_REF2)), array)); \ - } - -// Emulates a variadic function returning void on a pre-C++11 compiler. -# define FMT_VARIADIC_VOID(func, arg_type) \ - inline void func(arg_type arg) { func(arg, fmt::ArgList()); } \ - FMT_WRAP1(func, arg_type, 1) FMT_WRAP1(func, arg_type, 2) \ - FMT_WRAP1(func, arg_type, 3) FMT_WRAP1(func, arg_type, 4) \ - FMT_WRAP1(func, arg_type, 5) FMT_WRAP1(func, arg_type, 6) \ - FMT_WRAP1(func, arg_type, 7) FMT_WRAP1(func, arg_type, 8) \ - FMT_WRAP1(func, arg_type, 9) FMT_WRAP1(func, arg_type, 10) - -# define FMT_CTOR(ctor, func, arg0_type, arg1_type, n) \ - template \ - ctor(arg0_type arg0, arg1_type arg1, FMT_GEN(n, FMT_MAKE_ARG)) { \ - const fmt::internal::ArgArray::Type array = {FMT_GEN(n, FMT_MAKE_REF)}; \ - func(arg0, arg1, fmt::ArgList( \ - fmt::internal::make_type(FMT_GEN(n, FMT_MAKE_REF2)), array)); \ - } - -// Emulates a variadic constructor on a pre-C++11 compiler. -# define FMT_VARIADIC_CTOR(ctor, func, arg0_type, arg1_type) \ - FMT_CTOR(ctor, func, arg0_type, arg1_type, 1) \ - FMT_CTOR(ctor, func, arg0_type, arg1_type, 2) \ - FMT_CTOR(ctor, func, arg0_type, arg1_type, 3) \ - FMT_CTOR(ctor, func, arg0_type, arg1_type, 4) \ - FMT_CTOR(ctor, func, arg0_type, arg1_type, 5) \ - FMT_CTOR(ctor, func, arg0_type, arg1_type, 6) \ - FMT_CTOR(ctor, func, arg0_type, arg1_type, 7) \ - FMT_CTOR(ctor, func, arg0_type, arg1_type, 8) \ - FMT_CTOR(ctor, func, arg0_type, arg1_type, 9) \ - FMT_CTOR(ctor, func, arg0_type, arg1_type, 10) -#endif - // Generates a comma-separated list with results of applying f to pairs // (argument, index). #define FMT_FOR_EACH1(f, x0) f(x0, 0) @@ -3365,8 +3286,7 @@ void arg(WStringRef, const internal::NamedArg&) FMT_DELETED_OR_UNDEFINED; #define FMT_ADD_ARG_NAME(type, index) type arg##index #define FMT_GET_ARG_NAME(type, index) arg##index -#if FMT_USE_VARIADIC_TEMPLATES -# define FMT_VARIADIC_(Char, ReturnType, func, call, ...) \ +#define FMT_VARIADIC_(Char, ReturnType, func, call, ...) \ template \ ReturnType func(FMT_FOR_EACH(FMT_ADD_ARG_NAME, __VA_ARGS__), \ const Args & ... args) { \ @@ -3376,39 +3296,6 @@ void arg(WStringRef, const internal::NamedArg&) FMT_DELETED_OR_UNDEFINED; call(FMT_FOR_EACH(FMT_GET_ARG_NAME, __VA_ARGS__), \ fmt::ArgList(fmt::internal::make_type(args...), array)); \ } -#else -// Defines a wrapper for a function taking __VA_ARGS__ arguments -// and n additional arguments of arbitrary types. -# define FMT_WRAP(Char, ReturnType, func, call, n, ...) \ - template \ - inline ReturnType func(FMT_FOR_EACH(FMT_ADD_ARG_NAME, __VA_ARGS__), \ - FMT_GEN(n, FMT_MAKE_ARG)) { \ - fmt::internal::ArgArray::Type arr; \ - FMT_GEN(n, FMT_ASSIGN_##Char); \ - call(FMT_FOR_EACH(FMT_GET_ARG_NAME, __VA_ARGS__), fmt::ArgList( \ - fmt::internal::make_type(FMT_GEN(n, FMT_MAKE_REF2)), arr)); \ - } - -# define FMT_VARIADIC_(Char, ReturnType, func, call, ...) \ - inline ReturnType func(FMT_FOR_EACH(FMT_ADD_ARG_NAME, __VA_ARGS__)) { \ - call(FMT_FOR_EACH(FMT_GET_ARG_NAME, __VA_ARGS__), fmt::ArgList()); \ - } \ - FMT_WRAP(Char, ReturnType, func, call, 1, __VA_ARGS__) \ - FMT_WRAP(Char, ReturnType, func, call, 2, __VA_ARGS__) \ - FMT_WRAP(Char, ReturnType, func, call, 3, __VA_ARGS__) \ - FMT_WRAP(Char, ReturnType, func, call, 4, __VA_ARGS__) \ - FMT_WRAP(Char, ReturnType, func, call, 5, __VA_ARGS__) \ - FMT_WRAP(Char, ReturnType, func, call, 6, __VA_ARGS__) \ - FMT_WRAP(Char, ReturnType, func, call, 7, __VA_ARGS__) \ - FMT_WRAP(Char, ReturnType, func, call, 8, __VA_ARGS__) \ - FMT_WRAP(Char, ReturnType, func, call, 9, __VA_ARGS__) \ - FMT_WRAP(Char, ReturnType, func, call, 10, __VA_ARGS__) \ - FMT_WRAP(Char, ReturnType, func, call, 11, __VA_ARGS__) \ - FMT_WRAP(Char, ReturnType, func, call, 12, __VA_ARGS__) \ - FMT_WRAP(Char, ReturnType, func, call, 13, __VA_ARGS__) \ - FMT_WRAP(Char, ReturnType, func, call, 14, __VA_ARGS__) \ - FMT_WRAP(Char, ReturnType, func, call, 15, __VA_ARGS__) -#endif // FMT_USE_VARIADIC_TEMPLATES /** \rst diff --git a/test/macro-test.cc b/test/macro-test.cc index f6763eae..ea2fbfd6 100644 --- a/test/macro-test.cc +++ b/test/macro-test.cc @@ -76,13 +76,6 @@ int result; MAKE_TEST(test_func) typedef char Char; -FMT_WRAP1(test_func, const char *, 1) - -TEST(UtilTest, Wrap1) { - result = 0; - test_func("", 42); - EXPECT_EQ(42, result); -} MAKE_TEST(test_variadic_void) FMT_VARIADIC_VOID(test_variadic_void, const char *) From fc73e10620500af37ef8d5260dbdebc1647aae30 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Thu, 25 Aug 2016 08:50:07 -0700 Subject: [PATCH 003/340] ArgList -> format_args --- fmt/format.cc | 26 +++++++++--------- fmt/format.h | 50 +++++++++++++++++------------------ fmt/ostream.cc | 2 +- fmt/ostream.h | 2 +- fmt/posix.h | 2 +- fmt/printf.h | 16 +++++------ test/custom-formatter-test.cc | 4 +-- test/format-test.cc | 4 +-- test/macro-test.cc | 4 +-- test/ostream-test.cc | 2 +- test/util-test.cc | 6 ++--- 11 files changed, 59 insertions(+), 59 deletions(-) diff --git a/fmt/format.cc b/fmt/format.cc index 7fd0308e..8b175bbf 100644 --- a/fmt/format.cc +++ b/fmt/format.cc @@ -223,7 +223,7 @@ FMT_FUNC void format_system_error( } // namespace internal FMT_FUNC void SystemError::init( - int err_code, CStringRef format_str, ArgList args) { + int err_code, CStringRef format_str, format_args args) { error_code_ = err_code; MemoryWriter w; format_system_error(w, err_code, format(format_str, args)); @@ -347,7 +347,7 @@ FMT_FUNC int internal::UTF16ToUTF8::convert(WStringRef s) { } FMT_FUNC void WindowsError::init( - int err_code, CStringRef format_str, ArgList args) { + int err_code, CStringRef format_str, format_args args) { error_code_ = err_code; MemoryWriter w; internal::format_windows_error(w, err_code, format(format_str, args)); @@ -404,13 +404,13 @@ FMT_FUNC void format_system_error( } template -void internal::ArgMap::init(const ArgList &args) { +void internal::ArgMap::init(const format_args &args) { if (!map_.empty()) return; typedef internal::NamedArg NamedArg; const NamedArg *named_arg = 0; bool use_values = - args.type(ArgList::MAX_PACKED_ARGS - 1) == internal::Arg::NONE; + args.type(format_args::MAX_PACKED_ARGS - 1) == internal::Arg::NONE; if (use_values) { for (unsigned i = 0;/*nothing*/; ++i) { internal::Arg::Type arg_type = args.type(i); @@ -427,14 +427,14 @@ void internal::ArgMap::init(const ArgList &args) { } return; } - for (unsigned i = 0; i != ArgList::MAX_PACKED_ARGS; ++i) { + for (unsigned i = 0; i != format_args::MAX_PACKED_ARGS; ++i) { internal::Arg::Type arg_type = args.type(i); if (arg_type == internal::Arg::NAMED_ARG) { named_arg = static_cast(args.args_[i].pointer); map_.push_back(Pair(named_arg->name, *named_arg)); } } - for (unsigned i = ArgList::MAX_PACKED_ARGS;/*nothing*/; ++i) { + for (unsigned i = format_args::MAX_PACKED_ARGS;/*nothing*/; ++i) { switch (args.args_[i].type) { case internal::Arg::NONE: return; @@ -483,17 +483,17 @@ FMT_FUNC void report_windows_error( } #endif -FMT_FUNC void print(std::FILE *f, CStringRef format_str, ArgList args) { +FMT_FUNC void print(std::FILE *f, CStringRef format_str, format_args args) { MemoryWriter w; w.write(format_str, args); std::fwrite(w.data(), 1, w.size(), f); } -FMT_FUNC void print(CStringRef format_str, ArgList args) { +FMT_FUNC void print(CStringRef format_str, format_args args) { print(stdout, format_str, args); } -FMT_FUNC void print_colored(Color c, CStringRef format, ArgList args) { +FMT_FUNC void print_colored(Color c, CStringRef format, format_args args) { char escape[] = "\x1b[30m"; escape[3] = static_cast('0' + c); std::fputs(escape, stdout); @@ -502,9 +502,9 @@ FMT_FUNC void print_colored(Color c, CStringRef format, ArgList args) { } template -void printf(BasicWriter &w, BasicCStringRef format, ArgList args); +void printf(BasicWriter &w, BasicCStringRef format, format_args args); -FMT_FUNC int fprintf(std::FILE *f, CStringRef format, ArgList args) { +FMT_FUNC int fprintf(std::FILE *f, CStringRef format, format_args args) { MemoryWriter w; printf(w, format, args); std::size_t size = w.size(); @@ -519,7 +519,7 @@ template struct internal::BasicData; template void internal::FixedBuffer::grow(std::size_t); -template void internal::ArgMap::init(const ArgList &args); +template void internal::ArgMap::init(const format_args &args); template void PrintfFormatter::format(CStringRef format); @@ -535,7 +535,7 @@ template int internal::CharTraits::format_float( template void internal::FixedBuffer::grow(std::size_t); -template void internal::ArgMap::init(const ArgList &args); +template void internal::ArgMap::init(const format_args &args); template void PrintfFormatter::format(WCStringRef format); diff --git a/fmt/format.h b/fmt/format.h index 6f96e84c..7ca1de9b 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -1351,8 +1351,8 @@ template class ArgMap; } // namespace internal -/** An argument list. */ -class ArgList { +/** Formatting arguments. */ +class format_args { private: // To reduce compiled code size per formatting function call, types of first // MAX_PACKED_ARGS arguments are passed in the types_ field. @@ -1381,11 +1381,11 @@ class ArgList { // Maximum number of arguments with packed types. enum { MAX_PACKED_ARGS = 16 }; - ArgList() : types_(0) {} + format_args() : types_(0) {} - ArgList(ULongLong types, const internal::Value *values) + format_args(ULongLong types, const internal::Value *values) : types_(types), values_(values) {} - ArgList(ULongLong types, const internal::Arg *args) + format_args(ULongLong types, const internal::Arg *args) : types_(types), args_(args) {} /** Returns the argument at specified index. */ @@ -1809,7 +1809,7 @@ class ArgMap { MapType map_; public: - FMT_API void init(const ArgList &args); + FMT_API void init(const format_args &args); const internal::Arg* find(const fmt::BasicStringRef &name) const { // The list is unsorted, so just return the first matching name. @@ -1922,16 +1922,16 @@ class ArgFormatterBase : public ArgVisitor { class FormatterBase { private: - ArgList args_; + format_args args_; int next_arg_index_; // Returns the argument with specified index. FMT_API Arg do_get_arg(unsigned arg_index, const char *&error); protected: - const ArgList &args() const { return args_; } + const format_args &args() const { return args_; } - explicit FormatterBase(const ArgList &args) { + explicit FormatterBase(const format_args &args) { args_ = args; next_arg_index_ = 0; } @@ -2053,7 +2053,7 @@ class BasicFormatter : private internal::FormatterBase { appropriate lifetimes. \endrst */ - BasicFormatter(const ArgList &args, BasicWriter &w) + BasicFormatter(const format_args &args, BasicWriter &w) : internal::FormatterBase(args), writer_(w) {} /** Returns a reference to the writer associated with this formatter. */ @@ -2093,7 +2093,7 @@ inline uint64_t make_type(const T &arg) { return MakeValue< BasicFormatter >::type(arg); } -template +template struct ArgArray; template @@ -2143,7 +2143,7 @@ inline uint64_t make_type(const Arg &first, const Args & ... tail) { typedef fmt::internal::ArgArray ArgArray; \ typename ArgArray::Type array{ \ ArgArray::template make >(args)...}; \ - func(arg0, fmt::ArgList(fmt::internal::make_type(args...), array)); \ + func(arg0, fmt::format_args(fmt::internal::make_type(args...), array)); \ } // Defines a variadic constructor. @@ -2153,7 +2153,7 @@ inline uint64_t make_type(const Arg &first, const Args & ... tail) { typedef fmt::internal::ArgArray ArgArray; \ typename ArgArray::Type array{ \ ArgArray::template make >(args)...}; \ - func(arg0, arg1, fmt::ArgList(fmt::internal::make_type(args...), array)); \ + func(arg0, arg1, fmt::format_args(fmt::internal::make_type(args...), array)); \ } // Generates a comma-separated list with results of applying f to pairs @@ -2184,7 +2184,7 @@ inline uint64_t make_type(const Arg &first, const Args & ... tail) { */ class SystemError : public internal::RuntimeError { private: - void init(int err_code, CStringRef format_str, ArgList args); + void init(int err_code, CStringRef format_str, format_args args); protected: int error_code_; @@ -2213,7 +2213,7 @@ class SystemError : public internal::RuntimeError { \endrst */ SystemError(int error_code, CStringRef message) { - init(error_code, message, ArgList()); + init(error_code, message, format_args()); } FMT_VARIADIC_CTOR(SystemError, init, int, CStringRef) @@ -2433,7 +2433,7 @@ class BasicWriter { See also :ref:`syntax`. \endrst */ - void write(BasicCStringRef format, ArgList args) { + void write(BasicCStringRef format, format_args args) { BasicFormatter(args, *this).format(format); } FMT_VARIADIC_VOID(write, BasicCStringRef) @@ -3030,7 +3030,7 @@ FMT_API void report_system_error(int error_code, /** A Windows error. */ class WindowsError : public SystemError { private: - FMT_API void init(int error_code, CStringRef format_str, ArgList args); + FMT_API void init(int error_code, CStringRef format_str, format_args args); public: /** @@ -3062,7 +3062,7 @@ class WindowsError : public SystemError { \endrst */ WindowsError(int error_code, CStringRef message) { - init(error_code, message, ArgList()); + init(error_code, message, format_args()); } FMT_VARIADIC_CTOR(WindowsError, init, int, CStringRef) }; @@ -3082,7 +3082,7 @@ enum Color { BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE }; Example: print_colored(fmt::RED, "Elapsed time: {0:.2f} seconds", 1.23); */ -FMT_API void print_colored(Color c, CStringRef format, ArgList args); +FMT_API void print_colored(Color c, CStringRef format, format_args args); /** \rst @@ -3093,13 +3093,13 @@ FMT_API void print_colored(Color c, CStringRef format, ArgList args); std::string message = format("The answer is {}", 42); \endrst */ -inline std::string format(CStringRef format_str, ArgList args) { +inline std::string format(CStringRef format_str, format_args args) { MemoryWriter w; w.write(format_str, args); return w.str(); } -inline std::wstring format(WCStringRef format_str, ArgList args) { +inline std::wstring format(WCStringRef format_str, format_args args) { WMemoryWriter w; w.write(format_str, args); return w.str(); @@ -3114,7 +3114,7 @@ inline std::wstring format(WCStringRef format_str, ArgList args) { print(stderr, "Don't {}!", "panic"); \endrst */ -FMT_API void print(std::FILE *f, CStringRef format_str, ArgList args); +FMT_API void print(std::FILE *f, CStringRef format_str, format_args args); /** \rst @@ -3125,7 +3125,7 @@ FMT_API void print(std::FILE *f, CStringRef format_str, ArgList args); print("Elapsed time: {0:.2f} seconds", 1.23); \endrst */ -FMT_API void print(CStringRef format_str, ArgList args); +FMT_API void print(CStringRef format_str, format_args args); /** Fast integer formatter. @@ -3294,7 +3294,7 @@ void arg(WStringRef, const internal::NamedArg&) FMT_DELETED_OR_UNDEFINED; typename ArgArray::Type array{ \ ArgArray::template make >(args)...}; \ call(FMT_FOR_EACH(FMT_GET_ARG_NAME, __VA_ARGS__), \ - fmt::ArgList(fmt::internal::make_type(args...), array)); \ + fmt::format_args(fmt::internal::make_type(args...), array)); \ } /** @@ -3305,7 +3305,7 @@ void arg(WStringRef, const internal::NamedArg&) FMT_DELETED_OR_UNDEFINED; **Example**:: void print_error(const char *file, int line, const char *format, - fmt::ArgList args) { + fmt::format_args args) { fmt::print("{}: {}: ", file, line); fmt::print(format, args); } diff --git a/fmt/ostream.cc b/fmt/ostream.cc index 2890b4a8..92b00a09 100644 --- a/fmt/ostream.cc +++ b/fmt/ostream.cc @@ -27,7 +27,7 @@ FMT_FUNC void write(std::ostream &os, Writer &w) { } } -FMT_FUNC void print(std::ostream &os, CStringRef format_str, ArgList args) { +FMT_FUNC void print(std::ostream &os, CStringRef format_str, format_args args) { MemoryWriter w; w.write(format_str, args); internal::write(os, w); diff --git a/fmt/ostream.h b/fmt/ostream.h index e21b2f6d..db433ea0 100644 --- a/fmt/ostream.h +++ b/fmt/ostream.h @@ -95,7 +95,7 @@ void format_arg(BasicFormatter &f, print(cerr, "Don't {}!", "panic"); \endrst */ -FMT_API void print(std::ostream &os, CStringRef format_str, ArgList args); +FMT_API void print(std::ostream &os, CStringRef format_str, format_args args); FMT_VARIADIC(void, print, std::ostream &, CStringRef) } // namespace fmt diff --git a/fmt/posix.h b/fmt/posix.h index 7c2b0b5e..e6b2e900 100644 --- a/fmt/posix.h +++ b/fmt/posix.h @@ -166,7 +166,7 @@ public: // of MinGW that define fileno as a macro. int (fileno)() const; - void print(CStringRef format_str, const ArgList &args) { + void print(CStringRef format_str, const format_args &args) { fmt::print(file_, format_str, args); } FMT_VARIADIC(void, print, CStringRef) diff --git a/fmt/printf.h b/fmt/printf.h index e83a9976..9be2c424 100644 --- a/fmt/printf.h +++ b/fmt/printf.h @@ -262,7 +262,7 @@ class BasicPrintfArgFormatter : public internal::ArgFormatterBase { /** Formats an argument of a custom (user-defined) type. */ void visit_custom(internal::Arg::CustomValue c) { - BasicFormatter formatter(ArgList(), this->writer()); + BasicFormatter formatter(format_args(), this->writer()); const Char format_str[] = {'}', 0}; const Char *format = format_str; c.format(&formatter, c.value, &format); @@ -304,7 +304,7 @@ class PrintfFormatter : private internal::FormatterBase { appropriate lifetimes. \endrst */ - explicit PrintfFormatter(const ArgList &args, BasicWriter &w) + explicit PrintfFormatter(const format_args &args, BasicWriter &w) : FormatterBase(args), writer_(w) {} /** Formats stored arguments and writes the output to the writer. */ @@ -484,7 +484,7 @@ void PrintfFormatter::format(BasicCStringRef format_str) { } template -void printf(BasicWriter &w, BasicCStringRef format, ArgList args) { +void printf(BasicWriter &w, BasicCStringRef format, format_args args) { PrintfFormatter(args, w).format(format); } @@ -497,14 +497,14 @@ void printf(BasicWriter &w, BasicCStringRef format, ArgList args) { std::string message = fmt::sprintf("The answer is %d", 42); \endrst */ -inline std::string sprintf(CStringRef format, ArgList args) { +inline std::string sprintf(CStringRef format, format_args args) { MemoryWriter w; printf(w, format, args); return w.str(); } FMT_VARIADIC(std::string, sprintf, CStringRef) -inline std::wstring sprintf(WCStringRef format, ArgList args) { +inline std::wstring sprintf(WCStringRef format, format_args args) { WMemoryWriter w; printf(w, format, args); return w.str(); @@ -520,7 +520,7 @@ FMT_VARIADIC_W(std::wstring, sprintf, WCStringRef) fmt::fprintf(stderr, "Don't %s!", "panic"); \endrst */ -FMT_API int fprintf(std::FILE *f, CStringRef format, ArgList args); +FMT_API int fprintf(std::FILE *f, CStringRef format, format_args args); FMT_VARIADIC(int, fprintf, std::FILE *, CStringRef) /** @@ -532,7 +532,7 @@ FMT_VARIADIC(int, fprintf, std::FILE *, CStringRef) fmt::printf("Elapsed time: %.2f seconds", 1.23); \endrst */ -inline int printf(CStringRef format, ArgList args) { +inline int printf(CStringRef format, format_args args) { return fprintf(stdout, format, args); } FMT_VARIADIC(int, printf, CStringRef) @@ -546,7 +546,7 @@ FMT_VARIADIC(int, printf, CStringRef) fprintf(cerr, "Don't %s!", "panic"); \endrst */ -inline int fprintf(std::ostream &os, CStringRef format_str, ArgList args) { +inline int fprintf(std::ostream &os, CStringRef format_str, format_args args) { MemoryWriter w; printf(w, format_str, args); internal::write(os, w); diff --git a/test/custom-formatter-test.cc b/test/custom-formatter-test.cc index cc9c4485..436986c1 100644 --- a/test/custom-formatter-test.cc +++ b/test/custom-formatter-test.cc @@ -45,7 +45,7 @@ class CustomPrintfArgFormatter : } }; -std::string custom_format(const char *format_str, fmt::ArgList args) { +std::string custom_format(const char *format_str, fmt::format_args args) { fmt::MemoryWriter writer; // Pass custom argument formatter as a template arg to BasicFormatter. fmt::BasicFormatter formatter(args, writer); @@ -54,7 +54,7 @@ std::string custom_format(const char *format_str, fmt::ArgList args) { } FMT_VARIADIC(std::string, custom_format, const char *) -std::string custom_sprintf(const char* format_str, fmt::ArgList args){ +std::string custom_sprintf(const char* format_str, fmt::format_args args){ fmt::MemoryWriter writer; fmt::PrintfFormatter formatter(args, writer); formatter.format(format_str); diff --git a/test/format-test.cc b/test/format-test.cc index a92d875f..e18d136e 100644 --- a/test/format-test.cc +++ b/test/format-test.cc @@ -1564,7 +1564,7 @@ TEST(StrTest, Convert) { } std::string format_message(int id, const char *format, - const fmt::ArgList &args) { + const fmt::format_args &args) { MemoryWriter w; w.write("[{}] ", id); w.write(format, args); @@ -1643,7 +1643,7 @@ class MockArgFormatter : MOCK_METHOD1(visit_int, void (int value)); }; -void custom_format(const char *format_str, fmt::ArgList args) { +void custom_format(const char *format_str, fmt::format_args args) { fmt::MemoryWriter writer; fmt::BasicFormatter formatter(args, writer); formatter.format(format_str); diff --git a/test/macro-test.cc b/test/macro-test.cc index ea2fbfd6..ed35151b 100644 --- a/test/macro-test.cc +++ b/test/macro-test.cc @@ -67,7 +67,7 @@ TEST(UtilTest, NArg) { int result; #define MAKE_TEST(func) \ - void func(const char *, const fmt::ArgList &args) { \ + void func(const char *, const fmt::format_args &args) { \ result = 0; \ for (unsigned i = 0; args[i].type; ++i) \ result += args[i].int_value; \ @@ -91,7 +91,7 @@ struct S {}; #define GET_TYPE(n) S -int test_variadic(FMT_GEN(10, GET_TYPE), const fmt::ArgList &args) { \ +int test_variadic(FMT_GEN(10, GET_TYPE), const fmt::format_args &args) { \ int result = 0; \ for (unsigned i = 0; args[i].type; ++i) \ result += args[i].int_value; \ diff --git a/test/ostream-test.cc b/test/ostream-test.cc index fa2c40d6..9542a28c 100644 --- a/test/ostream-test.cc +++ b/test/ostream-test.cc @@ -67,7 +67,7 @@ struct TestArgFormatter : fmt::BasicArgFormatter { TEST(OStreamTest, CustomArg) { fmt::MemoryWriter writer; typedef fmt::BasicFormatter Formatter; - Formatter formatter(fmt::ArgList(), writer); + Formatter formatter(fmt::format_args(), writer); fmt::FormatSpec spec; TestArgFormatter af(formatter, spec, "}"); af.visit(fmt::internal::MakeArg(TestEnum())); diff --git a/test/util-test.cc b/test/util-test.cc index d67dd52c..376ea128 100644 --- a/test/util-test.cc +++ b/test/util-test.cc @@ -566,14 +566,14 @@ TEST(ArgTest, MakeArg) { EXPECT_EQ(fmt::internal::Arg::CUSTOM, arg.type); EXPECT_EQ(&t, arg.custom.value); fmt::MemoryWriter w; - fmt::BasicFormatter formatter(fmt::ArgList(), w); + fmt::BasicFormatter formatter(fmt::format_args(), w); const char *s = "}"; arg.custom.format(&formatter, &t, &s); EXPECT_EQ("test", w.str()); } -TEST(UtilTest, ArgList) { - fmt::ArgList args; +TEST(UtilTest, FormatArgs) { + fmt::format_args args; EXPECT_EQ(Arg::NONE, args[1].type); } From 4873685c7ef0c35accb07ae98071ac09f1cdb1c4 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Fri, 26 Aug 2016 06:44:41 -0700 Subject: [PATCH 004/340] ArgArray -> format_arg_store --- fmt/format.h | 66 +++++++++++++++++++++------------------------ test/CMakeLists.txt | 1 + 2 files changed, 31 insertions(+), 36 deletions(-) diff --git a/fmt/format.h b/fmt/format.h index 7ca1de9b..4093f3ea 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -37,6 +37,7 @@ #include #include #include +#include #include #include @@ -2093,34 +2094,33 @@ inline uint64_t make_type(const T &arg) { return MakeValue< BasicFormatter >::type(arg); } -template -struct ArgArray; +template +class format_arg_store { + private: + static const size_t NUM_ARGS = sizeof...(Args); + static const bool PACKED = NUM_ARGS <= format_args::MAX_PACKED_ARGS; -template -struct ArgArray { - typedef Value Type[N > 0 ? N : 1]; + typedef typename std::conditional::type value_type; - template - static Value make(const T &value) { -#ifdef __clang__ - Value result = MakeValue(value); - // Workaround a bug in Apple LLVM version 4.2 (clang-425.0.28) of clang: - // https://github.com/fmtlib/fmt/issues/276 - (void)result.custom.format; - return result; -#else - return MakeValue(value); -#endif - } + // If the arguments are not packed we add one more element to mark the end. + std::array data_; + + template + friend format_arg_store make_format_args(const A & ... args); + + public: + template + format_arg_store(const Args &... args, Formatter *) + : data_{MakeValue(args)...} {} + + const value_type *data() const { return data_.data(); } }; -template -struct ArgArray { - typedef Arg Type[N + 1]; // +1 for the list end Arg::NONE - - template - static Arg make(const T &value) { return MakeArg(value); } -}; +template +inline format_arg_store make_format_args(const Args & ... args) { + Formatter *f = nullptr; + return format_arg_store(args..., f); +} template inline uint64_t make_type(const Arg &first, const Args & ... tail) { @@ -2140,20 +2140,16 @@ inline uint64_t make_type(const Arg &first, const Args & ... tail) { # define FMT_VARIADIC_VOID(func, arg_type) \ template \ void func(arg_type arg0, const Args & ... args) { \ - typedef fmt::internal::ArgArray ArgArray; \ - typename ArgArray::Type array{ \ - ArgArray::template make >(args)...}; \ - func(arg0, fmt::format_args(fmt::internal::make_type(args...), array)); \ + auto store = fmt::internal::make_format_args< fmt::BasicFormatter >(args...); \ + func(arg0, fmt::format_args(fmt::internal::make_type(args...), store.data())); \ } // Defines a variadic constructor. # define FMT_VARIADIC_CTOR(ctor, func, arg0_type, arg1_type) \ template \ ctor(arg0_type arg0, arg1_type arg1, const Args & ... args) { \ - typedef fmt::internal::ArgArray ArgArray; \ - typename ArgArray::Type array{ \ - ArgArray::template make >(args)...}; \ - func(arg0, arg1, fmt::format_args(fmt::internal::make_type(args...), array)); \ + auto store = internal::make_format_args< fmt::BasicFormatter >(args...); \ + func(arg0, arg1, fmt::format_args(fmt::internal::make_type(args...), store.data())); \ } // Generates a comma-separated list with results of applying f to pairs @@ -3290,11 +3286,9 @@ void arg(WStringRef, const internal::NamedArg&) FMT_DELETED_OR_UNDEFINED; template \ ReturnType func(FMT_FOR_EACH(FMT_ADD_ARG_NAME, __VA_ARGS__), \ const Args & ... args) { \ - typedef fmt::internal::ArgArray ArgArray; \ - typename ArgArray::Type array{ \ - ArgArray::template make >(args)...}; \ + auto store = fmt::internal::make_format_args< fmt::BasicFormatter >(args...); \ call(FMT_FOR_EACH(FMT_GET_ARG_NAME, __VA_ARGS__), \ - fmt::format_args(fmt::internal::make_type(args...), array)); \ + fmt::format_args(fmt::internal::make_type(args...), store.data())); \ } /** diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 86e72b97..95ddca55 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -121,6 +121,7 @@ endif () check_cxx_compiler_flag(-fno-exceptions HAVE_FNO_EXCEPTIONS_FLAG) if (HAVE_FNO_EXCEPTIONS_FLAG) add_library(noexception-test ../fmt/format.cc) + target_compile_options(noexception-test PUBLIC ${CPP11_FLAG}) target_include_directories(noexception-test PRIVATE ${PROJECT_SOURCE_DIR}) target_compile_options(noexception-test PRIVATE -fno-exceptions) endif () From 43c0095aa34727ebc36f23dcfe98283ff950363b Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Fri, 26 Aug 2016 08:50:09 -0700 Subject: [PATCH 005/340] Refactor type mapping --- fmt/format.h | 114 +++++++++++++++++++++++++++++++--------------- test/util-test.cc | 2 +- 2 files changed, 79 insertions(+), 37 deletions(-) diff --git a/fmt/format.h b/fmt/format.h index 4093f3ea..3bf486f0 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -1212,8 +1212,7 @@ class MakeValue : public Arg { MakeValue() {} #define FMT_MAKE_VALUE_(Type, field, TYPE, rhs) \ - MakeValue(Type value) { field = rhs; } \ - static uint64_t type(Type) { return Arg::TYPE; } + MakeValue(Type value) { field = rhs; } #define FMT_MAKE_VALUE(Type, field, TYPE) \ FMT_MAKE_VALUE_(Type, field, TYPE, value) @@ -1232,9 +1231,6 @@ class MakeValue : public Arg { else long_long_value = value; } - static uint64_t type(long) { - return sizeof(long) == sizeof(int) ? Arg::INT : Arg::LONG_LONG; - } MakeValue(unsigned long value) { if (const_check(sizeof(unsigned long) == sizeof(unsigned))) @@ -1242,10 +1238,6 @@ class MakeValue : public Arg { else ulong_long_value = value; } - static uint64_t type(unsigned long) { - return sizeof(unsigned long) == sizeof(unsigned) ? - Arg::UINT : Arg::ULONG_LONG; - } FMT_MAKE_VALUE(LongLong, long_long_value, LONG_LONG) FMT_MAKE_VALUE(ULongLong, ulong_long_value, ULONG_LONG) @@ -1260,12 +1252,10 @@ class MakeValue : public Arg { MakeValue(typename WCharHelper::Supported value) { int_value = value; } - static uint64_t type(wchar_t) { return Arg::CHAR; } #endif #define FMT_MAKE_STR_VALUE(Type, TYPE) \ - MakeValue(Type value) { set_string(value); } \ - static uint64_t type(Type) { return Arg::TYPE; } + MakeValue(Type value) { set_string(value); } FMT_MAKE_VALUE(char *, string.value, CSTRING) FMT_MAKE_VALUE(const char *, string.value, CSTRING) @@ -1280,8 +1270,7 @@ class MakeValue : public Arg { #define FMT_MAKE_WSTR_VALUE(Type, TYPE) \ MakeValue(typename WCharHelper::Supported value) { \ set_string(value); \ - } \ - static uint64_t type(Type) { return Arg::TYPE; } + } FMT_MAKE_WSTR_VALUE(wchar_t *, WSTRING) FMT_MAKE_WSTR_VALUE(const wchar_t *, WSTRING) @@ -1305,20 +1294,74 @@ class MakeValue : public Arg { int_value = value; } - template - static uint64_t type(const T &) { - return ConvertToInt::value ? Arg::INT : Arg::CUSTOM; - } - // Additional template param `Char_` is needed here because make_type always // uses char. template MakeValue(const NamedArg &value) { pointer = &value; } - - template - static uint64_t type(const NamedArg &) { return Arg::NAMED_ARG; } }; +template +struct IsNamedArg : std::false_type {}; + +template +struct IsNamedArg< NamedArg > : std::true_type {}; + +typedef Value::Type Type; + +template +constexpr Type gettype() { + return IsNamedArg::value ? + Arg::NAMED_ARG : (ConvertToInt::value ? Arg::INT : Arg::CUSTOM); +} + +template <> constexpr Type gettype() { return Arg::BOOL; } +template <> constexpr Type gettype() { return Arg::INT; } +template <> constexpr Type gettype() { return Arg::UINT; } +template <> constexpr Type gettype() { return Arg::INT; } +template <> constexpr Type gettype() { return Arg::UINT; } +template <> constexpr Type gettype() { + return sizeof(long) == sizeof(int) ? Arg::INT : Arg::LONG_LONG; +} +template <> constexpr Type gettype() { + return sizeof(unsigned long) == sizeof(unsigned) ? + Arg::UINT : Arg::ULONG_LONG; +} +template <> constexpr Type gettype() { return Arg::LONG_LONG; } +template <> constexpr Type gettype() { return Arg::ULONG_LONG; } +template <> constexpr Type gettype() { return Arg::DOUBLE; } +template <> constexpr Type gettype() { return Arg::DOUBLE; } +template <> constexpr Type gettype() { return Arg::LONG_DOUBLE; } +template <> constexpr Type gettype() { return Arg::INT; } +template <> constexpr Type gettype() { return Arg::UINT; } +template <> constexpr Type gettype() { return Arg::CHAR; } + +#if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED) +template <> constexpr Type gettype() { return Arg::CHAR; } +#endif + +template <> constexpr Type gettype() { return Arg::CSTRING; } +template <> constexpr Type gettype() { return Arg::CSTRING; } +template <> constexpr Type gettype() { return Arg::CSTRING; } +template <> constexpr Type gettype() { + return Arg::CSTRING; +} +template <> constexpr Type gettype() { return Arg::CSTRING; } +template <> constexpr Type gettype() { + return Arg::CSTRING; +} +template <> constexpr Type gettype() { return Arg::STRING; } +template <> constexpr Type gettype() { return Arg::STRING; } +template <> constexpr Type gettype() { return Arg::CSTRING; } +template <> constexpr Type gettype() { return Arg::WSTRING; } +template <> constexpr Type gettype() { return Arg::WSTRING; } +template <> constexpr Type gettype() { return Arg::WSTRING; } +template <> constexpr Type gettype() { return Arg::WSTRING; } +template <> constexpr Type gettype() { return Arg::POINTER; } +template <> constexpr Type gettype() { return Arg::POINTER; } + +template +constexpr Type type() { return gettype::type>(); } + template class MakeArg : public Arg { public: @@ -1329,7 +1372,7 @@ public: template MakeArg(const T &value) : Arg(MakeValue(value)) { - type = static_cast(MakeValue::type(value)); + type = internal::type(); } }; @@ -2087,13 +2130,15 @@ class BasicFormatter : private internal::FormatterBase { # define FMT_GEN15(f) FMT_GEN14(f), f(14) namespace internal { -inline uint64_t make_type() { return 0; } -template -inline uint64_t make_type(const T &arg) { - return MakeValue< BasicFormatter >::type(arg); +template +constexpr uint64_t make_type() { + return type() | (make_type() << 4); } +template <> +constexpr uint64_t make_type() { return 0; } + template class format_arg_store { private: @@ -2102,13 +2147,15 @@ class format_arg_store { typedef typename std::conditional::type value_type; - // If the arguments are not packed we add one more element to mark the end. + // If the arguments are not packed, add one more element to mark the end. std::array data_; template friend format_arg_store make_format_args(const A & ... args); public: + static const uint64_t TYPES = make_type(); + template format_arg_store(const Args &... args, Formatter *) : data_{MakeValue(args)...} {} @@ -2121,11 +2168,6 @@ inline format_arg_store make_format_args(const Args & ... args) { Formatter *f = nullptr; return format_arg_store(args..., f); } - -template -inline uint64_t make_type(const Arg &first, const Args & ... tail) { - return make_type(first) | (make_type(tail...) << 4); -} } // namespace internal # define FMT_MAKE_TEMPLATE_ARG(n) typename T##n @@ -2141,7 +2183,7 @@ inline uint64_t make_type(const Arg &first, const Args & ... tail) { template \ void func(arg_type arg0, const Args & ... args) { \ auto store = fmt::internal::make_format_args< fmt::BasicFormatter >(args...); \ - func(arg0, fmt::format_args(fmt::internal::make_type(args...), store.data())); \ + func(arg0, fmt::format_args(store.TYPES, store.data())); \ } // Defines a variadic constructor. @@ -2149,7 +2191,7 @@ inline uint64_t make_type(const Arg &first, const Args & ... tail) { template \ ctor(arg0_type arg0, arg1_type arg1, const Args & ... args) { \ auto store = internal::make_format_args< fmt::BasicFormatter >(args...); \ - func(arg0, arg1, fmt::format_args(fmt::internal::make_type(args...), store.data())); \ + func(arg0, arg1, fmt::format_args(store.TYPES, store.data())); \ } // Generates a comma-separated list with results of applying f to pairs @@ -3288,7 +3330,7 @@ void arg(WStringRef, const internal::NamedArg&) FMT_DELETED_OR_UNDEFINED; const Args & ... args) { \ auto store = fmt::internal::make_format_args< fmt::BasicFormatter >(args...); \ call(FMT_FOR_EACH(FMT_GET_ARG_NAME, __VA_ARGS__), \ - fmt::format_args(fmt::internal::make_type(args...), store.data())); \ + fmt::format_args(store.TYPES, store.data())); \ } /** diff --git a/test/util-test.cc b/test/util-test.cc index 376ea128..6c1a2c0d 100644 --- a/test/util-test.cc +++ b/test/util-test.cc @@ -72,7 +72,7 @@ template Arg make_arg(const T &value) { typedef fmt::internal::MakeValue< fmt::BasicFormatter > MakeValue; Arg arg = MakeValue(value); - arg.type = static_cast(MakeValue::type(value)); + arg.type = fmt::internal::type(); return arg; } } // namespace From b903f5c1233d1073a2587b25a4b75a3324cc48b0 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Fri, 26 Aug 2016 09:10:23 -0700 Subject: [PATCH 006/340] format -> vformat --- fmt/format.cc | 2 +- fmt/format.h | 15 ++++++++++----- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/fmt/format.cc b/fmt/format.cc index 8b175bbf..3b46ded2 100644 --- a/fmt/format.cc +++ b/fmt/format.cc @@ -226,7 +226,7 @@ FMT_FUNC void SystemError::init( int err_code, CStringRef format_str, format_args args) { error_code_ = err_code; MemoryWriter w; - format_system_error(w, err_code, format(format_str, args)); + format_system_error(w, err_code, vformat(format_str, args)); std::runtime_error &base = *this; base = std::runtime_error(w.str()); } diff --git a/fmt/format.h b/fmt/format.h index 3bf486f0..10ae61bd 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -3122,6 +3122,12 @@ enum Color { BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE }; */ FMT_API void print_colored(Color c, CStringRef format, format_args args); +inline std::string vformat(CStringRef format_str, format_args args) { + MemoryWriter w; + w.write(format_str, args); + return w.str(); +} + /** \rst Formats arguments and returns the result as a string. @@ -3131,10 +3137,10 @@ FMT_API void print_colored(Color c, CStringRef format, format_args args); std::string message = format("The answer is {}", 42); \endrst */ -inline std::string format(CStringRef format_str, format_args args) { - MemoryWriter w; - w.write(format_str, args); - return w.str(); +template +inline std::string format(CStringRef format_str, const Args & ... args) { + auto vargs = internal::make_format_args>(args...); + vformat(format_str, format_args(vargs.TYPES, vargs.data())); } inline std::wstring format(WCStringRef format_str, format_args args) { @@ -3389,7 +3395,6 @@ void arg(WStringRef, const internal::NamedArg&) FMT_DELETED_OR_UNDEFINED; #define FMT_CAPTURE_W(...) FMT_FOR_EACH(FMT_CAPTURE_ARG_W_, __VA_ARGS__) namespace fmt { -FMT_VARIADIC(std::string, format, CStringRef) FMT_VARIADIC_W(std::wstring, format, WCStringRef) FMT_VARIADIC(void, print, CStringRef) FMT_VARIADIC(void, print, std::FILE *, CStringRef) From a0190e4bbdbadbc282249d5051d11660f561796b Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Fri, 26 Aug 2016 10:26:33 -0700 Subject: [PATCH 007/340] Add a missing include --- fmt/format.h | 1 + 1 file changed, 1 insertion(+) diff --git a/fmt/format.h b/fmt/format.h index 10ae61bd..f1194e06 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -28,6 +28,7 @@ #ifndef FMT_FORMAT_H_ #define FMT_FORMAT_H_ +#include #include #include #include From 621447fece184d41bd8ba33c9f50742be44dbec4 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Fri, 26 Aug 2016 14:41:18 -0700 Subject: [PATCH 008/340] Make initialization C++11-compatible --- fmt/format.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fmt/format.h b/fmt/format.h index f1194e06..5e8680c7 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -2159,7 +2159,7 @@ class format_arg_store { template format_arg_store(const Args &... args, Formatter *) - : data_{MakeValue(args)...} {} + : data_{{MakeValue(args)...}} {} const value_type *data() const { return data_.data(); } }; From ece7ae5f49897a8a92ac2598d26e966914474621 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Fri, 26 Aug 2016 15:09:40 -0700 Subject: [PATCH 009/340] Make format_arg_store convertible to format_args --- fmt/format.cc | 6 +-- fmt/format.h | 112 +++++++++++++++++++++++++------------------------- 2 files changed, 59 insertions(+), 59 deletions(-) diff --git a/fmt/format.cc b/fmt/format.cc index 3b46ded2..c4d67d56 100644 --- a/fmt/format.cc +++ b/fmt/format.cc @@ -410,7 +410,7 @@ void internal::ArgMap::init(const format_args &args) { typedef internal::NamedArg NamedArg; const NamedArg *named_arg = 0; bool use_values = - args.type(format_args::MAX_PACKED_ARGS - 1) == internal::Arg::NONE; + args.type(MAX_PACKED_ARGS - 1) == internal::Arg::NONE; if (use_values) { for (unsigned i = 0;/*nothing*/; ++i) { internal::Arg::Type arg_type = args.type(i); @@ -427,14 +427,14 @@ void internal::ArgMap::init(const format_args &args) { } return; } - for (unsigned i = 0; i != format_args::MAX_PACKED_ARGS; ++i) { + for (unsigned i = 0; i != MAX_PACKED_ARGS; ++i) { internal::Arg::Type arg_type = args.type(i); if (arg_type == internal::Arg::NAMED_ARG) { named_arg = static_cast(args.args_[i].pointer); map_.push_back(Pair(named_arg->name, *named_arg)); } } - for (unsigned i = format_args::MAX_PACKED_ARGS;/*nothing*/; ++i) { + for (unsigned i = MAX_PACKED_ARGS;/*nothing*/; ++i) { switch (args.args_[i].type) { case internal::Arg::NONE: return; diff --git a/fmt/format.h b/fmt/format.h index 5e8680c7..e05fa09f 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -1394,6 +1394,47 @@ class RuntimeError : public std::runtime_error { template class ArgMap; + +template +constexpr uint64_t make_type() { + return type() | (make_type() << 4); +} + +template <> +constexpr uint64_t make_type() { return 0; } + +// Maximum number of arguments with packed types. +enum { MAX_PACKED_ARGS = 16 }; + +template +class format_arg_store { + private: + static const size_t NUM_ARGS = sizeof...(Args); + static const bool PACKED = NUM_ARGS <= MAX_PACKED_ARGS; + + typedef typename std::conditional::type value_type; + + // If the arguments are not packed, add one more element to mark the end. + std::array data_; + + template + friend format_arg_store make_format_args(const A & ... args); + + public: + static const uint64_t TYPES = make_type(); + + template + format_arg_store(const Args &... args, Formatter *) + : data_{{MakeValue(args)...}} {} + + const value_type *data() const { return data_.data(); } +}; + +template +inline format_arg_store make_format_args(const Args & ... args) { + Formatter *f = nullptr; + return format_arg_store(args..., f); +} } // namespace internal /** Formatting arguments. */ @@ -1422,23 +1463,24 @@ class format_args { template friend class internal::ArgMap; - public: - // Maximum number of arguments with packed types. - enum { MAX_PACKED_ARGS = 16 }; + void set_data(const internal::Value *values) { values_ = values; } + void set_data(const internal::Arg *args) { args_ = args; } + public: format_args() : types_(0) {} - format_args(ULongLong types, const internal::Value *values) - : types_(types), values_(values) {} - format_args(ULongLong types, const internal::Arg *args) - : types_(types), args_(args) {} + template + format_args(const internal::format_arg_store &store) + : types_(store.TYPES) { + set_data(store.data()); + } /** Returns the argument at specified index. */ internal::Arg operator[](unsigned index) const { using internal::Arg; Arg arg; - bool use_values = type(MAX_PACKED_ARGS - 1) == Arg::NONE; - if (index < MAX_PACKED_ARGS) { + bool use_values = type(internal::MAX_PACKED_ARGS - 1) == Arg::NONE; + if (index < internal::MAX_PACKED_ARGS) { Arg::Type arg_type = type(index); internal::Value &val = arg; if (arg_type != Arg::NONE) @@ -1452,7 +1494,7 @@ class format_args { arg.type = Arg::NONE; return arg; } - for (unsigned i = MAX_PACKED_ARGS; i <= index; ++i) { + for (unsigned i = internal::MAX_PACKED_ARGS; i <= index; ++i) { if (args_[i].type == Arg::NONE) return args_[i]; } @@ -2130,47 +2172,6 @@ class BasicFormatter : private internal::FormatterBase { # define FMT_GEN14(f) FMT_GEN13(f), f(13) # define FMT_GEN15(f) FMT_GEN14(f), f(14) -namespace internal { - -template -constexpr uint64_t make_type() { - return type() | (make_type() << 4); -} - -template <> -constexpr uint64_t make_type() { return 0; } - -template -class format_arg_store { - private: - static const size_t NUM_ARGS = sizeof...(Args); - static const bool PACKED = NUM_ARGS <= format_args::MAX_PACKED_ARGS; - - typedef typename std::conditional::type value_type; - - // If the arguments are not packed, add one more element to mark the end. - std::array data_; - - template - friend format_arg_store make_format_args(const A & ... args); - - public: - static const uint64_t TYPES = make_type(); - - template - format_arg_store(const Args &... args, Formatter *) - : data_{{MakeValue(args)...}} {} - - const value_type *data() const { return data_.data(); } -}; - -template -inline format_arg_store make_format_args(const Args & ... args) { - Formatter *f = nullptr; - return format_arg_store(args..., f); -} -} // namespace internal - # define FMT_MAKE_TEMPLATE_ARG(n) typename T##n # define FMT_MAKE_ARG_TYPE(n) T##n # define FMT_MAKE_ARG(n) const T##n &v##n @@ -2184,7 +2185,7 @@ inline format_arg_store make_format_args(const Args & ... args) { template \ void func(arg_type arg0, const Args & ... args) { \ auto store = fmt::internal::make_format_args< fmt::BasicFormatter >(args...); \ - func(arg0, fmt::format_args(store.TYPES, store.data())); \ + func(arg0, fmt::format_args(store)); \ } // Defines a variadic constructor. @@ -2192,7 +2193,7 @@ inline format_arg_store make_format_args(const Args & ... args) { template \ ctor(arg0_type arg0, arg1_type arg1, const Args & ... args) { \ auto store = internal::make_format_args< fmt::BasicFormatter >(args...); \ - func(arg0, arg1, fmt::format_args(store.TYPES, store.data())); \ + func(arg0, arg1, fmt::format_args(store)); \ } // Generates a comma-separated list with results of applying f to pairs @@ -3141,7 +3142,7 @@ inline std::string vformat(CStringRef format_str, format_args args) { template inline std::string format(CStringRef format_str, const Args & ... args) { auto vargs = internal::make_format_args>(args...); - vformat(format_str, format_args(vargs.TYPES, vargs.data())); + return vformat(format_str, vargs); } inline std::wstring format(WCStringRef format_str, format_args args) { @@ -3336,8 +3337,7 @@ void arg(WStringRef, const internal::NamedArg&) FMT_DELETED_OR_UNDEFINED; ReturnType func(FMT_FOR_EACH(FMT_ADD_ARG_NAME, __VA_ARGS__), \ const Args & ... args) { \ auto store = fmt::internal::make_format_args< fmt::BasicFormatter >(args...); \ - call(FMT_FOR_EACH(FMT_GET_ARG_NAME, __VA_ARGS__), \ - fmt::format_args(store.TYPES, store.data())); \ + call(FMT_FOR_EACH(FMT_GET_ARG_NAME, __VA_ARGS__), fmt::format_args(store)); \ } /** From 0028ce57b63f42d0955ef6c14ae60262573637d2 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Fri, 26 Aug 2016 17:23:13 -0700 Subject: [PATCH 010/340] Get rid of FMT_VARIADIC --- fmt/format.cc | 15 ++++---- fmt/format.h | 70 ++++++++++++++--------------------- fmt/ostream.cc | 3 +- fmt/ostream.h | 10 ++++- fmt/posix.h | 11 ++++-- fmt/printf.h | 65 ++++++++++++++++++++++---------- test/custom-formatter-test.cc | 18 +++++++-- test/format-test.cc | 18 ++++++--- test/macro-test.cc | 21 ----------- 9 files changed, 127 insertions(+), 104 deletions(-) diff --git a/fmt/format.cc b/fmt/format.cc index c4d67d56..5137feb4 100644 --- a/fmt/format.cc +++ b/fmt/format.cc @@ -483,28 +483,29 @@ FMT_FUNC void report_windows_error( } #endif -FMT_FUNC void print(std::FILE *f, CStringRef format_str, format_args args) { +FMT_FUNC void vprint(std::FILE *f, CStringRef format_str, format_args args) { MemoryWriter w; w.write(format_str, args); std::fwrite(w.data(), 1, w.size(), f); } -FMT_FUNC void print(CStringRef format_str, format_args args) { - print(stdout, format_str, args); +FMT_FUNC void vprint(CStringRef format_str, format_args args) { + vprint(stdout, format_str, args); } -FMT_FUNC void print_colored(Color c, CStringRef format, format_args args) { +FMT_FUNC void vprint_colored(Color c, CStringRef format, format_args args) { char escape[] = "\x1b[30m"; escape[3] = static_cast('0' + c); std::fputs(escape, stdout); - print(format, args); + vprint(format, args); std::fputs(RESET_COLOR, stdout); } template -void printf(BasicWriter &w, BasicCStringRef format, format_args args); +void printf(BasicWriter &w, BasicCStringRef format, + format_args args); -FMT_FUNC int fprintf(std::FILE *f, CStringRef format, format_args args) { +FMT_FUNC int vfprintf(std::FILE *f, CStringRef format, format_args args) { MemoryWriter w; printf(w, format, args); std::size_t size = w.size(); diff --git a/fmt/format.h b/fmt/format.h index e05fa09f..b2645b63 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -3116,13 +3116,20 @@ FMT_API void report_windows_error(int error_code, enum Color { BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE }; +FMT_API void vprint_colored(Color c, CStringRef format, format_args args); + /** Formats a string and prints it to stdout using ANSI escape sequences to specify color (experimental). Example: print_colored(fmt::RED, "Elapsed time: {0:.2f} seconds", 1.23); */ -FMT_API void print_colored(Color c, CStringRef format, format_args args); +template +inline void print_colored(Color c, CStringRef format_str, + const Args & ... args) { + vprint_colored(c, format_str, + internal::make_format_args>(args...)); +} inline std::string vformat(CStringRef format_str, format_args args) { MemoryWriter w; @@ -3145,12 +3152,20 @@ inline std::string format(CStringRef format_str, const Args & ... args) { return vformat(format_str, vargs); } -inline std::wstring format(WCStringRef format_str, format_args args) { +inline std::wstring vformat(WCStringRef format_str, format_args args) { WMemoryWriter w; w.write(format_str, args); return w.str(); } +template +inline std::wstring format(WCStringRef format_str, const Args & ... args) { + auto vargs = internal::make_format_args>(args...); + return vformat(format_str, vargs); +} + +FMT_API void vprint(std::FILE *f, CStringRef format_str, format_args args); + /** \rst Prints formatted data to the file *f*. @@ -3160,7 +3175,13 @@ inline std::wstring format(WCStringRef format_str, format_args args) { print(stderr, "Don't {}!", "panic"); \endrst */ -FMT_API void print(std::FILE *f, CStringRef format_str, format_args args); +template +inline void print(std::FILE *f, CStringRef format_str, const Args & ... args) { + vprint(f, format_str, + internal::make_format_args>(args...)); +} + +FMT_API void vprint(CStringRef format_str, format_args args); /** \rst @@ -3171,7 +3192,10 @@ FMT_API void print(std::FILE *f, CStringRef format_str, format_args args); print("Elapsed time: {0:.2f} seconds", 1.23); \endrst */ -FMT_API void print(CStringRef format_str, format_args args); +template +inline void print(CStringRef format_str, const Args & ... args) { + vprint(format_str, internal::make_format_args>(args...)); +} /** Fast integer formatter. @@ -3340,39 +3364,6 @@ void arg(WStringRef, const internal::NamedArg&) FMT_DELETED_OR_UNDEFINED; call(FMT_FOR_EACH(FMT_GET_ARG_NAME, __VA_ARGS__), fmt::format_args(store)); \ } -/** - \rst - Defines a variadic function with the specified return type, function name - and argument types passed as variable arguments to this macro. - - **Example**:: - - void print_error(const char *file, int line, const char *format, - fmt::format_args args) { - fmt::print("{}: {}: ", file, line); - fmt::print(format, args); - } - FMT_VARIADIC(void, print_error, const char *, int, const char *) - - ``FMT_VARIADIC`` is used for compatibility with legacy C++ compilers that - don't implement variadic templates. You don't have to use this macro if - you don't need legacy compiler support and can use variadic templates - directly:: - - template - void print_error(const char *file, int line, const char *format, - const Args & ... args) { - fmt::print("{}: {}: ", file, line); - fmt::print(format, args...); - } - \endrst - */ -#define FMT_VARIADIC(ReturnType, func, ...) \ - FMT_VARIADIC_(char, ReturnType, func, return func, __VA_ARGS__) - -#define FMT_VARIADIC_W(ReturnType, func, ...) \ - FMT_VARIADIC_(wchar_t, ReturnType, func, return func, __VA_ARGS__) - #define FMT_CAPTURE_ARG_(id, index) ::fmt::arg(#id, id) #define FMT_CAPTURE_ARG_W_(id, index) ::fmt::arg(L###id, id) @@ -3396,11 +3387,6 @@ void arg(WStringRef, const internal::NamedArg&) FMT_DELETED_OR_UNDEFINED; #define FMT_CAPTURE_W(...) FMT_FOR_EACH(FMT_CAPTURE_ARG_W_, __VA_ARGS__) namespace fmt { -FMT_VARIADIC_W(std::wstring, format, WCStringRef) -FMT_VARIADIC(void, print, CStringRef) -FMT_VARIADIC(void, print, std::FILE *, CStringRef) -FMT_VARIADIC(void, print_colored, Color, CStringRef) - namespace internal { template inline bool is_name_start(Char c) { diff --git a/fmt/ostream.cc b/fmt/ostream.cc index 92b00a09..9719d248 100644 --- a/fmt/ostream.cc +++ b/fmt/ostream.cc @@ -27,7 +27,8 @@ FMT_FUNC void write(std::ostream &os, Writer &w) { } } -FMT_FUNC void print(std::ostream &os, CStringRef format_str, format_args args) { +FMT_FUNC void vprint(std::ostream &os, CStringRef format_str, + format_args args) { MemoryWriter w; w.write(format_str, args); internal::write(os, w); diff --git a/fmt/ostream.h b/fmt/ostream.h index db433ea0..89b4b872 100644 --- a/fmt/ostream.h +++ b/fmt/ostream.h @@ -86,6 +86,8 @@ void format_arg(BasicFormatter &f, format_str = f.format(format_str, MakeArg(str)); } +FMT_API void vprint(std::ostream &os, CStringRef format_str, format_args args); + /** \rst Prints formatted data to the stream *os*. @@ -95,8 +97,12 @@ void format_arg(BasicFormatter &f, print(cerr, "Don't {}!", "panic"); \endrst */ -FMT_API void print(std::ostream &os, CStringRef format_str, format_args args); -FMT_VARIADIC(void, print, std::ostream &, CStringRef) +template +inline void print(std::ostream &os, CStringRef format_str, + const Args & ... args) { + vprint(os, format_str, + internal::make_format_args>(args...)); +} } // namespace fmt #ifdef FMT_HEADER_ONLY diff --git a/fmt/posix.h b/fmt/posix.h index e6b2e900..78e72050 100644 --- a/fmt/posix.h +++ b/fmt/posix.h @@ -166,10 +166,15 @@ public: // of MinGW that define fileno as a macro. int (fileno)() const; - void print(CStringRef format_str, const format_args &args) { - fmt::print(file_, format_str, args); + void vprint(CStringRef format_str, const format_args &args) { + fmt::vprint(file_, format_str, args); + } + + template + inline void print(CStringRef format_str, const Args & ... args) { + vprint(format_str, + internal::make_format_args>(args...)); } - FMT_VARIADIC(void, print, CStringRef) }; // A file. Closed file is represented by a File object with descriptor -1. diff --git a/fmt/printf.h b/fmt/printf.h index 9be2c424..3d5507cd 100644 --- a/fmt/printf.h +++ b/fmt/printf.h @@ -484,10 +484,17 @@ void PrintfFormatter::format(BasicCStringRef format_str) { } template -void printf(BasicWriter &w, BasicCStringRef format, format_args args) { +void printf(BasicWriter &w, BasicCStringRef format, + format_args args) { PrintfFormatter(args, w).format(format); } +inline std::string vsprintf(CStringRef format, format_args args) { + MemoryWriter w; + printf(w, format, args); + return w.str(); +} + /** \rst Formats arguments and returns the result as a string. @@ -497,19 +504,25 @@ void printf(BasicWriter &w, BasicCStringRef format, format_args args std::string message = fmt::sprintf("The answer is %d", 42); \endrst */ -inline std::string sprintf(CStringRef format, format_args args) { - MemoryWriter w; - printf(w, format, args); - return w.str(); +template +inline std::string sprintf(CStringRef format_str, const Args & ... args) { + auto vargs = internal::make_format_args>(args...); + return vsprintf(format_str, vargs); } -FMT_VARIADIC(std::string, sprintf, CStringRef) -inline std::wstring sprintf(WCStringRef format, format_args args) { +inline std::wstring vsprintf(WCStringRef format, format_args args) { WMemoryWriter w; printf(w, format, args); return w.str(); } -FMT_VARIADIC_W(std::wstring, sprintf, WCStringRef) + +template +inline std::wstring sprintf(WCStringRef format_str, const Args & ... args) { + auto vargs = internal::make_format_args>(args...); + return vsprintf(format_str, vargs); +} + +FMT_API int vfprintf(std::FILE *f, CStringRef format, format_args args); /** \rst @@ -520,8 +533,15 @@ FMT_VARIADIC_W(std::wstring, sprintf, WCStringRef) fmt::fprintf(stderr, "Don't %s!", "panic"); \endrst */ -FMT_API int fprintf(std::FILE *f, CStringRef format, format_args args); -FMT_VARIADIC(int, fprintf, std::FILE *, CStringRef) +template +inline int fprintf(std::FILE *f, CStringRef format_str, const Args & ... args) { + auto vargs = internal::make_format_args>(args...); + return vfprintf(f, format_str, vargs); +} + +inline int vprintf(CStringRef format, format_args args) { + return vfprintf(stdout, format, args); +} /** \rst @@ -532,10 +552,18 @@ FMT_VARIADIC(int, fprintf, std::FILE *, CStringRef) fmt::printf("Elapsed time: %.2f seconds", 1.23); \endrst */ -inline int printf(CStringRef format, format_args args) { - return fprintf(stdout, format, args); +template +inline int printf(CStringRef format_str, const Args & ... args) { + auto vargs = internal::make_format_args>(args...); + return vprintf(format_str, vargs); +} + +inline int vfprintf(std::ostream &os, CStringRef format_str, format_args args) { + MemoryWriter w; + printf(w, format_str, args); + internal::write(os, w); + return static_cast(w.size()); } -FMT_VARIADIC(int, printf, CStringRef) /** \rst @@ -546,13 +574,12 @@ FMT_VARIADIC(int, printf, CStringRef) fprintf(cerr, "Don't %s!", "panic"); \endrst */ -inline int fprintf(std::ostream &os, CStringRef format_str, format_args args) { - MemoryWriter w; - printf(w, format_str, args); - internal::write(os, w); - return static_cast(w.size()); +template +inline int fprintf(std::ostream &os, CStringRef format_str, + const Args & ... args) { + auto vargs = internal::make_format_args>(args...); + return vfprintf(os, format_str, vargs); } -FMT_VARIADIC(int, fprintf, std::ostream &, CStringRef) } // namespace fmt #endif // FMT_PRINTF_H_ diff --git a/test/custom-formatter-test.cc b/test/custom-formatter-test.cc index 436986c1..2bcc1d65 100644 --- a/test/custom-formatter-test.cc +++ b/test/custom-formatter-test.cc @@ -45,22 +45,32 @@ class CustomPrintfArgFormatter : } }; -std::string custom_format(const char *format_str, fmt::format_args args) { +std::string vcustom_format(const char *format_str, fmt::format_args args) { fmt::MemoryWriter writer; // Pass custom argument formatter as a template arg to BasicFormatter. fmt::BasicFormatter formatter(args, writer); formatter.format(format_str); return writer.str(); } -FMT_VARIADIC(std::string, custom_format, const char *) -std::string custom_sprintf(const char* format_str, fmt::format_args args){ +template +std::string custom_format(const char *format_str, const Args & ... args) { + auto va = fmt::internal::make_format_args>(args...); + return vcustom_format(format_str, va); +} + +std::string vcustom_sprintf(const char* format_str, fmt::format_args args) { fmt::MemoryWriter writer; fmt::PrintfFormatter formatter(args, writer); formatter.format(format_str); return writer.str(); } -FMT_VARIADIC(std::string, custom_sprintf, const char*); + +template +std::string custom_sprintf(const char *format_str, const Args & ... args) { + auto va = fmt::internal::make_format_args>(args...); + return vcustom_sprintf(format_str, va); +} TEST(CustomFormatterTest, Format) { EXPECT_EQ("0.00", custom_format("{:.2f}", -.00001)); diff --git a/test/format-test.cc b/test/format-test.cc index e18d136e..fef96b1f 100644 --- a/test/format-test.cc +++ b/test/format-test.cc @@ -1563,15 +1563,18 @@ TEST(StrTest, Convert) { EXPECT_EQ("2012-12-9", s); } -std::string format_message(int id, const char *format, - const fmt::format_args &args) { +std::string vformat_message(int id, const char *format, fmt::format_args args) { MemoryWriter w; w.write("[{}] ", id); w.write(format, args); return w.str(); } -FMT_VARIADIC(std::string, format_message, int, const char *) +template +std::string format_message(int id, const char *format, const Args & ... args) { + auto va = fmt::internal::make_format_args>(args...); + return vformat_message(id, format, va); +} TEST(FormatTest, FormatMessageExample) { EXPECT_EQ("[42] something happened", @@ -1643,12 +1646,17 @@ class MockArgFormatter : MOCK_METHOD1(visit_int, void (int value)); }; -void custom_format(const char *format_str, fmt::format_args args) { +void vcustom_format(const char *format_str, fmt::format_args args) { fmt::MemoryWriter writer; fmt::BasicFormatter formatter(args, writer); formatter.format(format_str); } -FMT_VARIADIC(void, custom_format, const char *) + +template +void custom_format(const char *format_str, const Args & ... args) { + auto va = fmt::internal::make_format_args>(args...); + return vcustom_format(format_str, va); +} TEST(FormatTest, CustomArgFormatter) { custom_format("{}", 42); diff --git a/test/macro-test.cc b/test/macro-test.cc index ed35151b..b39fc495 100644 --- a/test/macro-test.cc +++ b/test/macro-test.cc @@ -85,24 +85,3 @@ TEST(UtilTest, VariadicVoid) { test_variadic_void("", 10, 20, 30, 40, 50, 60, 70, 80, 90, 100); EXPECT_EQ(550, result); } - -template -struct S {}; - -#define GET_TYPE(n) S - -int test_variadic(FMT_GEN(10, GET_TYPE), const fmt::format_args &args) { \ - int result = 0; \ - for (unsigned i = 0; args[i].type; ++i) \ - result += args[i].int_value; \ - return result; -} -FMT_VARIADIC(int, test_variadic, - S<0>, S<1>, S<2>, S<3>, S<4>, S<5>, S<6>, S<7>, S<8>, S<9>) - -#define MAKE_ARG(n) S() - -TEST(UtilTest, Variadic) { - EXPECT_EQ(550, test_variadic(FMT_GEN(10, MAKE_ARG), - 10, 20, 30, 40, 50, 60, 70, 80, 90, 100)); -} From 4ece95a75487f6330c964fc9c69ecb40835fb906 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sat, 27 Aug 2016 07:57:48 -0700 Subject: [PATCH 011/340] Make make_format_args public --- build/test/test | 1 + build/test/test-file | 1 + fmt/format.h | 29 ++++++++++++++--------------- fmt/ostream.h | 3 +-- fmt/posix.h | 3 +-- fmt/printf.h | 12 +++++------- test/custom-formatter-test.cc | 12 ++++++------ test/format-test.cc | 4 ++-- 8 files changed, 31 insertions(+), 34 deletions(-) create mode 100644 build/test/test create mode 100644 build/test/test-file diff --git a/build/test/test b/build/test/test new file mode 100644 index 00000000..50a6f636 --- /dev/null +++ b/build/test/test @@ -0,0 +1 @@ +there must be something here \ No newline at end of file diff --git a/build/test/test-file b/build/test/test-file new file mode 100644 index 00000000..2810a093 --- /dev/null +++ b/build/test/test-file @@ -0,0 +1 @@ +Don't panic! \ No newline at end of file diff --git a/fmt/format.h b/fmt/format.h index b2645b63..27155241 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -1405,14 +1405,16 @@ constexpr uint64_t make_type() { return 0; } // Maximum number of arguments with packed types. enum { MAX_PACKED_ARGS = 16 }; +} // namespace internal template class format_arg_store { private: static const size_t NUM_ARGS = sizeof...(Args); - static const bool PACKED = NUM_ARGS <= MAX_PACKED_ARGS; + static const bool PACKED = NUM_ARGS <= internal::MAX_PACKED_ARGS; - typedef typename std::conditional::type value_type; + typedef typename std::conditional< + PACKED, internal::Value, internal::Arg>::type value_type; // If the arguments are not packed, add one more element to mark the end. std::array data_; @@ -1421,11 +1423,11 @@ class format_arg_store { friend format_arg_store make_format_args(const A & ... args); public: - static const uint64_t TYPES = make_type(); + static const uint64_t TYPES = internal::make_type(); template format_arg_store(const Args &... args, Formatter *) - : data_{{MakeValue(args)...}} {} + : data_{{internal::MakeValue(args)...}} {} const value_type *data() const { return data_.data(); } }; @@ -1435,7 +1437,6 @@ inline format_arg_store make_format_args(const Args & ... args) { Formatter *f = nullptr; return format_arg_store(args..., f); } -} // namespace internal /** Formatting arguments. */ class format_args { @@ -1470,7 +1471,7 @@ class format_args { format_args() : types_(0) {} template - format_args(const internal::format_arg_store &store) + format_args(const format_arg_store &store) : types_(store.TYPES) { set_data(store.data()); } @@ -2184,7 +2185,7 @@ class BasicFormatter : private internal::FormatterBase { # define FMT_VARIADIC_VOID(func, arg_type) \ template \ void func(arg_type arg0, const Args & ... args) { \ - auto store = fmt::internal::make_format_args< fmt::BasicFormatter >(args...); \ + auto store = fmt::make_format_args< fmt::BasicFormatter >(args...); \ func(arg0, fmt::format_args(store)); \ } @@ -2192,7 +2193,7 @@ class BasicFormatter : private internal::FormatterBase { # define FMT_VARIADIC_CTOR(ctor, func, arg0_type, arg1_type) \ template \ ctor(arg0_type arg0, arg1_type arg1, const Args & ... args) { \ - auto store = internal::make_format_args< fmt::BasicFormatter >(args...); \ + auto store = fmt::make_format_args< fmt::BasicFormatter >(args...); \ func(arg0, arg1, fmt::format_args(store)); \ } @@ -3128,7 +3129,7 @@ template inline void print_colored(Color c, CStringRef format_str, const Args & ... args) { vprint_colored(c, format_str, - internal::make_format_args>(args...)); + make_format_args>(args...)); } inline std::string vformat(CStringRef format_str, format_args args) { @@ -3148,8 +3149,7 @@ inline std::string vformat(CStringRef format_str, format_args args) { */ template inline std::string format(CStringRef format_str, const Args & ... args) { - auto vargs = internal::make_format_args>(args...); - return vformat(format_str, vargs); + return vformat(format_str, make_format_args>(args...)); } inline std::wstring vformat(WCStringRef format_str, format_args args) { @@ -3160,7 +3160,7 @@ inline std::wstring vformat(WCStringRef format_str, format_args args) { template inline std::wstring format(WCStringRef format_str, const Args & ... args) { - auto vargs = internal::make_format_args>(args...); + auto vargs = make_format_args>(args...); return vformat(format_str, vargs); } @@ -3177,8 +3177,7 @@ FMT_API void vprint(std::FILE *f, CStringRef format_str, format_args args); */ template inline void print(std::FILE *f, CStringRef format_str, const Args & ... args) { - vprint(f, format_str, - internal::make_format_args>(args...)); + vprint(f, format_str, make_format_args>(args...)); } FMT_API void vprint(CStringRef format_str, format_args args); @@ -3194,7 +3193,7 @@ FMT_API void vprint(CStringRef format_str, format_args args); */ template inline void print(CStringRef format_str, const Args & ... args) { - vprint(format_str, internal::make_format_args>(args...)); + vprint(format_str, make_format_args>(args...)); } /** diff --git a/fmt/ostream.h b/fmt/ostream.h index 89b4b872..259bc3e1 100644 --- a/fmt/ostream.h +++ b/fmt/ostream.h @@ -100,8 +100,7 @@ FMT_API void vprint(std::ostream &os, CStringRef format_str, format_args args); template inline void print(std::ostream &os, CStringRef format_str, const Args & ... args) { - vprint(os, format_str, - internal::make_format_args>(args...)); + vprint(os, format_str, make_format_args>(args...)); } } // namespace fmt diff --git a/fmt/posix.h b/fmt/posix.h index 78e72050..18d14de2 100644 --- a/fmt/posix.h +++ b/fmt/posix.h @@ -172,8 +172,7 @@ public: template inline void print(CStringRef format_str, const Args & ... args) { - vprint(format_str, - internal::make_format_args>(args...)); + vprint(format_str, make_format_args>(args...)); } }; diff --git a/fmt/printf.h b/fmt/printf.h index 3d5507cd..47f71c9b 100644 --- a/fmt/printf.h +++ b/fmt/printf.h @@ -506,8 +506,7 @@ inline std::string vsprintf(CStringRef format, format_args args) { */ template inline std::string sprintf(CStringRef format_str, const Args & ... args) { - auto vargs = internal::make_format_args>(args...); - return vsprintf(format_str, vargs); + return vsprintf(format_str, make_format_args>(args...)); } inline std::wstring vsprintf(WCStringRef format, format_args args) { @@ -518,7 +517,7 @@ inline std::wstring vsprintf(WCStringRef format, format_args args) { template inline std::wstring sprintf(WCStringRef format_str, const Args & ... args) { - auto vargs = internal::make_format_args>(args...); + auto vargs = make_format_args>(args...); return vsprintf(format_str, vargs); } @@ -535,7 +534,7 @@ FMT_API int vfprintf(std::FILE *f, CStringRef format, format_args args); */ template inline int fprintf(std::FILE *f, CStringRef format_str, const Args & ... args) { - auto vargs = internal::make_format_args>(args...); + auto vargs = make_format_args>(args...); return vfprintf(f, format_str, vargs); } @@ -554,8 +553,7 @@ inline int vprintf(CStringRef format, format_args args) { */ template inline int printf(CStringRef format_str, const Args & ... args) { - auto vargs = internal::make_format_args>(args...); - return vprintf(format_str, vargs); + return vprintf(format_str, make_format_args>(args...)); } inline int vfprintf(std::ostream &os, CStringRef format_str, format_args args) { @@ -577,7 +575,7 @@ inline int vfprintf(std::ostream &os, CStringRef format_str, format_args args) { template inline int fprintf(std::ostream &os, CStringRef format_str, const Args & ... args) { - auto vargs = internal::make_format_args>(args...); + auto vargs = make_format_args>(args...); return vfprintf(os, format_str, vargs); } } // namespace fmt diff --git a/test/custom-formatter-test.cc b/test/custom-formatter-test.cc index 2bcc1d65..32ea166e 100644 --- a/test/custom-formatter-test.cc +++ b/test/custom-formatter-test.cc @@ -45,7 +45,7 @@ class CustomPrintfArgFormatter : } }; -std::string vcustom_format(const char *format_str, fmt::format_args args) { +std::string custom_vformat(const char *format_str, fmt::format_args args) { fmt::MemoryWriter writer; // Pass custom argument formatter as a template arg to BasicFormatter. fmt::BasicFormatter formatter(args, writer); @@ -55,11 +55,11 @@ std::string vcustom_format(const char *format_str, fmt::format_args args) { template std::string custom_format(const char *format_str, const Args & ... args) { - auto va = fmt::internal::make_format_args>(args...); - return vcustom_format(format_str, va); + auto va = fmt::make_format_args>(args...); + return custom_vformat(format_str, va); } -std::string vcustom_sprintf(const char* format_str, fmt::format_args args) { +std::string custom_vsprintf(const char* format_str, fmt::format_args args) { fmt::MemoryWriter writer; fmt::PrintfFormatter formatter(args, writer); formatter.format(format_str); @@ -68,8 +68,8 @@ std::string vcustom_sprintf(const char* format_str, fmt::format_args args) { template std::string custom_sprintf(const char *format_str, const Args & ... args) { - auto va = fmt::internal::make_format_args>(args...); - return vcustom_sprintf(format_str, va); + auto va = fmt::make_format_args>(args...); + return custom_vsprintf(format_str, va); } TEST(CustomFormatterTest, Format) { diff --git a/test/format-test.cc b/test/format-test.cc index fef96b1f..e5dcede5 100644 --- a/test/format-test.cc +++ b/test/format-test.cc @@ -1572,7 +1572,7 @@ std::string vformat_message(int id, const char *format, fmt::format_args args) { template std::string format_message(int id, const char *format, const Args & ... args) { - auto va = fmt::internal::make_format_args>(args...); + auto va = fmt::make_format_args>(args...); return vformat_message(id, format, va); } @@ -1654,7 +1654,7 @@ void vcustom_format(const char *format_str, fmt::format_args args) { template void custom_format(const char *format_str, const Args & ... args) { - auto va = fmt::internal::make_format_args>(args...); + auto va = fmt::make_format_args>(args...); return vcustom_format(format_str, va); } From 0d8aca8de3115187aa65088d0c45aa7644644faf Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sat, 27 Aug 2016 08:16:49 -0700 Subject: [PATCH 012/340] Get rid of FMT_VARIADIC_VOID --- fmt/format.cc | 2 +- fmt/format.h | 22 +++++++++------------- fmt/ostream.cc | 2 +- test/format-test.cc | 2 +- test/macro-test.cc | 11 ----------- 5 files changed, 12 insertions(+), 27 deletions(-) diff --git a/fmt/format.cc b/fmt/format.cc index 5137feb4..719a556f 100644 --- a/fmt/format.cc +++ b/fmt/format.cc @@ -485,7 +485,7 @@ FMT_FUNC void report_windows_error( FMT_FUNC void vprint(std::FILE *f, CStringRef format_str, format_args args) { MemoryWriter w; - w.write(format_str, args); + w.vwrite(format_str, args); std::fwrite(w.data(), 1, w.size(), f); } diff --git a/fmt/format.h b/fmt/format.h index 27155241..774be47b 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -2181,14 +2181,6 @@ class BasicFormatter : private internal::FormatterBase { # define FMT_ASSIGN_wchar_t(n) \ arr[n] = fmt::internal::MakeValue< fmt::BasicFormatter >(v##n) -// Defines a variadic function returning void. -# define FMT_VARIADIC_VOID(func, arg_type) \ - template \ - void func(arg_type arg0, const Args & ... args) { \ - auto store = fmt::make_format_args< fmt::BasicFormatter >(args...); \ - func(arg0, fmt::format_args(store)); \ - } - // Defines a variadic constructor. # define FMT_VARIADIC_CTOR(ctor, func, arg0_type, arg1_type) \ template \ @@ -2449,6 +2441,10 @@ class BasicWriter { return std::basic_string(&buffer_[0], buffer_.size()); } + void vwrite(BasicCStringRef format, format_args args) { + BasicFormatter(args, *this).format(format); + } + /** \rst Writes formatted data. @@ -2474,10 +2470,10 @@ class BasicWriter { See also :ref:`syntax`. \endrst */ - void write(BasicCStringRef format, format_args args) { - BasicFormatter(args, *this).format(format); + template + void write(BasicCStringRef format, const Args & ... args) { + vwrite(format, make_format_args>(args...)); } - FMT_VARIADIC_VOID(write, BasicCStringRef) BasicWriter &operator<<(int value) { write_decimal(value); @@ -3134,7 +3130,7 @@ inline void print_colored(Color c, CStringRef format_str, inline std::string vformat(CStringRef format_str, format_args args) { MemoryWriter w; - w.write(format_str, args); + w.vwrite(format_str, args); return w.str(); } @@ -3154,7 +3150,7 @@ inline std::string format(CStringRef format_str, const Args & ... args) { inline std::wstring vformat(WCStringRef format_str, format_args args) { WMemoryWriter w; - w.write(format_str, args); + w.vwrite(format_str, args); return w.str(); } diff --git a/fmt/ostream.cc b/fmt/ostream.cc index 9719d248..8b83b2d1 100644 --- a/fmt/ostream.cc +++ b/fmt/ostream.cc @@ -30,7 +30,7 @@ FMT_FUNC void write(std::ostream &os, Writer &w) { FMT_FUNC void vprint(std::ostream &os, CStringRef format_str, format_args args) { MemoryWriter w; - w.write(format_str, args); + w.vwrite(format_str, args); internal::write(os, w); } } // namespace fmt diff --git a/test/format-test.cc b/test/format-test.cc index e5dcede5..ae01dfe2 100644 --- a/test/format-test.cc +++ b/test/format-test.cc @@ -1566,7 +1566,7 @@ TEST(StrTest, Convert) { std::string vformat_message(int id, const char *format, fmt::format_args args) { MemoryWriter w; w.write("[{}] ", id); - w.write(format, args); + w.vwrite(format, args); return w.str(); } diff --git a/test/macro-test.cc b/test/macro-test.cc index b39fc495..7882e8c5 100644 --- a/test/macro-test.cc +++ b/test/macro-test.cc @@ -74,14 +74,3 @@ int result; } MAKE_TEST(test_func) - -typedef char Char; - -MAKE_TEST(test_variadic_void) -FMT_VARIADIC_VOID(test_variadic_void, const char *) - -TEST(UtilTest, VariadicVoid) { - result = 0; - test_variadic_void("", 10, 20, 30, 40, 50, 60, 70, 80, 90, 100); - EXPECT_EQ(550, result); -} From ea28a6370641ccbf12813cae9e2163c7549de8a0 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sat, 27 Aug 2016 08:23:44 -0700 Subject: [PATCH 013/340] Get rid of FMT_VARIADIC_CTOR --- fmt/format.h | 22 ++++++---------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/fmt/format.h b/fmt/format.h index 774be47b..0e674d4a 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -2181,14 +2181,6 @@ class BasicFormatter : private internal::FormatterBase { # define FMT_ASSIGN_wchar_t(n) \ arr[n] = fmt::internal::MakeValue< fmt::BasicFormatter >(v##n) -// Defines a variadic constructor. -# define FMT_VARIADIC_CTOR(ctor, func, arg0_type, arg1_type) \ - template \ - ctor(arg0_type arg0, arg1_type arg1, const Args & ... args) { \ - auto store = fmt::make_format_args< fmt::BasicFormatter >(args...); \ - func(arg0, arg1, fmt::format_args(store)); \ - } - // Generates a comma-separated list with results of applying f to pairs // (argument, index). #define FMT_FOR_EACH1(f, x0) f(x0, 0) @@ -2222,8 +2214,6 @@ class SystemError : public internal::RuntimeError { protected: int error_code_; - typedef char Char; // For FMT_VARIADIC_CTOR. - SystemError() {} public: @@ -2245,10 +2235,10 @@ class SystemError : public internal::RuntimeError { throw fmt::SystemError(errno, "cannot open file '{}'", filename); \endrst */ - SystemError(int error_code, CStringRef message) { - init(error_code, message, format_args()); + template + SystemError(int error_code, CStringRef message, const Args & ... args) { + init(error_code, message, make_format_args>(args...)); } - FMT_VARIADIC_CTOR(SystemError, init, int, CStringRef) ~SystemError() throw(); @@ -3098,10 +3088,10 @@ class WindowsError : public SystemError { } \endrst */ - WindowsError(int error_code, CStringRef message) { - init(error_code, message, format_args()); + template + WindowsError(int error_code, CStringRef message, const Args & ... args) { + init(error_code, message, make_format_args>(args...)); } - FMT_VARIADIC_CTOR(WindowsError, init, int, CStringRef) }; // Reports a Windows error without throwing an exception. From 9a07973261d18ec45ce27407bc7aa2a74b666026 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sat, 27 Aug 2016 08:55:01 -0700 Subject: [PATCH 014/340] Test types --- fmt/format.h | 295 +++++++++++++++++++++++++++------------------------ 1 file changed, 155 insertions(+), 140 deletions(-) diff --git a/fmt/format.h b/fmt/format.h index 0e674d4a..64dabf16 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -1161,146 +1161,6 @@ void format_arg(Formatter &, const Char *, const T &) { "an overload of format_arg."); } -// Makes an Arg object from any type. -template -class MakeValue : public Arg { - public: - typedef typename Formatter::Char Char; - - private: - // The following two methods are private to disallow formatting of - // arbitrary pointers. If you want to output a pointer cast it to - // "void *" or "const void *". In particular, this forbids formatting - // of "[const] volatile char *" which is printed as bool by iostreams. - // Do not implement! - template - MakeValue(const T *value); - template - MakeValue(T *value); - - // The following methods are private to disallow formatting of wide - // characters and strings into narrow strings as in - // fmt::format("{}", L"test"); - // To fix this, use a wide format string: fmt::format(L"{}", L"test"). -#if !FMT_MSC_VER || defined(_NATIVE_WCHAR_T_DEFINED) - MakeValue(typename WCharHelper::Unsupported); -#endif - MakeValue(typename WCharHelper::Unsupported); - MakeValue(typename WCharHelper::Unsupported); - MakeValue(typename WCharHelper::Unsupported); - MakeValue(typename WCharHelper::Unsupported); - - void set_string(StringRef str) { - string.value = str.data(); - string.size = str.size(); - } - - void set_string(WStringRef str) { - wstring.value = str.data(); - wstring.size = str.size(); - } - - // Formats an argument of a custom type, such as a user-defined class. - template - static void format_custom_arg( - void *formatter, const void *arg, void *format_str_ptr) { - format_arg(*static_cast(formatter), - *static_cast(format_str_ptr), - *static_cast(arg)); - } - - public: - MakeValue() {} - -#define FMT_MAKE_VALUE_(Type, field, TYPE, rhs) \ - MakeValue(Type value) { field = rhs; } - -#define FMT_MAKE_VALUE(Type, field, TYPE) \ - FMT_MAKE_VALUE_(Type, field, TYPE, value) - - FMT_MAKE_VALUE(bool, int_value, BOOL) - FMT_MAKE_VALUE(short, int_value, INT) - FMT_MAKE_VALUE(unsigned short, uint_value, UINT) - FMT_MAKE_VALUE(int, int_value, INT) - FMT_MAKE_VALUE(unsigned, uint_value, UINT) - - MakeValue(long value) { - // To minimize the number of types we need to deal with, long is - // translated either to int or to long long depending on its size. - if (const_check(sizeof(long) == sizeof(int))) - int_value = static_cast(value); - else - long_long_value = value; - } - - MakeValue(unsigned long value) { - if (const_check(sizeof(unsigned long) == sizeof(unsigned))) - uint_value = static_cast(value); - else - ulong_long_value = value; - } - - FMT_MAKE_VALUE(LongLong, long_long_value, LONG_LONG) - FMT_MAKE_VALUE(ULongLong, ulong_long_value, ULONG_LONG) - FMT_MAKE_VALUE(float, double_value, DOUBLE) - FMT_MAKE_VALUE(double, double_value, DOUBLE) - FMT_MAKE_VALUE(long double, long_double_value, LONG_DOUBLE) - FMT_MAKE_VALUE(signed char, int_value, INT) - FMT_MAKE_VALUE(unsigned char, uint_value, UINT) - FMT_MAKE_VALUE(char, int_value, CHAR) - -#if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED) - MakeValue(typename WCharHelper::Supported value) { - int_value = value; - } -#endif - -#define FMT_MAKE_STR_VALUE(Type, TYPE) \ - MakeValue(Type value) { set_string(value); } - - FMT_MAKE_VALUE(char *, string.value, CSTRING) - FMT_MAKE_VALUE(const char *, string.value, CSTRING) - FMT_MAKE_VALUE(signed char *, sstring.value, CSTRING) - FMT_MAKE_VALUE(const signed char *, sstring.value, CSTRING) - FMT_MAKE_VALUE(unsigned char *, ustring.value, CSTRING) - FMT_MAKE_VALUE(const unsigned char *, ustring.value, CSTRING) - FMT_MAKE_STR_VALUE(const std::string &, STRING) - FMT_MAKE_STR_VALUE(StringRef, STRING) - FMT_MAKE_VALUE_(CStringRef, string.value, CSTRING, value.c_str()) - -#define FMT_MAKE_WSTR_VALUE(Type, TYPE) \ - MakeValue(typename WCharHelper::Supported value) { \ - set_string(value); \ - } - - FMT_MAKE_WSTR_VALUE(wchar_t *, WSTRING) - FMT_MAKE_WSTR_VALUE(const wchar_t *, WSTRING) - FMT_MAKE_WSTR_VALUE(const std::wstring &, WSTRING) - FMT_MAKE_WSTR_VALUE(WStringRef, WSTRING) - - FMT_MAKE_VALUE(void *, pointer, POINTER) - FMT_MAKE_VALUE(const void *, pointer, POINTER) - - template - MakeValue(const T &value, - typename EnableIf::value>::value, int>::type = 0) { - custom.value = &value; - custom.format = &format_custom_arg; - } - - template - MakeValue(const T &value, - typename EnableIf::value, int>::type = 0) { - int_value = value; - } - - // Additional template param `Char_` is needed here because make_type always - // uses char. - template - MakeValue(const NamedArg &value) { pointer = &value; } -}; - template struct IsNamedArg : std::false_type {}; @@ -1363,6 +1223,161 @@ template <> constexpr Type gettype() { return Arg::POINTER; } template constexpr Type type() { return gettype::type>(); } +// Makes an Arg object from any type. +template +class MakeValue : public Arg { + public: + typedef typename Formatter::Char Char; + + private: + // The following two methods are private to disallow formatting of + // arbitrary pointers. If you want to output a pointer cast it to + // "void *" or "const void *". In particular, this forbids formatting + // of "[const] volatile char *" which is printed as bool by iostreams. + // Do not implement! + template + MakeValue(const T *value); + template + MakeValue(T *value); + + // The following methods are private to disallow formatting of wide + // characters and strings into narrow strings as in + // fmt::format("{}", L"test"); + // To fix this, use a wide format string: fmt::format(L"{}", L"test"). +#if !FMT_MSC_VER || defined(_NATIVE_WCHAR_T_DEFINED) + MakeValue(typename WCharHelper::Unsupported); +#endif + MakeValue(typename WCharHelper::Unsupported); + MakeValue(typename WCharHelper::Unsupported); + MakeValue(typename WCharHelper::Unsupported); + MakeValue(typename WCharHelper::Unsupported); + + void set_string(StringRef str) { + string.value = str.data(); + string.size = str.size(); + } + + void set_string(WStringRef str) { + wstring.value = str.data(); + wstring.size = str.size(); + } + + // Formats an argument of a custom type, such as a user-defined class. + template + static void format_custom_arg( + void *formatter, const void *arg, void *format_str_ptr) { + format_arg(*static_cast(formatter), + *static_cast(format_str_ptr), + *static_cast(arg)); + } + + public: + MakeValue() {} + +#define FMT_MAKE_VALUE_(Type, field, TYPE, rhs) \ + MakeValue(Type value) { \ + static_assert(internal::type() == TYPE, "invalid type"); \ + field = rhs; \ + } + +#define FMT_MAKE_VALUE(Type, field, TYPE) \ + FMT_MAKE_VALUE_(Type, field, TYPE, value) + + FMT_MAKE_VALUE(bool, int_value, BOOL) + FMT_MAKE_VALUE(short, int_value, INT) + FMT_MAKE_VALUE(unsigned short, uint_value, UINT) + FMT_MAKE_VALUE(int, int_value, INT) + FMT_MAKE_VALUE(unsigned, uint_value, UINT) + + MakeValue(long value) { + // To minimize the number of types we need to deal with, long is + // translated either to int or to long long depending on its size. + if (const_check(sizeof(long) == sizeof(int))) + int_value = static_cast(value); + else + long_long_value = value; + } + + MakeValue(unsigned long value) { + if (const_check(sizeof(unsigned long) == sizeof(unsigned))) + uint_value = static_cast(value); + else + ulong_long_value = value; + } + + FMT_MAKE_VALUE(LongLong, long_long_value, LONG_LONG) + FMT_MAKE_VALUE(ULongLong, ulong_long_value, ULONG_LONG) + FMT_MAKE_VALUE(float, double_value, DOUBLE) + FMT_MAKE_VALUE(double, double_value, DOUBLE) + FMT_MAKE_VALUE(long double, long_double_value, LONG_DOUBLE) + FMT_MAKE_VALUE(signed char, int_value, INT) + FMT_MAKE_VALUE(unsigned char, uint_value, UINT) + FMT_MAKE_VALUE(char, int_value, CHAR) + +#if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED) + typedef typename WCharHelper::Supported WChar; + MakeValue(WChar value) { + static_assert(internal::type() == CHAR, "invalid type"); + int_value = value; + } +#endif + +#define FMT_MAKE_STR_VALUE(Type, TYPE) \ + MakeValue(Type value) { \ + static_assert(internal::type() == TYPE, "invalid type"); \ + set_string(value); \ + } + + FMT_MAKE_VALUE(char *, string.value, CSTRING) + FMT_MAKE_VALUE(const char *, string.value, CSTRING) + FMT_MAKE_VALUE(signed char *, sstring.value, CSTRING) + FMT_MAKE_VALUE(const signed char *, sstring.value, CSTRING) + FMT_MAKE_VALUE(unsigned char *, ustring.value, CSTRING) + FMT_MAKE_VALUE(const unsigned char *, ustring.value, CSTRING) + FMT_MAKE_STR_VALUE(const std::string &, STRING) + FMT_MAKE_STR_VALUE(StringRef, STRING) + FMT_MAKE_VALUE_(CStringRef, string.value, CSTRING, value.c_str()) + +#define FMT_MAKE_WSTR_VALUE(Type, TYPE) \ + MakeValue(typename WCharHelper::Supported value) { \ + static_assert(internal::type() == TYPE, "invalid type"); \ + set_string(value); \ + } + + FMT_MAKE_WSTR_VALUE(wchar_t *, WSTRING) + FMT_MAKE_WSTR_VALUE(const wchar_t *, WSTRING) + FMT_MAKE_WSTR_VALUE(const std::wstring &, WSTRING) + FMT_MAKE_WSTR_VALUE(WStringRef, WSTRING) + + FMT_MAKE_VALUE(void *, pointer, POINTER) + FMT_MAKE_VALUE(const void *, pointer, POINTER) + + template + MakeValue(const T &value, + typename EnableIf::value>::value, int>::type = 0) { + static_assert(internal::type() == CUSTOM, "invalid type"); + custom.value = &value; + custom.format = &format_custom_arg; + } + + template + MakeValue(const T &value, + typename EnableIf::value, int>::type = 0) { + static_assert(internal::type() == INT, "invalid type"); + int_value = value; + } + + // Additional template param `Char_` is needed here because make_type always + // uses char. + template + MakeValue(const NamedArg &value) { + static_assert(internal::type &>() == NAMED_ARG, + "invalid type"); + pointer = &value; + } +}; + template class MakeArg : public Arg { public: From 209a1d58bfae08874961c3d46b9573fc2226018c Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sat, 27 Aug 2016 09:06:21 -0700 Subject: [PATCH 015/340] Get rid of macros --- fmt/format.h | 97 --------------------------------------------- test/CMakeLists.txt | 1 - test/format-test.cc | 13 ------ test/macro-test.cc | 76 ----------------------------------- 4 files changed, 187 deletions(-) delete mode 100644 test/macro-test.cc diff --git a/fmt/format.h b/fmt/format.h index 64dabf16..b32cb53d 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -2169,55 +2169,6 @@ class BasicFormatter : private internal::FormatterBase { const Char *format(const Char *&format_str, const internal::Arg &arg); }; -// Generates a comma-separated list with results of applying f to -// numbers 0..n-1. -# define FMT_GEN(n, f) FMT_GEN##n(f) -# define FMT_GEN1(f) f(0) -# define FMT_GEN2(f) FMT_GEN1(f), f(1) -# define FMT_GEN3(f) FMT_GEN2(f), f(2) -# define FMT_GEN4(f) FMT_GEN3(f), f(3) -# define FMT_GEN5(f) FMT_GEN4(f), f(4) -# define FMT_GEN6(f) FMT_GEN5(f), f(5) -# define FMT_GEN7(f) FMT_GEN6(f), f(6) -# define FMT_GEN8(f) FMT_GEN7(f), f(7) -# define FMT_GEN9(f) FMT_GEN8(f), f(8) -# define FMT_GEN10(f) FMT_GEN9(f), f(9) -# define FMT_GEN11(f) FMT_GEN10(f), f(10) -# define FMT_GEN12(f) FMT_GEN11(f), f(11) -# define FMT_GEN13(f) FMT_GEN12(f), f(12) -# define FMT_GEN14(f) FMT_GEN13(f), f(13) -# define FMT_GEN15(f) FMT_GEN14(f), f(14) - -# define FMT_MAKE_TEMPLATE_ARG(n) typename T##n -# define FMT_MAKE_ARG_TYPE(n) T##n -# define FMT_MAKE_ARG(n) const T##n &v##n -# define FMT_ASSIGN_char(n) \ - arr[n] = fmt::internal::MakeValue< fmt::BasicFormatter >(v##n) -# define FMT_ASSIGN_wchar_t(n) \ - arr[n] = fmt::internal::MakeValue< fmt::BasicFormatter >(v##n) - -// Generates a comma-separated list with results of applying f to pairs -// (argument, index). -#define FMT_FOR_EACH1(f, x0) f(x0, 0) -#define FMT_FOR_EACH2(f, x0, x1) \ - FMT_FOR_EACH1(f, x0), f(x1, 1) -#define FMT_FOR_EACH3(f, x0, x1, x2) \ - FMT_FOR_EACH2(f, x0 ,x1), f(x2, 2) -#define FMT_FOR_EACH4(f, x0, x1, x2, x3) \ - FMT_FOR_EACH3(f, x0, x1, x2), f(x3, 3) -#define FMT_FOR_EACH5(f, x0, x1, x2, x3, x4) \ - FMT_FOR_EACH4(f, x0, x1, x2, x3), f(x4, 4) -#define FMT_FOR_EACH6(f, x0, x1, x2, x3, x4, x5) \ - FMT_FOR_EACH5(f, x0, x1, x2, x3, x4), f(x5, 5) -#define FMT_FOR_EACH7(f, x0, x1, x2, x3, x4, x5, x6) \ - FMT_FOR_EACH6(f, x0, x1, x2, x3, x4, x5), f(x6, 6) -#define FMT_FOR_EACH8(f, x0, x1, x2, x3, x4, x5, x6, x7) \ - FMT_FOR_EACH7(f, x0, x1, x2, x3, x4, x5, x6), f(x7, 7) -#define FMT_FOR_EACH9(f, x0, x1, x2, x3, x4, x5, x6, x7, x8) \ - FMT_FOR_EACH8(f, x0, x1, x2, x3, x4, x5, x6, x7), f(x8, 8) -#define FMT_FOR_EACH10(f, x0, x1, x2, x3, x4, x5, x6, x7, x8, x9) \ - FMT_FOR_EACH9(f, x0, x1, x2, x3, x4, x5, x6, x7, x8), f(x9, 9) - /** An error returned by an operating system or a language runtime, for example a file opening error. @@ -3338,54 +3289,6 @@ void arg(WStringRef, const internal::NamedArg&) FMT_DELETED_OR_UNDEFINED; # pragma GCC system_header #endif -// This is used to work around VC++ bugs in handling variadic macros. -#define FMT_EXPAND(args) args - -// Returns the number of arguments. -// Based on https://groups.google.com/forum/#!topic/comp.std.c/d-6Mj5Lko_s. -#define FMT_NARG(...) FMT_NARG_(__VA_ARGS__, FMT_RSEQ_N()) -#define FMT_NARG_(...) FMT_EXPAND(FMT_ARG_N(__VA_ARGS__)) -#define FMT_ARG_N(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, N, ...) N -#define FMT_RSEQ_N() 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 - -#define FMT_FOR_EACH_(N, f, ...) \ - FMT_EXPAND(FMT_CONCAT(FMT_FOR_EACH, N)(f, __VA_ARGS__)) -#define FMT_FOR_EACH(f, ...) \ - FMT_EXPAND(FMT_FOR_EACH_(FMT_NARG(__VA_ARGS__), f, __VA_ARGS__)) - -#define FMT_ADD_ARG_NAME(type, index) type arg##index -#define FMT_GET_ARG_NAME(type, index) arg##index - -#define FMT_VARIADIC_(Char, ReturnType, func, call, ...) \ - template \ - ReturnType func(FMT_FOR_EACH(FMT_ADD_ARG_NAME, __VA_ARGS__), \ - const Args & ... args) { \ - auto store = fmt::internal::make_format_args< fmt::BasicFormatter >(args...); \ - call(FMT_FOR_EACH(FMT_GET_ARG_NAME, __VA_ARGS__), fmt::format_args(store)); \ - } - -#define FMT_CAPTURE_ARG_(id, index) ::fmt::arg(#id, id) - -#define FMT_CAPTURE_ARG_W_(id, index) ::fmt::arg(L###id, id) - -/** - \rst - Convenient macro to capture the arguments' names and values into several - ``fmt::arg(name, value)``. - - **Example**:: - - int x = 1, y = 2; - print("point: ({x}, {y})", FMT_CAPTURE(x, y)); - // same as: - // print("point: ({x}, {y})", arg("x", x), arg("y", y)); - - \endrst - */ -#define FMT_CAPTURE(...) FMT_FOR_EACH(FMT_CAPTURE_ARG_, __VA_ARGS__) - -#define FMT_CAPTURE_W(...) FMT_FOR_EACH(FMT_CAPTURE_ARG_W_, __VA_ARGS__) - namespace fmt { namespace internal { template diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 95ddca55..f657337c 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -88,7 +88,6 @@ add_fmt_test(printf-test) add_fmt_test(string-test) add_fmt_test(time-test) add_fmt_test(util-test mock-allocator.h) -add_fmt_test(macro-test) add_fmt_test(custom-formatter-test) # Enable stricter options for one test to make sure that the header is free of diff --git a/test/format-test.cc b/test/format-test.cc index ae01dfe2..8a8df1a5 100644 --- a/test/format-test.cc +++ b/test/format-test.cc @@ -606,22 +606,9 @@ TEST(FormatterTest, ManyArgs) { TEST(FormatterTest, NamedArg) { EXPECT_EQ("1/a/A", format("{_1}/{a_}/{A_}", fmt::arg("a_", 'a'), fmt::arg("A_", "A"), fmt::arg("_1", 1))); - char a = 'A', b = 'B', c = 'C'; - EXPECT_EQ("BB/AA/CC", format("{1}{b}/{0}{a}/{2}{c}", FMT_CAPTURE(a, b, c))); - EXPECT_EQ(" A", format("{a:>2}", FMT_CAPTURE(a))); - EXPECT_THROW_MSG(format("{a+}", FMT_CAPTURE(a)), format_error, - "missing '}' in format string"); EXPECT_THROW_MSG(format("{a}"), format_error, "argument not found"); - EXPECT_THROW_MSG(format("{d}", FMT_CAPTURE(a, b, c)), format_error, - "argument not found"); - EXPECT_THROW_MSG(format("{a}{}", FMT_CAPTURE(a)), - format_error, "cannot switch from manual to automatic argument indexing"); - EXPECT_THROW_MSG(format("{}{a}", FMT_CAPTURE(a)), - format_error, "cannot switch from automatic to manual argument indexing"); EXPECT_EQ(" -42", format("{0:{width}}", -42, fmt::arg("width", 4))); EXPECT_EQ("st", format("{0:.{precision}}", "str", fmt::arg("precision", 2))); - int n = 100; - EXPECT_EQ(L"n=100", format(L"n={n}", FMT_CAPTURE_W(n))); } TEST(FormatterTest, AutoArgIndex) { diff --git a/test/macro-test.cc b/test/macro-test.cc deleted file mode 100644 index 7882e8c5..00000000 --- a/test/macro-test.cc +++ /dev/null @@ -1,76 +0,0 @@ -/* - Tests of variadic function emulation macros. - - Copyright (c) 2012-2014, Victor Zverovich - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include -#include - -#define FMT_USE_VARIADIC_TEMPLATES 0 -#include "fmt/format.h" - -#define IDENTITY(x) x - -TEST(UtilTest, Gen) { - int values[] = {FMT_GEN(10, IDENTITY)}; - for (int i = 0; i < 10; ++i) - EXPECT_EQ(i, values[i]); -} - -#define MAKE_PAIR(x, y) std::make_pair(x, y) - -TEST(UtilTest, ForEach) { - std::pair values[] = { - FMT_FOR_EACH10(MAKE_PAIR, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j') - }; - for (int i = 0; i < 10; ++i) { - EXPECT_EQ('a' + i, values[i].first); - EXPECT_EQ(i, values[i].second); - } -} - -TEST(UtilTest, NArg) { - EXPECT_EQ(1, FMT_NARG(a)); - EXPECT_EQ(2, FMT_NARG(a, b)); - EXPECT_EQ(3, FMT_NARG(a, b, c)); - EXPECT_EQ(4, FMT_NARG(a, b, c, d)); - EXPECT_EQ(5, FMT_NARG(a, b, c, d, e)); - EXPECT_EQ(6, FMT_NARG(a, b, c, d, e, f)); - EXPECT_EQ(7, FMT_NARG(a, b, c, d, e, f, g)); - EXPECT_EQ(8, FMT_NARG(a, b, c, d, e, f, g, h)); - EXPECT_EQ(9, FMT_NARG(a, b, c, d, e, f, g, h, i)); - EXPECT_EQ(10, FMT_NARG(a, b, c, d, e, f, g, h, i, j)); -} - -int result; - -#define MAKE_TEST(func) \ - void func(const char *, const fmt::format_args &args) { \ - result = 0; \ - for (unsigned i = 0; args[i].type; ++i) \ - result += args[i].int_value; \ - } - -MAKE_TEST(test_func) From 21c6700b83b1a7af61b5965ad4ff4e87b861507f Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Mon, 26 Sep 2016 07:35:27 -0700 Subject: [PATCH 016/340] Don't build std branch with -std=c++0=98 --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index d6b81a2a..3264544f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,7 +14,6 @@ env: matrix: - BUILD=Doc - BUILD=Debug STANDARD=0x - - BUILD=Release STANDARD=98 - BUILD=Release STANDARD=0x matrix: From c4212f9ec2ce8aee42541243d1861c04b54518ba Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Wed, 28 Sep 2016 07:09:26 -0700 Subject: [PATCH 017/340] format -> vformat --- fmt/format.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fmt/format.cc b/fmt/format.cc index 719a556f..6abda6d5 100644 --- a/fmt/format.cc +++ b/fmt/format.cc @@ -350,7 +350,7 @@ FMT_FUNC void WindowsError::init( int err_code, CStringRef format_str, format_args args) { error_code_ = err_code; MemoryWriter w; - internal::format_windows_error(w, err_code, format(format_str, args)); + internal::format_windows_error(w, err_code, vformat(format_str, args)); std::runtime_error &base = *this; base = std::runtime_error(w.str()); } From 6fd6ecc10d593ec8d4be0fbdadba22de17498c95 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Wed, 28 Sep 2016 07:45:28 -0700 Subject: [PATCH 018/340] Enable C++11 for no-windows-h-test --- test/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index f657337c..3caeb5b0 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -129,6 +129,7 @@ if (FMT_PEDANTIC) # Test that the library compiles without windows.h. if (CMAKE_SYSTEM_NAME STREQUAL "Windows") add_library(no-windows-h-test ../fmt/format.cc) + target_compile_options(no-windows-h-test PUBLIC ${CPP11_FLAG}) target_include_directories(no-windows-h-test PRIVATE ${PROJECT_SOURCE_DIR}) target_compile_definitions(no-windows-h-test PRIVATE FMT_USE_WINDOWS_H=0) endif () From 06bab3edb07b889d4054b262b7fe86e0ba3fb624 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Fri, 30 Sep 2016 07:20:57 -0700 Subject: [PATCH 019/340] Workaround mingw bug https://sourceforge.net/p/mingw/bugs/1531/ --- fmt/format.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/fmt/format.h b/fmt/format.h index b32cb53d..0ac3ce33 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -1426,13 +1426,13 @@ template class format_arg_store { private: static const size_t NUM_ARGS = sizeof...(Args); - static const bool PACKED = NUM_ARGS <= internal::MAX_PACKED_ARGS; + static const bool IS_PACKED = NUM_ARGS <= internal::MAX_PACKED_ARGS; typedef typename std::conditional< - PACKED, internal::Value, internal::Arg>::type value_type; + IS_PACKED, internal::Value, internal::Arg>::type value_type; // If the arguments are not packed, add one more element to mark the end. - std::array data_; + std::array data_; template friend format_arg_store make_format_args(const A & ... args); From 1e8553d6795c63ced9702b77dad6086b6ddcb510 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sat, 1 Oct 2016 07:02:58 -0700 Subject: [PATCH 020/340] Enable C++11 in tests. --- test/CMakeLists.txt | 1 + test/find-package-test/CMakeLists.txt | 2 ++ 2 files changed, 3 insertions(+) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 3caeb5b0..3aa63cf6 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -155,6 +155,7 @@ if (FMT_PEDANTIC) --build-makeprogram ${CMAKE_MAKE_PROGRAM} --build-options "-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}" + "-DCPP11_FLAG=${CPP11_FLAG}" "-DFMT_DIR=${PROJECT_BINARY_DIR}" "-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}") diff --git a/test/find-package-test/CMakeLists.txt b/test/find-package-test/CMakeLists.txt index 1f28c30c..54180419 100644 --- a/test/find-package-test/CMakeLists.txt +++ b/test/find-package-test/CMakeLists.txt @@ -5,9 +5,11 @@ project(fmt-test) find_package(FMT REQUIRED) add_executable(library-test main.cc) +target_compile_options(library-test PUBLIC ${CPP11_FLAG}) target_link_libraries(library-test fmt) if (TARGET fmt-header-only) add_executable(header-only-test main.cc) + target_compile_options(header-only-test PUBLIC ${CPP11_FLAG}) target_link_libraries(header-only-test fmt-header-only) endif () From 8a77e7927e320cbfbc6efee4c50872bda05c436a Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sat, 1 Oct 2016 07:18:55 -0700 Subject: [PATCH 021/340] Enable C++11 in tests. --- test/CMakeLists.txt | 1 + test/add-subdirectory-test/CMakeLists.txt | 2 ++ 2 files changed, 3 insertions(+) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 3aa63cf6..459a77dd 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -169,5 +169,6 @@ if (FMT_PEDANTIC) --build-makeprogram ${CMAKE_MAKE_PROGRAM} --build-options "-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}" + "-DCPP11_FLAG=${CPP11_FLAG}" "-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}") endif () diff --git a/test/add-subdirectory-test/CMakeLists.txt b/test/add-subdirectory-test/CMakeLists.txt index 5460363a..e99bc673 100644 --- a/test/add-subdirectory-test/CMakeLists.txt +++ b/test/add-subdirectory-test/CMakeLists.txt @@ -5,9 +5,11 @@ project(fmt-test) add_subdirectory(../.. fmt) add_executable(library-test "main.cc") +target_compile_options(library-test PUBLIC ${CPP11_FLAG}) target_link_libraries(library-test fmt) if (TARGET fmt-header-only) add_executable(header-only-test "main.cc") + target_compile_options(header-only-test PUBLIC ${CPP11_FLAG}) target_link_libraries(header-only-test fmt-header-only) endif () From 13b04044e57e86ccc0058068ef514ae22b1a3728 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sun, 2 Oct 2016 08:26:32 -0700 Subject: [PATCH 022/340] Add format_args::size_type --- fmt/format.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/fmt/format.h b/fmt/format.h index 0ac3ce33..b0b1bc81 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -1483,6 +1483,8 @@ class format_args { void set_data(const internal::Arg *args) { args_ = args; } public: + typedef unsigned size_type; + format_args() : types_(0) {} template @@ -1492,7 +1494,7 @@ class format_args { } /** Returns the argument at specified index. */ - internal::Arg operator[](unsigned index) const { + internal::Arg operator[](size_type index) const { using internal::Arg; Arg arg; bool use_values = type(internal::MAX_PACKED_ARGS - 1) == Arg::NONE; From 65a8c2c34336e5c24a3fe0789efb1d11d80764ee Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sun, 2 Oct 2016 08:49:10 -0700 Subject: [PATCH 023/340] format_arg -> format_value --- fmt/format.h | 8 ++++---- fmt/ostream.h | 2 +- fmt/time.h | 2 +- test/format-test.cc | 4 ++-- test/util-test.cc | 4 ++-- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/fmt/format.h b/fmt/format.h index b0b1bc81..533678ea 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -1154,7 +1154,7 @@ inline fmt::StringRef thousands_sep(...) { return ""; } #endif template -void format_arg(Formatter &, const Char *, const T &) { +void format_value(Formatter &, const Char *, const T &) { FMT_STATIC_ASSERT(False::value, "Cannot format argument. To enable the use of ostream " "operator<< include fmt/ostream.h. Otherwise provide " @@ -1266,9 +1266,9 @@ class MakeValue : public Arg { template static void format_custom_arg( void *formatter, const void *arg, void *format_str_ptr) { - format_arg(*static_cast(formatter), - *static_cast(format_str_ptr), - *static_cast(arg)); + format_value(*static_cast(formatter), + *static_cast(format_str_ptr), + *static_cast(arg)); } public: diff --git a/fmt/ostream.h b/fmt/ostream.h index 259bc3e1..87b80471 100644 --- a/fmt/ostream.h +++ b/fmt/ostream.h @@ -73,7 +73,7 @@ void write(std::ostream &os, Writer &w); // Formats a value. template -void format_arg(BasicFormatter &f, +void format_value(BasicFormatter &f, const Char *&format_str, const T &value) { internal::MemoryBuffer buffer; diff --git a/fmt/time.h b/fmt/time.h index 83f742c4..675ff0da 100644 --- a/fmt/time.h +++ b/fmt/time.h @@ -15,7 +15,7 @@ namespace fmt { template -void format_arg(BasicFormatter &f, +void format_value(BasicFormatter &f, const char *&format_str, const std::tm &tm) { if (*format_str == ':') ++format_str; diff --git a/test/format-test.cc b/test/format-test.cc index 8a8df1a5..022b1aa7 100644 --- a/test/format-test.cc +++ b/test/format-test.cc @@ -1355,7 +1355,7 @@ TEST(FormatterTest, FormatCStringRef) { EXPECT_EQ("test", format("{0}", CStringRef("test"))); } -void format_arg(fmt::BasicFormatter &f, const char *, const Date &d) { +void format_value(fmt::BasicFormatter &f, const char *, const Date &d) { f.writer() << d.year() << '-' << d.month() << '-' << d.day(); } @@ -1368,7 +1368,7 @@ TEST(FormatterTest, FormatCustom) { class Answer {}; template -void format_arg(fmt::BasicFormatter &f, const Char *, Answer) { +void format_value(fmt::BasicFormatter &f, const Char *, Answer) { f.writer() << "42"; } diff --git a/test/util-test.cc b/test/util-test.cc index 6c1a2c0d..5d5ddf32 100644 --- a/test/util-test.cc +++ b/test/util-test.cc @@ -64,7 +64,7 @@ namespace { struct Test {}; template -void format_arg(fmt::BasicFormatter &f, const Char *, Test) { +void format_value(fmt::BasicFormatter &f, const Char *, Test) { f.writer() << "test"; } @@ -581,7 +581,7 @@ struct CustomFormatter { typedef char Char; }; -void format_arg(CustomFormatter &, const char *&s, const Test &) { +void format_value(CustomFormatter &, const char *&s, const Test &) { s = "custom_format"; } From 119a63ab72f12a3d5ecaf45941fdca1a97f1cd08 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sun, 2 Oct 2016 09:29:11 -0700 Subject: [PATCH 024/340] internal::Arg -> format_arg --- fmt/format.h | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/fmt/format.h b/fmt/format.h index 533678ea..d5249326 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -1025,13 +1025,18 @@ struct Value { CSTRING, STRING, WSTRING, POINTER, CUSTOM }; }; +} // namespace internal // A formatting argument. It is a trivially copyable/constructible type to // allow storage in internal::MemoryBuffer. -struct Arg : Value { +struct format_arg : internal::Value { Type type; }; +namespace internal { + +typedef format_arg Arg; + template struct NamedArg; @@ -1466,21 +1471,20 @@ class format_args { // may require more code (at least on x86-64) even if the same amount of // data is actually copied to stack. It saves ~10% on the bloat test. const internal::Value *values_; - const internal::Arg *args_; + const format_arg *args_; }; - internal::Arg::Type type(unsigned index) const { + format_arg::Type type(unsigned index) const { unsigned shift = index * 4; uint64_t mask = 0xf; - return static_cast( - (types_ & (mask << shift)) >> shift); + return static_cast((types_ & (mask << shift)) >> shift); } template friend class internal::ArgMap; void set_data(const internal::Value *values) { values_ = values; } - void set_data(const internal::Arg *args) { args_ = args; } + void set_data(const format_arg *args) { args_ = args; } public: typedef unsigned size_type; @@ -1494,14 +1498,13 @@ class format_args { } /** Returns the argument at specified index. */ - internal::Arg operator[](size_type index) const { - using internal::Arg; - Arg arg; - bool use_values = type(internal::MAX_PACKED_ARGS - 1) == Arg::NONE; + format_arg operator[](size_type index) const { + format_arg arg; + bool use_values = type(internal::MAX_PACKED_ARGS - 1) == format_arg::NONE; if (index < internal::MAX_PACKED_ARGS) { - Arg::Type arg_type = type(index); + format_arg::Type arg_type = type(index); internal::Value &val = arg; - if (arg_type != Arg::NONE) + if (arg_type != format_arg::NONE) val = use_values ? values_[index] : args_[index]; arg.type = arg_type; return arg; @@ -1509,11 +1512,11 @@ class format_args { if (use_values) { // The index is greater than the number of arguments that can be stored // in values, so return a "none" argument. - arg.type = Arg::NONE; + arg.type = format_arg::NONE; return arg; } for (unsigned i = internal::MAX_PACKED_ARGS; i <= index; ++i) { - if (args_[i].type == Arg::NONE) + if (args_[i].type == format_arg::NONE) return args_[i]; } return args_[index]; From 48fe97835b35023b9fb1668b73d6baa421b70755 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sun, 2 Oct 2016 09:36:40 -0700 Subject: [PATCH 025/340] Add format_arg::operator bool --- fmt/format.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fmt/format.h b/fmt/format.h index d5249326..27137d4d 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -1031,6 +1031,8 @@ struct Value { // allow storage in internal::MemoryBuffer. struct format_arg : internal::Value { Type type; + + explicit operator bool() const noexcept { return type != NONE; } }; namespace internal { From f28799408462457e88a03a2d31ed1c83b35596af Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Fri, 7 Oct 2016 03:22:14 -0700 Subject: [PATCH 026/340] Fix formatting --- doc/api.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/api.rst b/doc/api.rst index ba847ae3..53376188 100644 --- a/doc/api.rst +++ b/doc/api.rst @@ -90,8 +90,8 @@ custom argument formatter class:: // A custom argument formatter that formats negative integers as unsigned // with the ``x`` format specifier. class CustomArgFormatter : - public fmt::BasicArgFormatter { - public: + public fmt::BasicArgFormatter { + public: CustomArgFormatter(fmt::BasicFormatter &f, fmt::FormatSpec &s, const char *fmt) : fmt::BasicArgFormatter(f, s, fmt) {} From 506435bf718d5d313e0469fcf1f13c1655da45f5 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Fri, 7 Oct 2016 03:41:23 -0700 Subject: [PATCH 027/340] Fix formatting --- fmt/time.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fmt/time.h b/fmt/time.h index 675ff0da..e33ee93f 100644 --- a/fmt/time.h +++ b/fmt/time.h @@ -16,7 +16,7 @@ namespace fmt { template void format_value(BasicFormatter &f, - const char *&format_str, const std::tm &tm) { + const char *&format_str, const std::tm &tm) { if (*format_str == ':') ++format_str; const char *end = format_str; From dafbec7553337717c932436ad17569662256aec9 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Fri, 7 Oct 2016 08:37:06 -0700 Subject: [PATCH 028/340] Fix type safety when using custom formatters (#394) --- fmt/format.cc | 64 +---------------- fmt/format.h | 128 ++++++++++++++++++++++++++-------- fmt/printf.h | 40 +++++++---- test/custom-formatter-test.cc | 16 +++-- test/format-test.cc | 9 ++- test/ostream-test.cc | 2 +- 6 files changed, 143 insertions(+), 116 deletions(-) diff --git a/fmt/format.cc b/fmt/format.cc index 6abda6d5..2f43762f 100644 --- a/fmt/format.cc +++ b/fmt/format.cc @@ -403,72 +403,11 @@ FMT_FUNC void format_system_error( fmt::format_error_code(out, error_code, message); // 'fmt::' is for bcc32. } -template -void internal::ArgMap::init(const format_args &args) { - if (!map_.empty()) - return; - typedef internal::NamedArg NamedArg; - const NamedArg *named_arg = 0; - bool use_values = - args.type(MAX_PACKED_ARGS - 1) == internal::Arg::NONE; - if (use_values) { - for (unsigned i = 0;/*nothing*/; ++i) { - internal::Arg::Type arg_type = args.type(i); - switch (arg_type) { - case internal::Arg::NONE: - return; - case internal::Arg::NAMED_ARG: - named_arg = static_cast(args.values_[i].pointer); - map_.push_back(Pair(named_arg->name, *named_arg)); - break; - default: - /*nothing*/; - } - } - return; - } - for (unsigned i = 0; i != MAX_PACKED_ARGS; ++i) { - internal::Arg::Type arg_type = args.type(i); - if (arg_type == internal::Arg::NAMED_ARG) { - named_arg = static_cast(args.args_[i].pointer); - map_.push_back(Pair(named_arg->name, *named_arg)); - } - } - for (unsigned i = MAX_PACKED_ARGS;/*nothing*/; ++i) { - switch (args.args_[i].type) { - case internal::Arg::NONE: - return; - case internal::Arg::NAMED_ARG: - named_arg = static_cast(args.args_[i].pointer); - map_.push_back(Pair(named_arg->name, *named_arg)); - break; - default: - /*nothing*/; - } - } -} - template void internal::FixedBuffer::grow(std::size_t) { FMT_THROW(std::runtime_error("buffer overflow")); } -FMT_FUNC Arg internal::FormatterBase::do_get_arg( - unsigned arg_index, const char *&error) { - Arg arg = args_[arg_index]; - switch (arg.type) { - case Arg::NONE: - error = "argument index out of range"; - break; - case Arg::NAMED_ARG: - arg = *static_cast(arg.pointer); - break; - default: - /*nothing*/; - } - return arg; -} - FMT_FUNC void report_system_error( int error_code, fmt::StringRef message) FMT_NOEXCEPT { // 'fmt::' is for bcc32. @@ -505,7 +444,8 @@ template void printf(BasicWriter &w, BasicCStringRef format, format_args args); -FMT_FUNC int vfprintf(std::FILE *f, CStringRef format, format_args args) { +FMT_FUNC int vfprintf(std::FILE *f, CStringRef format, + basic_format_args> args) { MemoryWriter w; printf(w, format, args); std::size_t size = w.size(); diff --git a/fmt/format.h b/fmt/format.h index 27137d4d..e012bba1 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -1429,7 +1429,7 @@ constexpr uint64_t make_type() { return 0; } enum { MAX_PACKED_ARGS = 16 }; } // namespace internal -template +template class format_arg_store { private: static const size_t NUM_ARGS = sizeof...(Args); @@ -1441,13 +1441,12 @@ class format_arg_store { // If the arguments are not packed, add one more element to mark the end. std::array data_; - template - friend format_arg_store make_format_args(const A & ... args); + template + friend format_arg_store make_format_args(const A & ... args); public: static const uint64_t TYPES = internal::make_type(); - template format_arg_store(const Args &... args, Formatter *) : data_{{internal::MakeValue(args)...}} {} @@ -1455,13 +1454,15 @@ class format_arg_store { }; template -inline format_arg_store make_format_args(const Args & ... args) { +inline format_arg_store + make_format_args(const Args & ... args) { Formatter *f = nullptr; - return format_arg_store(args..., f); + return format_arg_store(args..., f); } /** Formatting arguments. */ -class format_args { +template +class basic_format_args { private: // To reduce compiled code size per formatting function call, types of first // MAX_PACKED_ARGS arguments are passed in the types_ field. @@ -1491,10 +1492,10 @@ class format_args { public: typedef unsigned size_type; - format_args() : types_(0) {} + basic_format_args() : types_(0) {} - template - format_args(const format_arg_store &store) + template + basic_format_args(const format_arg_store &store) : types_(store.TYPES) { set_data(store.data()); } @@ -1525,6 +1526,9 @@ class format_args { } }; +typedef basic_format_args> format_args; +typedef basic_format_args> wformat_args; + #define FMT_DISPATCH(call) static_cast(this)->call /** @@ -1919,7 +1923,8 @@ class ArgMap { MapType map_; public: - FMT_API void init(const format_args &args); + template + void init(const basic_format_args &args); const internal::Arg* find(const fmt::BasicStringRef &name) const { // The list is unsorted, so just return the first matching name. @@ -1932,6 +1937,52 @@ class ArgMap { } }; +template +template +void ArgMap::init(const basic_format_args &args) { + if (!map_.empty()) + return; + typedef internal::NamedArg NamedArg; + const NamedArg *named_arg = 0; + bool use_values = + args.type(MAX_PACKED_ARGS - 1) == internal::Arg::NONE; + if (use_values) { + for (unsigned i = 0;/*nothing*/; ++i) { + internal::Arg::Type arg_type = args.type(i); + switch (arg_type) { + case internal::Arg::NONE: + return; + case internal::Arg::NAMED_ARG: + named_arg = static_cast(args.values_[i].pointer); + map_.push_back(Pair(named_arg->name, *named_arg)); + break; + default: + /*nothing*/; + } + } + return; + } + for (unsigned i = 0; i != MAX_PACKED_ARGS; ++i) { + internal::Arg::Type arg_type = args.type(i); + if (arg_type == internal::Arg::NAMED_ARG) { + named_arg = static_cast(args.args_[i].pointer); + map_.push_back(Pair(named_arg->name, *named_arg)); + } + } + for (unsigned i = MAX_PACKED_ARGS;/*nothing*/; ++i) { + switch (args.args_[i].type) { + case internal::Arg::NONE: + return; + case internal::Arg::NAMED_ARG: + named_arg = static_cast(args.args_[i].pointer); + map_.push_back(Pair(named_arg->name, *named_arg)); + break; + default: + /*nothing*/; + } + } +} + template class ArgFormatterBase : public ArgVisitor { private: @@ -2030,21 +2081,33 @@ class ArgFormatterBase : public ArgVisitor { } }; +template class FormatterBase { - private: - format_args args_; +private: + basic_format_args args_; int next_arg_index_; // Returns the argument with specified index. - FMT_API Arg do_get_arg(unsigned arg_index, const char *&error); + Arg do_get_arg(unsigned arg_index, const char *&error) { + Arg arg = args_[arg_index]; + switch (arg.type) { + case Arg::NONE: + error = "argument index out of range"; + break; + case Arg::NAMED_ARG: + arg = *static_cast(arg.pointer); + break; + default: + /*nothing*/; + } + return arg; + } protected: - const format_args &args() const { return args_; } + FormatterBase(basic_format_args args) + : args_(args), next_arg_index_(0) {} - explicit FormatterBase(const format_args &args) { - args_ = args; - next_arg_index_ = 0; - } + const basic_format_args &args() const { return args_; } // Returns the next argument. Arg next_arg(const char *&error) { @@ -2132,7 +2195,8 @@ class ArgFormatter : public BasicArgFormatter, Char> { /** This template formats data and writes the output to a writer. */ template -class BasicFormatter : private internal::FormatterBase { +class BasicFormatter : + private internal::FormatterBase> { public: /** The character type for the output. */ typedef CharType Char; @@ -2143,7 +2207,8 @@ class BasicFormatter : private internal::FormatterBase { FMT_DISALLOW_COPY_AND_ASSIGN(BasicFormatter); - using internal::FormatterBase::get_arg; + typedef internal::FormatterBase Base; + using Base::get_arg; // Checks if manual indexing is used and returns the argument with // specified name. @@ -2163,8 +2228,8 @@ class BasicFormatter : private internal::FormatterBase { appropriate lifetimes. \endrst */ - BasicFormatter(const format_args &args, BasicWriter &w) - : internal::FormatterBase(args), writer_(w) {} + BasicFormatter(basic_format_args args, BasicWriter &w) + : Base(args), writer_(w) {} /** Returns a reference to the writer associated with this formatter. */ BasicWriter &writer() { return writer_; } @@ -2404,7 +2469,8 @@ class BasicWriter { return std::basic_string(&buffer_[0], buffer_.size()); } - void vwrite(BasicCStringRef format, format_args args) { + void vwrite(BasicCStringRef format, + basic_format_args> args) { BasicFormatter(args, *this).format(format); } @@ -3111,7 +3177,7 @@ inline std::string format(CStringRef format_str, const Args & ... args) { return vformat(format_str, make_format_args>(args...)); } -inline std::wstring vformat(WCStringRef format_str, format_args args) { +inline std::wstring vformat(WCStringRef format_str, wformat_args args) { WMemoryWriter w; w.vwrite(format_str, args); return w.str(); @@ -3348,8 +3414,8 @@ void check_sign(const Char *&s, const Arg &arg) { template inline internal::Arg BasicFormatter::get_arg( BasicStringRef arg_name, const char *&error) { - if (check_no_auto_index(error)) { - map_.init(args()); + if (this->check_no_auto_index(error)) { + map_.init(this->args()); const internal::Arg *arg = map_.find(arg_name); if (arg) return *arg; @@ -3362,7 +3428,7 @@ template inline internal::Arg BasicFormatter::parse_arg_index(const Char *&s) { const char *error = 0; internal::Arg arg = *s < '0' || *s > '9' ? - next_arg(error) : get_arg(internal::parse_nonnegative_int(s), error); + this->next_arg(error) : get_arg(internal::parse_nonnegative_int(s), error); if (error) { FMT_THROW(format_error( *s != '}' && *s != ':' ? "invalid format string" : error)); @@ -3563,18 +3629,18 @@ void BasicFormatter::format(BasicCStringRef format_str) { Char c = *s++; if (c != '{' && c != '}') continue; if (*s == c) { - write(writer_, start, s); + this->write(writer_, start, s); start = ++s; continue; } if (c == '}') FMT_THROW(format_error("unmatched '}' in format string")); - write(writer_, start, s - 1); + this->write(writer_, start, s - 1); internal::Arg arg = internal::is_name_start(*s) ? parse_arg_name(s) : parse_arg_index(s); start = s = format(s, arg); } - write(writer_, start, s); + this->write(writer_, start, s); } } // namespace fmt diff --git a/fmt/printf.h b/fmt/printf.h index 47f71c9b..4317f10b 100644 --- a/fmt/printf.h +++ b/fmt/printf.h @@ -262,7 +262,8 @@ class BasicPrintfArgFormatter : public internal::ArgFormatterBase { /** Formats an argument of a custom (user-defined) type. */ void visit_custom(internal::Arg::CustomValue c) { - BasicFormatter formatter(format_args(), this->writer()); + BasicFormatter formatter(basic_format_args>(), + this->writer()); const Char format_str[] = {'}', 0}; const Char *format = format_str; c.format(&formatter, c.value, &format); @@ -281,10 +282,13 @@ class PrintfArgFormatter /** This template formats data and writes the output to a writer. */ template > -class PrintfFormatter : private internal::FormatterBase { +class PrintfFormatter : + private internal::FormatterBase> { private: BasicWriter &writer_; + typedef internal::FormatterBase Base; + void parse_flags(FormatSpec &spec, const Char *&s); // Returns the argument with specified index or, if arg_index is equal @@ -304,8 +308,9 @@ class PrintfFormatter : private internal::FormatterBase { appropriate lifetimes. \endrst */ - explicit PrintfFormatter(const format_args &args, BasicWriter &w) - : FormatterBase(args), writer_(w) {} + explicit PrintfFormatter(basic_format_args args, + BasicWriter &w) + : Base(args), writer_(w) {} /** Formats stored arguments and writes the output to the writer. */ FMT_API void format(BasicCStringRef format_str); @@ -343,7 +348,7 @@ internal::Arg PrintfFormatter::get_arg(const Char *s, (void)s; const char *error = 0; internal::Arg arg = arg_index == std::numeric_limits::max() ? - next_arg(error) : FormatterBase::get_arg(arg_index - 1, error); + this->next_arg(error) : Base::get_arg(arg_index - 1, error); if (error) FMT_THROW(format_error(!*s ? "invalid format string" : error)); return arg; @@ -391,11 +396,11 @@ void PrintfFormatter::format(BasicCStringRef format_str) { Char c = *s++; if (c != '%') continue; if (*s == c) { - write(writer_, start, s); + this->write(writer_, start, s); start = ++s; continue; } - write(writer_, start, s - 1); + this->write(writer_, start, s - 1); FormatSpec spec; spec.align_ = ALIGN_RIGHT; @@ -480,16 +485,17 @@ void PrintfFormatter::format(BasicCStringRef format_str) { // Format argument. AF(writer_, spec).visit(arg); } - write(writer_, start, s); + this->write(writer_, start, s); } template void printf(BasicWriter &w, BasicCStringRef format, - format_args args) { + basic_format_args> args) { PrintfFormatter(args, w).format(format); } -inline std::string vsprintf(CStringRef format, format_args args) { +inline std::string vsprintf(CStringRef format, + basic_format_args> args) { MemoryWriter w; printf(w, format, args); return w.str(); @@ -509,7 +515,8 @@ inline std::string sprintf(CStringRef format_str, const Args & ... args) { return vsprintf(format_str, make_format_args>(args...)); } -inline std::wstring vsprintf(WCStringRef format, format_args args) { +inline std::wstring vsprintf(WCStringRef format, + basic_format_args> args) { WMemoryWriter w; printf(w, format, args); return w.str(); @@ -521,7 +528,8 @@ inline std::wstring sprintf(WCStringRef format_str, const Args & ... args) { return vsprintf(format_str, vargs); } -FMT_API int vfprintf(std::FILE *f, CStringRef format, format_args args); +FMT_API int vfprintf(std::FILE *f, CStringRef format, + basic_format_args> args); /** \rst @@ -534,11 +542,12 @@ FMT_API int vfprintf(std::FILE *f, CStringRef format, format_args args); */ template inline int fprintf(std::FILE *f, CStringRef format_str, const Args & ... args) { - auto vargs = make_format_args>(args...); + auto vargs = make_format_args>(args...); return vfprintf(f, format_str, vargs); } -inline int vprintf(CStringRef format, format_args args) { +inline int vprintf(CStringRef format, + basic_format_args> args) { return vfprintf(stdout, format, args); } @@ -556,7 +565,8 @@ inline int printf(CStringRef format_str, const Args & ... args) { return vprintf(format_str, make_format_args>(args...)); } -inline int vfprintf(std::ostream &os, CStringRef format_str, format_args args) { +inline int vfprintf(std::ostream &os, CStringRef format_str, + basic_format_args> args) { MemoryWriter w; printf(w, format_str, args); internal::write(os, w); diff --git a/test/custom-formatter-test.cc b/test/custom-formatter-test.cc index 32ea166e..b556ee87 100644 --- a/test/custom-formatter-test.cc +++ b/test/custom-formatter-test.cc @@ -45,10 +45,13 @@ class CustomPrintfArgFormatter : } }; -std::string custom_vformat(const char *format_str, fmt::format_args args) { +typedef fmt::BasicFormatter CustomFormatter; + +std::string custom_vformat(const char *format_str, + fmt::basic_format_args args) { fmt::MemoryWriter writer; // Pass custom argument formatter as a template arg to BasicFormatter. - fmt::BasicFormatter formatter(args, writer); + CustomFormatter formatter(args, writer); formatter.format(format_str); return writer.str(); } @@ -59,9 +62,14 @@ std::string custom_format(const char *format_str, const Args & ... args) { return custom_vformat(format_str, va); } -std::string custom_vsprintf(const char* format_str, fmt::format_args args) { +typedef fmt::PrintfFormatter + CustomPrintfFormatter; + +std::string custom_vsprintf( + const char* format_str, + fmt::basic_format_args args) { fmt::MemoryWriter writer; - fmt::PrintfFormatter formatter(args, writer); + CustomPrintfFormatter formatter(args, writer); formatter.format(format_str); return writer.str(); } diff --git a/test/format-test.cc b/test/format-test.cc index 022b1aa7..616c015d 100644 --- a/test/format-test.cc +++ b/test/format-test.cc @@ -1633,16 +1633,19 @@ class MockArgFormatter : MOCK_METHOD1(visit_int, void (int value)); }; -void vcustom_format(const char *format_str, fmt::format_args args) { +typedef fmt::BasicFormatter CustomFormatter; + +void custom_vformat(const char *format_str, + fmt::basic_format_args args) { fmt::MemoryWriter writer; - fmt::BasicFormatter formatter(args, writer); + CustomFormatter formatter(args, writer); formatter.format(format_str); } template void custom_format(const char *format_str, const Args & ... args) { auto va = fmt::make_format_args>(args...); - return vcustom_format(format_str, va); + return custom_vformat(format_str, va); } TEST(FormatTest, CustomArgFormatter) { diff --git a/test/ostream-test.cc b/test/ostream-test.cc index 9542a28c..2469e041 100644 --- a/test/ostream-test.cc +++ b/test/ostream-test.cc @@ -67,7 +67,7 @@ struct TestArgFormatter : fmt::BasicArgFormatter { TEST(OStreamTest, CustomArg) { fmt::MemoryWriter writer; typedef fmt::BasicFormatter Formatter; - Formatter formatter(fmt::format_args(), writer); + Formatter formatter(fmt::basic_format_args(), writer); fmt::FormatSpec spec; TestArgFormatter af(formatter, spec, "}"); af.visit(fmt::internal::MakeArg(TestEnum())); From 18dfa257d051d3694f6d3fdbf6d77a1e584753fe Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Fri, 21 Oct 2016 06:46:21 -0700 Subject: [PATCH 029/340] Pass correct formatters to make_format_args --- fmt/format.h | 4 ++-- fmt/ostream.h | 19 ++++++++++++------- fmt/printf.h | 26 ++++++++++++++++++++------ test/custom-formatter-test.cc | 4 ++-- test/format-test.cc | 2 +- 5 files changed, 37 insertions(+), 18 deletions(-) diff --git a/fmt/format.h b/fmt/format.h index e012bba1..6ed68352 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -1494,8 +1494,8 @@ class basic_format_args { basic_format_args() : types_(0) {} - template - basic_format_args(const format_arg_store &store) + template + basic_format_args(const format_arg_store &store) : types_(store.TYPES) { set_data(store.data()); } diff --git a/fmt/ostream.h b/fmt/ostream.h index 87b80471..a941f6c9 100644 --- a/fmt/ostream.h +++ b/fmt/ostream.h @@ -69,19 +69,24 @@ struct ConvertToIntImpl { // Write the content of w to os. void write(std::ostream &os, Writer &w); + +template +BasicStringRef format_value( + internal::MemoryBuffer &buffer, + const T &value) { + internal::FormatBuf format_buf(buffer); + std::basic_ostream output(&format_buf); + output << value; + return BasicStringRef(&buffer[0], format_buf.size()); +} } // namespace internal // Formats a value. template void format_value(BasicFormatter &f, - const Char *&format_str, const T &value) { + const Char *&format_str, const T &value) { internal::MemoryBuffer buffer; - - internal::FormatBuf format_buf(buffer); - std::basic_ostream output(&format_buf); - output << value; - - BasicStringRef str(&buffer[0], format_buf.size()); + auto str = internal::format_value(buffer, value); typedef internal::MakeArg< BasicFormatter > MakeArg; format_str = f.format(format_str, MakeArg(str)); } diff --git a/fmt/printf.h b/fmt/printf.h index 4317f10b..75ae5598 100644 --- a/fmt/printf.h +++ b/fmt/printf.h @@ -281,9 +281,14 @@ class PrintfArgFormatter }; /** This template formats data and writes the output to a writer. */ -template > +template > class PrintfFormatter : - private internal::FormatterBase> { + private internal::FormatterBase> { + public: + /** The character type for the output. */ + typedef CharType Char; + private: BasicWriter &writer_; @@ -312,6 +317,8 @@ class PrintfFormatter : BasicWriter &w) : Base(args), writer_(w) {} + BasicWriter &writer() { return writer_; } + /** Formats stored arguments and writes the output to the writer. */ FMT_API void format(BasicCStringRef format_str); }; @@ -488,6 +495,13 @@ void PrintfFormatter::format(BasicCStringRef format_str) { this->write(writer_, start, s); } +// Formats a value. +template +void format_value(PrintfFormatter &f, const Char *&, const T &value) { + internal::MemoryBuffer buffer; + f.writer() << internal::format_value(buffer, value); +} + template void printf(BasicWriter &w, BasicCStringRef format, basic_format_args> args) { @@ -512,7 +526,7 @@ inline std::string vsprintf(CStringRef format, */ template inline std::string sprintf(CStringRef format_str, const Args & ... args) { - return vsprintf(format_str, make_format_args>(args...)); + return vsprintf(format_str, make_format_args>(args...)); } inline std::wstring vsprintf(WCStringRef format, @@ -524,7 +538,7 @@ inline std::wstring vsprintf(WCStringRef format, template inline std::wstring sprintf(WCStringRef format_str, const Args & ... args) { - auto vargs = make_format_args>(args...); + auto vargs = make_format_args>(args...); return vsprintf(format_str, vargs); } @@ -562,7 +576,7 @@ inline int vprintf(CStringRef format, */ template inline int printf(CStringRef format_str, const Args & ... args) { - return vprintf(format_str, make_format_args>(args...)); + return vprintf(format_str, make_format_args>(args...)); } inline int vfprintf(std::ostream &os, CStringRef format_str, @@ -585,7 +599,7 @@ inline int vfprintf(std::ostream &os, CStringRef format_str, template inline int fprintf(std::ostream &os, CStringRef format_str, const Args & ... args) { - auto vargs = make_format_args>(args...); + auto vargs = make_format_args>(args...); return vfprintf(os, format_str, vargs); } } // namespace fmt diff --git a/test/custom-formatter-test.cc b/test/custom-formatter-test.cc index b556ee87..85f307dd 100644 --- a/test/custom-formatter-test.cc +++ b/test/custom-formatter-test.cc @@ -58,7 +58,7 @@ std::string custom_vformat(const char *format_str, template std::string custom_format(const char *format_str, const Args & ... args) { - auto va = fmt::make_format_args>(args...); + auto va = fmt::make_format_args(args...); return custom_vformat(format_str, va); } @@ -76,7 +76,7 @@ std::string custom_vsprintf( template std::string custom_sprintf(const char *format_str, const Args & ... args) { - auto va = fmt::make_format_args>(args...); + auto va = fmt::make_format_args(args...); return custom_vsprintf(format_str, va); } diff --git a/test/format-test.cc b/test/format-test.cc index 616c015d..1be9a821 100644 --- a/test/format-test.cc +++ b/test/format-test.cc @@ -1644,7 +1644,7 @@ void custom_vformat(const char *format_str, template void custom_format(const char *format_str, const Args & ... args) { - auto va = fmt::make_format_args>(args...); + auto va = fmt::make_format_args(args...); return custom_vformat(format_str, va); } From f85d5f4dac89eaf5f9fd87f2673d2b910dd804e4 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sat, 22 Oct 2016 08:04:20 -0700 Subject: [PATCH 030/340] BasicFormatter -> basic_formatter --- fmt/format.cc | 7 +++-- fmt/format.h | 59 ++++++++++++++++++----------------- fmt/ostream.h | 6 ++-- fmt/posix.h | 2 +- fmt/printf.h | 2 +- fmt/time.h | 2 +- test/custom-formatter-test.cc | 6 ++-- test/format-test.cc | 10 +++--- test/ostream-test.cc | 4 +-- test/util-test.cc | 6 ++-- 10 files changed, 53 insertions(+), 51 deletions(-) diff --git a/fmt/format.cc b/fmt/format.cc index 2f43762f..b770fc02 100644 --- a/fmt/format.cc +++ b/fmt/format.cc @@ -362,9 +362,10 @@ FMT_FUNC void internal::format_windows_error( buffer.resize(INLINE_BUFFER_SIZE); for (;;) { wchar_t *system_message = &buffer[0]; - int result = FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, - 0, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - system_message, static_cast(buffer.size()), 0); + int result = FormatMessageW( + FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + 0, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + system_message, static_cast(buffer.size()), 0); if (result != 0) { UTF16ToUTF8 utf8_message; if (utf8_message.convert(system_message) == ERROR_SUCCESS) { diff --git a/fmt/format.h b/fmt/format.h index 6ed68352..62796d11 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -379,7 +379,7 @@ class BasicPrintfArgFormatter; template > -class BasicFormatter; +class basic_formatter; /** \rst @@ -1405,7 +1405,7 @@ struct NamedArg : Arg { template NamedArg(BasicStringRef argname, const T &value) - : Arg(MakeArg< BasicFormatter >(value)), name(argname) {} + : Arg(MakeArg< basic_formatter >(value)), name(argname) {} }; class RuntimeError : public std::runtime_error { @@ -1526,8 +1526,8 @@ class basic_format_args { } }; -typedef basic_format_args> format_args; -typedef basic_format_args> wformat_args; +typedef basic_format_args> format_args; +typedef basic_format_args> wformat_args; #define FMT_DISPATCH(call) static_cast(this)->call @@ -2160,7 +2160,7 @@ private: template class BasicArgFormatter : public internal::ArgFormatterBase { private: - BasicFormatter &formatter_; + basic_formatter &formatter_; const Char *format_; public: @@ -2172,7 +2172,7 @@ class BasicArgFormatter : public internal::ArgFormatterBase { to the part of the format string being parsed for custom argument types. \endrst */ - BasicArgFormatter(BasicFormatter &formatter, + BasicArgFormatter(basic_formatter &formatter, FormatSpec &spec, const Char *fmt) : internal::ArgFormatterBase(formatter.writer(), spec), formatter_(formatter), format_(fmt) {} @@ -2188,15 +2188,15 @@ template class ArgFormatter : public BasicArgFormatter, Char> { public: /** Constructs an argument formatter object. */ - ArgFormatter(BasicFormatter &formatter, + ArgFormatter(basic_formatter &formatter, FormatSpec &spec, const Char *fmt) : BasicArgFormatter, Char>(formatter, spec, fmt) {} }; /** This template formats data and writes the output to a writer. */ template -class BasicFormatter : - private internal::FormatterBase> { +class basic_formatter : + private internal::FormatterBase> { public: /** The character type for the output. */ typedef CharType Char; @@ -2205,9 +2205,9 @@ class BasicFormatter : BasicWriter &writer_; internal::ArgMap map_; - FMT_DISALLOW_COPY_AND_ASSIGN(BasicFormatter); + FMT_DISALLOW_COPY_AND_ASSIGN(basic_formatter); - typedef internal::FormatterBase Base; + typedef internal::FormatterBase Base; using Base::get_arg; // Checks if manual indexing is used and returns the argument with @@ -2223,12 +2223,12 @@ class BasicFormatter : public: /** \rst - Constructs a ``BasicFormatter`` object. References to the arguments and + Constructs a ``basic_formatter`` object. References to the arguments and the writer are stored in the formatter object so make sure they have appropriate lifetimes. \endrst */ - BasicFormatter(basic_format_args args, BasicWriter &w) + basic_formatter(basic_format_args args, BasicWriter &w) : Base(args), writer_(w) {} /** Returns a reference to the writer associated with this formatter. */ @@ -2275,7 +2275,7 @@ class SystemError : public internal::RuntimeError { */ template SystemError(int error_code, CStringRef message, const Args & ... args) { - init(error_code, message, make_format_args>(args...)); + init(error_code, message, make_format_args>(args...)); } ~SystemError() throw(); @@ -2470,8 +2470,8 @@ class BasicWriter { } void vwrite(BasicCStringRef format, - basic_format_args> args) { - BasicFormatter(args, *this).format(format); + basic_format_args> args) { + basic_formatter(args, *this).format(format); } /** @@ -2501,7 +2501,7 @@ class BasicWriter { */ template void write(BasicCStringRef format, const Args & ... args) { - vwrite(format, make_format_args>(args...)); + vwrite(format, make_format_args>(args...)); } BasicWriter &operator<<(int value) { @@ -3129,7 +3129,7 @@ class WindowsError : public SystemError { */ template WindowsError(int error_code, CStringRef message, const Args & ... args) { - init(error_code, message, make_format_args>(args...)); + init(error_code, message, make_format_args>(args...)); } }; @@ -3154,7 +3154,7 @@ template inline void print_colored(Color c, CStringRef format_str, const Args & ... args) { vprint_colored(c, format_str, - make_format_args>(args...)); + make_format_args>(args...)); } inline std::string vformat(CStringRef format_str, format_args args) { @@ -3174,7 +3174,7 @@ inline std::string vformat(CStringRef format_str, format_args args) { */ template inline std::string format(CStringRef format_str, const Args & ... args) { - return vformat(format_str, make_format_args>(args...)); + return vformat(format_str, make_format_args>(args...)); } inline std::wstring vformat(WCStringRef format_str, wformat_args args) { @@ -3185,7 +3185,7 @@ inline std::wstring vformat(WCStringRef format_str, wformat_args args) { template inline std::wstring format(WCStringRef format_str, const Args & ... args) { - auto vargs = make_format_args>(args...); + auto vargs = make_format_args>(args...); return vformat(format_str, vargs); } @@ -3202,7 +3202,7 @@ FMT_API void vprint(std::FILE *f, CStringRef format_str, format_args args); */ template inline void print(std::FILE *f, CStringRef format_str, const Args & ... args) { - vprint(f, format_str, make_format_args>(args...)); + vprint(f, format_str, make_format_args>(args...)); } FMT_API void vprint(CStringRef format_str, format_args args); @@ -3218,7 +3218,7 @@ FMT_API void vprint(CStringRef format_str, format_args args); */ template inline void print(CStringRef format_str, const Args & ... args) { - vprint(format_str, make_format_args>(args...)); + vprint(format_str, make_format_args>(args...)); } /** @@ -3412,7 +3412,7 @@ void check_sign(const Char *&s, const Arg &arg) { } // namespace internal template -inline internal::Arg BasicFormatter::get_arg( +inline internal::Arg basic_formatter::get_arg( BasicStringRef arg_name, const char *&error) { if (this->check_no_auto_index(error)) { map_.init(this->args()); @@ -3425,10 +3425,11 @@ inline internal::Arg BasicFormatter::get_arg( } template -inline internal::Arg BasicFormatter::parse_arg_index(const Char *&s) { +inline internal::Arg basic_formatter::parse_arg_index( + const Char *&s) { const char *error = 0; internal::Arg arg = *s < '0' || *s > '9' ? - this->next_arg(error) : get_arg(internal::parse_nonnegative_int(s), error); + this->next_arg(error) : get_arg(internal::parse_nonnegative_int(s), error); if (error) { FMT_THROW(format_error( *s != '}' && *s != ':' ? "invalid format string" : error)); @@ -3437,7 +3438,7 @@ inline internal::Arg BasicFormatter::parse_arg_index(const Char *&s) { } template -inline internal::Arg BasicFormatter::parse_arg_name(const Char *&s) { +inline internal::Arg basic_formatter::parse_arg_name(const Char *&s) { assert(internal::is_name_start(*s)); const Char *start = s; Char c; @@ -3452,7 +3453,7 @@ inline internal::Arg BasicFormatter::parse_arg_name(const Char *&s) { } template -const Char *BasicFormatter::format( +const Char *basic_formatter::format( const Char *&format_str, const internal::Arg &arg) { using internal::Arg; const Char *s = format_str; @@ -3622,7 +3623,7 @@ const Char *BasicFormatter::format( } template -void BasicFormatter::format(BasicCStringRef format_str) { +void basic_formatter::format(BasicCStringRef format_str) { const Char *s = format_str.c_str(); const Char *start = s; while (*s) { diff --git a/fmt/ostream.h b/fmt/ostream.h index a941f6c9..ac089749 100644 --- a/fmt/ostream.h +++ b/fmt/ostream.h @@ -83,11 +83,11 @@ BasicStringRef format_value( // Formats a value. template -void format_value(BasicFormatter &f, +void format_value(basic_formatter &f, const Char *&format_str, const T &value) { internal::MemoryBuffer buffer; auto str = internal::format_value(buffer, value); - typedef internal::MakeArg< BasicFormatter > MakeArg; + typedef internal::MakeArg< basic_formatter > MakeArg; format_str = f.format(format_str, MakeArg(str)); } @@ -105,7 +105,7 @@ FMT_API void vprint(std::ostream &os, CStringRef format_str, format_args args); template inline void print(std::ostream &os, CStringRef format_str, const Args & ... args) { - vprint(os, format_str, make_format_args>(args...)); + vprint(os, format_str, make_format_args>(args...)); } } // namespace fmt diff --git a/fmt/posix.h b/fmt/posix.h index 18d14de2..5fd17859 100644 --- a/fmt/posix.h +++ b/fmt/posix.h @@ -172,7 +172,7 @@ public: template inline void print(CStringRef format_str, const Args & ... args) { - vprint(format_str, make_format_args>(args...)); + vprint(format_str, make_format_args>(args...)); } }; diff --git a/fmt/printf.h b/fmt/printf.h index 75ae5598..a0d2b8d3 100644 --- a/fmt/printf.h +++ b/fmt/printf.h @@ -262,7 +262,7 @@ class BasicPrintfArgFormatter : public internal::ArgFormatterBase { /** Formats an argument of a custom (user-defined) type. */ void visit_custom(internal::Arg::CustomValue c) { - BasicFormatter formatter(basic_format_args>(), + basic_formatter formatter(basic_format_args>(), this->writer()); const Char format_str[] = {'}', 0}; const Char *format = format_str; diff --git a/fmt/time.h b/fmt/time.h index e33ee93f..ed2335c0 100644 --- a/fmt/time.h +++ b/fmt/time.h @@ -15,7 +15,7 @@ namespace fmt { template -void format_value(BasicFormatter &f, +void format_value(basic_formatter &f, const char *&format_str, const std::tm &tm) { if (*format_str == ':') ++format_str; diff --git a/test/custom-formatter-test.cc b/test/custom-formatter-test.cc index 85f307dd..53227a3c 100644 --- a/test/custom-formatter-test.cc +++ b/test/custom-formatter-test.cc @@ -17,7 +17,7 @@ using fmt::BasicPrintfArgFormatter; class CustomArgFormatter : public fmt::BasicArgFormatter { public: - CustomArgFormatter(fmt::BasicFormatter &f, + CustomArgFormatter(fmt::basic_formatter &f, fmt::FormatSpec &s, const char *fmt) : fmt::BasicArgFormatter(f, s, fmt) {} @@ -45,12 +45,12 @@ class CustomPrintfArgFormatter : } }; -typedef fmt::BasicFormatter CustomFormatter; +typedef fmt::basic_formatter CustomFormatter; std::string custom_vformat(const char *format_str, fmt::basic_format_args args) { fmt::MemoryWriter writer; - // Pass custom argument formatter as a template arg to BasicFormatter. + // Pass custom argument formatter as a template arg to basic_formatter. CustomFormatter formatter(args, writer); formatter.format(format_str); return writer.str(); diff --git a/test/format-test.cc b/test/format-test.cc index 1be9a821..2c7fc29f 100644 --- a/test/format-test.cc +++ b/test/format-test.cc @@ -1355,7 +1355,7 @@ TEST(FormatterTest, FormatCStringRef) { EXPECT_EQ("test", format("{0}", CStringRef("test"))); } -void format_value(fmt::BasicFormatter &f, const char *, const Date &d) { +void format_value(fmt::basic_formatter &f, const char *, const Date &d) { f.writer() << d.year() << '-' << d.month() << '-' << d.day(); } @@ -1368,7 +1368,7 @@ TEST(FormatterTest, FormatCustom) { class Answer {}; template -void format_value(fmt::BasicFormatter &f, const Char *, Answer) { +void format_value(fmt::basic_formatter &f, const Char *, Answer) { f.writer() << "42"; } @@ -1559,7 +1559,7 @@ std::string vformat_message(int id, const char *format, fmt::format_args args) { template std::string format_message(int id, const char *format, const Args & ... args) { - auto va = fmt::make_format_args>(args...); + auto va = fmt::make_format_args>(args...); return vformat_message(id, format, va); } @@ -1624,7 +1624,7 @@ class MockArgFormatter : public: typedef fmt::internal::ArgFormatterBase Base; - MockArgFormatter(fmt::BasicFormatter &f, + MockArgFormatter(fmt::basic_formatter &f, fmt::FormatSpec &s, const char *) : fmt::internal::ArgFormatterBase(f.writer(), s) { EXPECT_CALL(*this, visit_int(42)); @@ -1633,7 +1633,7 @@ class MockArgFormatter : MOCK_METHOD1(visit_int, void (int value)); }; -typedef fmt::BasicFormatter CustomFormatter; +typedef fmt::basic_formatter CustomFormatter; void custom_vformat(const char *format_str, fmt::basic_format_args args) { diff --git a/test/ostream-test.cc b/test/ostream-test.cc index 2469e041..224540b1 100644 --- a/test/ostream-test.cc +++ b/test/ostream-test.cc @@ -59,14 +59,14 @@ TEST(OStreamTest, Enum) { } struct TestArgFormatter : fmt::BasicArgFormatter { - TestArgFormatter(fmt::BasicFormatter &f, + TestArgFormatter(fmt::basic_formatter &f, fmt::FormatSpec &s, const char *fmt) : fmt::BasicArgFormatter(f, s, fmt) {} }; TEST(OStreamTest, CustomArg) { fmt::MemoryWriter writer; - typedef fmt::BasicFormatter Formatter; + typedef fmt::basic_formatter Formatter; Formatter formatter(fmt::basic_format_args(), writer); fmt::FormatSpec spec; TestArgFormatter af(formatter, spec, "}"); diff --git a/test/util-test.cc b/test/util-test.cc index 5d5ddf32..5e836d49 100644 --- a/test/util-test.cc +++ b/test/util-test.cc @@ -64,13 +64,13 @@ namespace { struct Test {}; template -void format_value(fmt::BasicFormatter &f, const Char *, Test) { +void format_value(fmt::basic_formatter &f, const Char *, Test) { f.writer() << "test"; } template Arg make_arg(const T &value) { - typedef fmt::internal::MakeValue< fmt::BasicFormatter > MakeValue; + typedef fmt::internal::MakeValue< fmt::basic_formatter > MakeValue; Arg arg = MakeValue(value); arg.type = fmt::internal::type(); return arg; @@ -566,7 +566,7 @@ TEST(ArgTest, MakeArg) { EXPECT_EQ(fmt::internal::Arg::CUSTOM, arg.type); EXPECT_EQ(&t, arg.custom.value); fmt::MemoryWriter w; - fmt::BasicFormatter formatter(fmt::format_args(), w); + fmt::basic_formatter formatter(fmt::format_args(), w); const char *s = "}"; arg.custom.format(&formatter, &t, &s); EXPECT_EQ("test", w.str()); From be613204abec44e6e419078176136bd7288c24e8 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sat, 22 Oct 2016 08:19:19 -0700 Subject: [PATCH 031/340] Char -> char_type --- fmt/format.h | 8 ++++---- fmt/printf.h | 8 ++++---- test/util-test.cc | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/fmt/format.h b/fmt/format.h index 62796d11..6c688b18 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -1234,7 +1234,7 @@ constexpr Type type() { return gettype::type>(); } template class MakeValue : public Arg { public: - typedef typename Formatter::Char Char; + typedef typename Formatter::char_type Char; private: // The following two methods are private to disallow formatting of @@ -2194,12 +2194,12 @@ class ArgFormatter : public BasicArgFormatter, Char> { }; /** This template formats data and writes the output to a writer. */ -template +template class basic_formatter : - private internal::FormatterBase> { + private internal::FormatterBase> { public: /** The character type for the output. */ - typedef CharType Char; + typedef Char char_type; private: BasicWriter &writer_; diff --git a/fmt/printf.h b/fmt/printf.h index a0d2b8d3..d75eef1f 100644 --- a/fmt/printf.h +++ b/fmt/printf.h @@ -281,13 +281,13 @@ class PrintfArgFormatter }; /** This template formats data and writes the output to a writer. */ -template > +template > class PrintfFormatter : - private internal::FormatterBase> { + private internal::FormatterBase> { public: /** The character type for the output. */ - typedef CharType Char; + typedef Char char_type; private: BasicWriter &writer_; diff --git a/test/util-test.cc b/test/util-test.cc index 5e836d49..502f463e 100644 --- a/test/util-test.cc +++ b/test/util-test.cc @@ -578,7 +578,7 @@ TEST(UtilTest, FormatArgs) { } struct CustomFormatter { - typedef char Char; + typedef char char_type; }; void format_value(CustomFormatter &, const char *&s, const Test &) { From 64ca334a2dee674e2a26095c4d2b834d50cab537 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sat, 22 Oct 2016 09:15:28 -0700 Subject: [PATCH 032/340] CharType -> Char --- fmt/format.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/fmt/format.h b/fmt/format.h index 6c688b18..40c7c17b 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -377,8 +377,7 @@ class ArgFormatter; template class BasicPrintfArgFormatter; -template > +template > class basic_formatter; /** From edf98792a51f7a0e7ca52290875fa9efe2c4892e Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Tue, 25 Oct 2016 05:55:40 -0700 Subject: [PATCH 033/340] Pass writer to format_value --- fmt/format.h | 24 +++++++++++++++++------- fmt/ostream.h | 2 +- fmt/printf.h | 5 +++-- fmt/time.h | 5 +++-- test/format-test.cc | 6 ++++-- test/util-test.cc | 13 ++++++++----- 6 files changed, 36 insertions(+), 19 deletions(-) diff --git a/fmt/format.h b/fmt/format.h index 40c7c17b..56347bad 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -993,7 +993,7 @@ struct Value { }; typedef void (*FormatFunc)( - void *formatter, const void *arg, void *format_str_ptr); + void *writer, void *formatter, const void *arg, void *format_str_ptr); struct CustomValue { const void *value; @@ -1160,7 +1160,7 @@ inline fmt::StringRef thousands_sep(...) { return ""; } #endif template -void format_value(Formatter &, const Char *, const T &) { +void format_value(BasicWriter &, Formatter &, const Char *, const T &) { FMT_STATIC_ASSERT(False::value, "Cannot format argument. To enable the use of ostream " "operator<< include fmt/ostream.h. Otherwise provide " @@ -1271,8 +1271,10 @@ class MakeValue : public Arg { // Formats an argument of a custom type, such as a user-defined class. template static void format_custom_arg( - void *formatter, const void *arg, void *format_str_ptr) { - format_value(*static_cast(formatter), + void *writer, void *formatter, const void *arg, void *format_str_ptr) { + typedef BasicWriter Writer; + format_value(*static_cast(writer), + *static_cast(formatter), *static_cast(format_str_ptr), *static_cast(arg)); } @@ -2178,7 +2180,7 @@ class BasicArgFormatter : public internal::ArgFormatterBase { /** Formats an argument of a custom (user-defined) type. */ void visit_custom(internal::Arg::CustomValue c) { - c.format(&formatter_, c.value, &format_); + c.format(&formatter_.writer(), &formatter_, c.value, &format_); } }; @@ -2240,6 +2242,14 @@ class basic_formatter : const Char *format(const Char *&format_str, const internal::Arg &arg); }; +template +void vformat(BasicWriter &writer, + BasicCStringRef format_str, + basic_format_args> args) { + basic_formatter formatter(args, writer); + formatter.format(format_str); +} + /** An error returned by an operating system or a language runtime, for example a file opening error. @@ -2470,7 +2480,7 @@ class BasicWriter { void vwrite(BasicCStringRef format, basic_format_args> args) { - basic_formatter(args, *this).format(format); + vformat(*this, format, args); } /** @@ -3459,7 +3469,7 @@ const Char *basic_formatter::format( FormatSpec spec; if (*s == ':') { if (arg.type == Arg::CUSTOM) { - arg.custom.format(this, arg.custom.value, &s); + arg.custom.format(&writer(), this, arg.custom.value, &s); return s; } ++s; diff --git a/fmt/ostream.h b/fmt/ostream.h index ac089749..5fee51a9 100644 --- a/fmt/ostream.h +++ b/fmt/ostream.h @@ -83,7 +83,7 @@ BasicStringRef format_value( // Formats a value. template -void format_value(basic_formatter &f, +void format_value(BasicWriter &w, basic_formatter &f, const Char *&format_str, const T &value) { internal::MemoryBuffer buffer; auto str = internal::format_value(buffer, value); diff --git a/fmt/printf.h b/fmt/printf.h index d75eef1f..1635396e 100644 --- a/fmt/printf.h +++ b/fmt/printf.h @@ -266,7 +266,7 @@ class BasicPrintfArgFormatter : public internal::ArgFormatterBase { this->writer()); const Char format_str[] = {'}', 0}; const Char *format = format_str; - c.format(&formatter, c.value, &format); + c.format(&formatter.writer(), &formatter, c.value, &format); } }; @@ -497,7 +497,8 @@ void PrintfFormatter::format(BasicCStringRef format_str) { // Formats a value. template -void format_value(PrintfFormatter &f, const Char *&, const T &value) { +void format_value(BasicWriter &w, PrintfFormatter &f, + const Char *&, const T &value) { internal::MemoryBuffer buffer; f.writer() << internal::format_value(buffer, value); } diff --git a/fmt/time.h b/fmt/time.h index ed2335c0..bb12a66f 100644 --- a/fmt/time.h +++ b/fmt/time.h @@ -14,8 +14,9 @@ #include namespace fmt { + template -void format_value(basic_formatter &f, +void format_value(Writer &w, basic_formatter &f, const char *&format_str, const std::tm &tm) { if (*format_str == ':') ++format_str; @@ -27,7 +28,7 @@ void format_value(basic_formatter &f, internal::MemoryBuffer format; format.append(format_str, end + 1); format[format.size() - 1] = '\0'; - Buffer &buffer = f.writer().buffer(); + Buffer &buffer = w.buffer(); std::size_t start = buffer.size(); for (;;) { std::size_t size = buffer.capacity() - start; diff --git a/test/format-test.cc b/test/format-test.cc index 2c7fc29f..998767bf 100644 --- a/test/format-test.cc +++ b/test/format-test.cc @@ -1355,7 +1355,8 @@ TEST(FormatterTest, FormatCStringRef) { EXPECT_EQ("test", format("{0}", CStringRef("test"))); } -void format_value(fmt::basic_formatter &f, const char *, const Date &d) { +void format_value(fmt::Writer &w, fmt::basic_formatter &f, + const char *, const Date &d) { f.writer() << d.year() << '-' << d.month() << '-' << d.day(); } @@ -1368,7 +1369,8 @@ TEST(FormatterTest, FormatCustom) { class Answer {}; template -void format_value(fmt::basic_formatter &f, const Char *, Answer) { +void format_value(BasicWriter &w, fmt::basic_formatter &f, + const Char *, Answer) { f.writer() << "42"; } diff --git a/test/util-test.cc b/test/util-test.cc index 502f463e..d27d2a3f 100644 --- a/test/util-test.cc +++ b/test/util-test.cc @@ -64,8 +64,9 @@ namespace { struct Test {}; template -void format_value(fmt::basic_formatter &f, const Char *, Test) { - f.writer() << "test"; +void format_value(fmt::BasicWriter &w, fmt::basic_formatter &f, + const Char *, Test) { + w << "test"; } template @@ -568,7 +569,7 @@ TEST(ArgTest, MakeArg) { fmt::MemoryWriter w; fmt::basic_formatter formatter(fmt::format_args(), w); const char *s = "}"; - arg.custom.format(&formatter, &t, &s); + arg.custom.format(&formatter.writer(), &formatter, &t, &s); EXPECT_EQ("test", w.str()); } @@ -581,7 +582,8 @@ struct CustomFormatter { typedef char char_type; }; -void format_value(CustomFormatter &, const char *&s, const Test &) { +void format_value(fmt::Writer &, CustomFormatter &, const char *&s, + const Test &) { s = "custom_format"; } @@ -590,7 +592,8 @@ TEST(UtilTest, MakeValueWithCustomFormatter) { Arg arg = fmt::internal::MakeValue(t); CustomFormatter formatter; const char *s = ""; - arg.custom.format(&formatter, &t, &s); + fmt::MemoryWriter w; + arg.custom.format(&w, &formatter, &t, &s); EXPECT_STREQ("custom_format", s); } From b656a1c133a0dccd8070d391ba5e80852bc6a6fb Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Tue, 25 Oct 2016 06:19:19 -0700 Subject: [PATCH 034/340] Make value the second argument to format_value --- fmt/format.h | 16 ++++++++-------- fmt/ostream.h | 5 +++-- fmt/printf.h | 6 +++--- fmt/time.h | 5 +++-- test/format-test.cc | 8 ++++---- test/util-test.cc | 8 ++++---- 6 files changed, 25 insertions(+), 23 deletions(-) diff --git a/fmt/format.h b/fmt/format.h index 56347bad..8cddbd7f 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -993,7 +993,7 @@ struct Value { }; typedef void (*FormatFunc)( - void *writer, void *formatter, const void *arg, void *format_str_ptr); + void *writer, const void *arg, void *formatter, void *format_str_ptr); struct CustomValue { const void *value; @@ -1159,8 +1159,8 @@ inline fmt::StringRef thousands_sep(...) { return ""; } typedef int FMT_CONCAT_(Assert, __LINE__)[(cond) ? 1 : -1] FMT_UNUSED #endif -template -void format_value(BasicWriter &, Formatter &, const Char *, const T &) { +template +void format_value(BasicWriter &, const T &, Formatter &, const Char *) { FMT_STATIC_ASSERT(False::value, "Cannot format argument. To enable the use of ostream " "operator<< include fmt/ostream.h. Otherwise provide " @@ -1271,12 +1271,12 @@ class MakeValue : public Arg { // Formats an argument of a custom type, such as a user-defined class. template static void format_custom_arg( - void *writer, void *formatter, const void *arg, void *format_str_ptr) { + void *writer, const void *arg, void *formatter, void *format_str_ptr) { typedef BasicWriter Writer; format_value(*static_cast(writer), + *static_cast(arg), *static_cast(formatter), - *static_cast(format_str_ptr), - *static_cast(arg)); + *static_cast(format_str_ptr)); } public: @@ -2180,7 +2180,7 @@ class BasicArgFormatter : public internal::ArgFormatterBase { /** Formats an argument of a custom (user-defined) type. */ void visit_custom(internal::Arg::CustomValue c) { - c.format(&formatter_.writer(), &formatter_, c.value, &format_); + c.format(&formatter_.writer(), c.value, &formatter_, &format_); } }; @@ -3469,7 +3469,7 @@ const Char *basic_formatter::format( FormatSpec spec; if (*s == ':') { if (arg.type == Arg::CUSTOM) { - arg.custom.format(&writer(), this, arg.custom.value, &s); + arg.custom.format(&writer(), arg.custom.value, this, &s); return s; } ++s; diff --git a/fmt/ostream.h b/fmt/ostream.h index 5fee51a9..968a4100 100644 --- a/fmt/ostream.h +++ b/fmt/ostream.h @@ -83,8 +83,9 @@ BasicStringRef format_value( // Formats a value. template -void format_value(BasicWriter &w, basic_formatter &f, - const Char *&format_str, const T &value) { +void format_value(BasicWriter &w, const T &value, + basic_formatter &f, + const Char *&format_str) { internal::MemoryBuffer buffer; auto str = internal::format_value(buffer, value); typedef internal::MakeArg< basic_formatter > MakeArg; diff --git a/fmt/printf.h b/fmt/printf.h index 1635396e..cf9a8517 100644 --- a/fmt/printf.h +++ b/fmt/printf.h @@ -266,7 +266,7 @@ class BasicPrintfArgFormatter : public internal::ArgFormatterBase { this->writer()); const Char format_str[] = {'}', 0}; const Char *format = format_str; - c.format(&formatter.writer(), &formatter, c.value, &format); + c.format(&formatter.writer(), c.value, &formatter, &format); } }; @@ -497,8 +497,8 @@ void PrintfFormatter::format(BasicCStringRef format_str) { // Formats a value. template -void format_value(BasicWriter &w, PrintfFormatter &f, - const Char *&, const T &value) { +void format_value(BasicWriter &w, const T &value, + PrintfFormatter &f, const Char *&) { internal::MemoryBuffer buffer; f.writer() << internal::format_value(buffer, value); } diff --git a/fmt/time.h b/fmt/time.h index bb12a66f..5b40a93f 100644 --- a/fmt/time.h +++ b/fmt/time.h @@ -16,8 +16,9 @@ namespace fmt { template -void format_value(Writer &w, basic_formatter &f, - const char *&format_str, const std::tm &tm) { +void format_value(Writer &w, const std::tm &tm, + basic_formatter &f, + const char *&format_str) { if (*format_str == ':') ++format_str; const char *end = format_str; diff --git a/test/format-test.cc b/test/format-test.cc index 998767bf..2d4d10aa 100644 --- a/test/format-test.cc +++ b/test/format-test.cc @@ -1355,8 +1355,8 @@ TEST(FormatterTest, FormatCStringRef) { EXPECT_EQ("test", format("{0}", CStringRef("test"))); } -void format_value(fmt::Writer &w, fmt::basic_formatter &f, - const char *, const Date &d) { +void format_value(fmt::Writer &w, const Date &d, fmt::basic_formatter &f, + const char *) { f.writer() << d.year() << '-' << d.month() << '-' << d.day(); } @@ -1369,8 +1369,8 @@ TEST(FormatterTest, FormatCustom) { class Answer {}; template -void format_value(BasicWriter &w, fmt::basic_formatter &f, - const Char *, Answer) { +void format_value(BasicWriter &w, Answer, fmt::basic_formatter &f, + const Char *) { f.writer() << "42"; } diff --git a/test/util-test.cc b/test/util-test.cc index d27d2a3f..33603340 100644 --- a/test/util-test.cc +++ b/test/util-test.cc @@ -64,8 +64,8 @@ namespace { struct Test {}; template -void format_value(fmt::BasicWriter &w, fmt::basic_formatter &f, - const Char *, Test) { +void format_value(fmt::BasicWriter &w, Test, + fmt::basic_formatter &f, const Char *) { w << "test"; } @@ -582,8 +582,8 @@ struct CustomFormatter { typedef char char_type; }; -void format_value(fmt::Writer &, CustomFormatter &, const char *&s, - const Test &) { +void format_value(fmt::Writer &, const Test &, CustomFormatter &, + const char *&s) { s = "custom_format"; } From 2bba420337944a89cffe9485e528e433b959a730 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Wed, 26 Oct 2016 17:54:11 -0700 Subject: [PATCH 035/340] Pass writer directly to format_value (#400) --- fmt/format.cc | 5 ++- fmt/format.h | 82 +++++++++++++++-------------------- fmt/ostream.h | 2 +- fmt/printf.h | 33 +++++++------- test/custom-formatter-test.cc | 16 +++---- test/format-test.cc | 14 +++--- test/ostream-test.cc | 9 ++-- test/util-test.cc | 4 +- 8 files changed, 76 insertions(+), 89 deletions(-) diff --git a/fmt/format.cc b/fmt/format.cc index b770fc02..55ece67c 100644 --- a/fmt/format.cc +++ b/fmt/format.cc @@ -463,7 +463,7 @@ template void internal::FixedBuffer::grow(std::size_t); template void internal::ArgMap::init(const format_args &args); -template void PrintfFormatter::format(CStringRef format); +template void PrintfFormatter::format(Writer &writer, CStringRef format); template int internal::CharTraits::format_float( char *buffer, std::size_t size, const char *format, @@ -479,7 +479,8 @@ template void internal::FixedBuffer::grow(std::size_t); template void internal::ArgMap::init(const format_args &args); -template void PrintfFormatter::format(WCStringRef format); +template void PrintfFormatter::format(WWriter &writer, + WCStringRef format); template int internal::CharTraits::format_float( wchar_t *buffer, std::size_t size, const wchar_t *format, diff --git a/fmt/format.h b/fmt/format.h index 8cddbd7f..9d9359bc 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -2132,13 +2132,13 @@ private: next_arg_index_ = -1; return true; } - - template - void write(BasicWriter &w, const Char *start, const Char *end) { - if (start != end) - w << BasicStringRef(start, internal::to_unsigned(end - start)); - } }; + +template +inline void write(BasicWriter &w, const Char *start, const Char *end) { + if (start != end) + w << BasicStringRef(start, internal::to_unsigned(end - start)); +} } // namespace internal /** @@ -2173,14 +2173,15 @@ class BasicArgFormatter : public internal::ArgFormatterBase { to the part of the format string being parsed for custom argument types. \endrst */ - BasicArgFormatter(basic_formatter &formatter, + BasicArgFormatter(BasicWriter &writer, + basic_formatter &formatter, FormatSpec &spec, const Char *fmt) - : internal::ArgFormatterBase(formatter.writer(), spec), + : internal::ArgFormatterBase(writer, spec), formatter_(formatter), format_(fmt) {} /** Formats an argument of a custom (user-defined) type. */ void visit_custom(internal::Arg::CustomValue c) { - c.format(&formatter_.writer(), c.value, &formatter_, &format_); + c.format(&this->writer(), c.value, &formatter_, &format_); } }; @@ -2189,9 +2190,9 @@ template class ArgFormatter : public BasicArgFormatter, Char> { public: /** Constructs an argument formatter object. */ - ArgFormatter(basic_formatter &formatter, + ArgFormatter(BasicWriter &writer, basic_formatter &formatter, FormatSpec &spec, const Char *fmt) - : BasicArgFormatter, Char>(formatter, spec, fmt) {} + : BasicArgFormatter, Char>(writer, formatter, spec, fmt) {} }; /** This template formats data and writes the output to a writer. */ @@ -2203,7 +2204,6 @@ class basic_formatter : typedef Char char_type; private: - BasicWriter &writer_; internal::ArgMap map_; FMT_DISALLOW_COPY_AND_ASSIGN(basic_formatter); @@ -2215,41 +2215,26 @@ class basic_formatter : // specified name. internal::Arg get_arg(BasicStringRef arg_name, const char *&error); - // Parses argument index and returns corresponding argument. - internal::Arg parse_arg_index(const Char *&s); - - // Parses argument name and returns corresponding argument. - internal::Arg parse_arg_name(const Char *&s); - public: /** \rst - Constructs a ``basic_formatter`` object. References to the arguments and - the writer are stored in the formatter object so make sure they have - appropriate lifetimes. + Constructs a ``basic_formatter`` object. References to the arguments are + stored in the formatter object so make sure they have appropriate lifetimes. \endrst */ - basic_formatter(basic_format_args args, BasicWriter &w) - : Base(args), writer_(w) {} + basic_formatter(basic_format_args args) : Base(args) {} - /** Returns a reference to the writer associated with this formatter. */ - BasicWriter &writer() { return writer_; } - - /** Formats stored arguments and writes the output to the writer. */ - void format(BasicCStringRef format_str); + // Parses argument index and returns corresponding argument. + internal::Arg parse_arg_index(const Char *&s); + + // Parses argument name and returns corresponding argument. + internal::Arg parse_arg_name(const Char *&s); // Formats a single argument and advances format_str, a format string pointer. - const Char *format(const Char *&format_str, const internal::Arg &arg); + const Char *format(BasicWriter &writer, const Char *&format_str, + const internal::Arg &arg); }; -template -void vformat(BasicWriter &writer, - BasicCStringRef format_str, - basic_format_args> args) { - basic_formatter formatter(args, writer); - formatter.format(format_str); -} - /** An error returned by an operating system or a language runtime, for example a file opening error. @@ -3463,13 +3448,13 @@ inline internal::Arg basic_formatter::parse_arg_name(const Char *&s) { template const Char *basic_formatter::format( - const Char *&format_str, const internal::Arg &arg) { + BasicWriter &writer, const Char *&format_str, const internal::Arg &arg) { using internal::Arg; const Char *s = format_str; FormatSpec spec; if (*s == ':') { if (arg.type == Arg::CUSTOM) { - arg.custom.format(&writer(), arg.custom.value, this, &s); + arg.custom.format(&writer, arg.custom.value, this, &s); return s; } ++s; @@ -3627,30 +3612,33 @@ const Char *basic_formatter::format( FMT_THROW(format_error("missing '}' in format string")); // Format argument. - ArgFormatter(*this, spec, s - 1).visit(arg); + ArgFormatter(writer, *this, spec, s - 1).visit(arg); return s; } -template -void basic_formatter::format(BasicCStringRef format_str) { +/** Formats arguments and writes the output to the writer. */ +template +void vformat(BasicWriter &writer, BasicCStringRef format_str, + basic_format_args> args) { + basic_formatter formatter(args); const Char *s = format_str.c_str(); const Char *start = s; while (*s) { Char c = *s++; if (c != '{' && c != '}') continue; if (*s == c) { - this->write(writer_, start, s); + internal::write(writer, start, s); start = ++s; continue; } if (c == '}') FMT_THROW(format_error("unmatched '}' in format string")); - this->write(writer_, start, s - 1); + internal::write(writer, start, s - 1); internal::Arg arg = internal::is_name_start(*s) ? - parse_arg_name(s) : parse_arg_index(s); - start = s = format(s, arg); + formatter.parse_arg_name(s) : formatter.parse_arg_index(s); + start = s = formatter.format(writer, s, arg); } - this->write(writer_, start, s); + internal::write(writer, start, s); } } // namespace fmt diff --git a/fmt/ostream.h b/fmt/ostream.h index 968a4100..6173e688 100644 --- a/fmt/ostream.h +++ b/fmt/ostream.h @@ -89,7 +89,7 @@ void format_value(BasicWriter &w, const T &value, internal::MemoryBuffer buffer; auto str = internal::format_value(buffer, value); typedef internal::MakeArg< basic_formatter > MakeArg; - format_str = f.format(format_str, MakeArg(str)); + format_str = f.format(w, format_str, MakeArg(str)); } FMT_API void vprint(std::ostream &os, CStringRef format_str, format_args args); diff --git a/fmt/printf.h b/fmt/printf.h index cf9a8517..7d171255 100644 --- a/fmt/printf.h +++ b/fmt/printf.h @@ -262,11 +262,11 @@ class BasicPrintfArgFormatter : public internal::ArgFormatterBase { /** Formats an argument of a custom (user-defined) type. */ void visit_custom(internal::Arg::CustomValue c) { - basic_formatter formatter(basic_format_args>(), - this->writer()); + typedef basic_formatter Formatter; + Formatter formatter((basic_format_args())); const Char format_str[] = {'}', 0}; const Char *format = format_str; - c.format(&formatter.writer(), c.value, &formatter, &format); + c.format(&this->writer(), c.value, &formatter, &format); } }; @@ -290,8 +290,6 @@ class PrintfFormatter : typedef Char char_type; private: - BasicWriter &writer_; - typedef internal::FormatterBase Base; void parse_flags(FormatSpec &spec, const Char *&s); @@ -313,14 +311,12 @@ class PrintfFormatter : appropriate lifetimes. \endrst */ - explicit PrintfFormatter(basic_format_args args, - BasicWriter &w) - : Base(args), writer_(w) {} - - BasicWriter &writer() { return writer_; } + explicit PrintfFormatter(basic_format_args args) + : Base(args) {} /** Formats stored arguments and writes the output to the writer. */ - FMT_API void format(BasicCStringRef format_str); + FMT_API void format(BasicWriter &writer, + BasicCStringRef format_str); }; template @@ -396,18 +392,19 @@ unsigned PrintfFormatter::parse_header( } template -void PrintfFormatter::format(BasicCStringRef format_str) { +void PrintfFormatter::format(BasicWriter &writer, + BasicCStringRef format_str) { const Char *start = format_str.c_str(); const Char *s = start; while (*s) { Char c = *s++; if (c != '%') continue; if (*s == c) { - this->write(writer_, start, s); + internal::write(writer, start, s); start = ++s; continue; } - this->write(writer_, start, s - 1); + internal::write(writer, start, s - 1); FormatSpec spec; spec.align_ = ALIGN_RIGHT; @@ -490,9 +487,9 @@ void PrintfFormatter::format(BasicCStringRef format_str) { start = s; // Format argument. - AF(writer_, spec).visit(arg); + AF(writer, spec).visit(arg); } - this->write(writer_, start, s); + internal::write(writer, start, s); } // Formats a value. @@ -500,13 +497,13 @@ template void format_value(BasicWriter &w, const T &value, PrintfFormatter &f, const Char *&) { internal::MemoryBuffer buffer; - f.writer() << internal::format_value(buffer, value); + w << internal::format_value(buffer, value); } template void printf(BasicWriter &w, BasicCStringRef format, basic_format_args> args) { - PrintfFormatter(args, w).format(format); + PrintfFormatter(args).format(w, format); } inline std::string vsprintf(CStringRef format, diff --git a/test/custom-formatter-test.cc b/test/custom-formatter-test.cc index 53227a3c..499e07a2 100644 --- a/test/custom-formatter-test.cc +++ b/test/custom-formatter-test.cc @@ -17,9 +17,10 @@ using fmt::BasicPrintfArgFormatter; class CustomArgFormatter : public fmt::BasicArgFormatter { public: - CustomArgFormatter(fmt::basic_formatter &f, + CustomArgFormatter(fmt::Writer &w, + fmt::basic_formatter &f, fmt::FormatSpec &s, const char *fmt) - : fmt::BasicArgFormatter(f, s, fmt) {} + : fmt::BasicArgFormatter(w, f, s, fmt) {} void visit_double(double value) { if (round(value * pow(10, spec().precision())) == 0) @@ -47,12 +48,11 @@ class CustomPrintfArgFormatter : typedef fmt::basic_formatter CustomFormatter; -std::string custom_vformat(const char *format_str, +std::string custom_vformat(fmt::CStringRef format_str, fmt::basic_format_args args) { fmt::MemoryWriter writer; - // Pass custom argument formatter as a template arg to basic_formatter. - CustomFormatter formatter(args, writer); - formatter.format(format_str); + // Pass custom argument formatter as a template arg to vformat. + fmt::vformat(writer, format_str, args); return writer.str(); } @@ -69,8 +69,8 @@ std::string custom_vsprintf( const char* format_str, fmt::basic_format_args args) { fmt::MemoryWriter writer; - CustomPrintfFormatter formatter(args, writer); - formatter.format(format_str); + CustomPrintfFormatter formatter(args); + formatter.format(writer, format_str); return writer.str(); } diff --git a/test/format-test.cc b/test/format-test.cc index 2d4d10aa..4493d003 100644 --- a/test/format-test.cc +++ b/test/format-test.cc @@ -1357,7 +1357,7 @@ TEST(FormatterTest, FormatCStringRef) { void format_value(fmt::Writer &w, const Date &d, fmt::basic_formatter &f, const char *) { - f.writer() << d.year() << '-' << d.month() << '-' << d.day(); + w << d.year() << '-' << d.month() << '-' << d.day(); } TEST(FormatterTest, FormatCustom) { @@ -1371,7 +1371,7 @@ class Answer {}; template void format_value(BasicWriter &w, Answer, fmt::basic_formatter &f, const Char *) { - f.writer() << "42"; + w << "42"; } TEST(FormatterTest, CustomFormat) { @@ -1626,9 +1626,10 @@ class MockArgFormatter : public: typedef fmt::internal::ArgFormatterBase Base; - MockArgFormatter(fmt::basic_formatter &f, + MockArgFormatter(fmt::Writer &w, + fmt::basic_formatter &f, fmt::FormatSpec &s, const char *) - : fmt::internal::ArgFormatterBase(f.writer(), s) { + : fmt::internal::ArgFormatterBase(w, s) { EXPECT_CALL(*this, visit_int(42)); } @@ -1637,11 +1638,10 @@ class MockArgFormatter : typedef fmt::basic_formatter CustomFormatter; -void custom_vformat(const char *format_str, +void custom_vformat(fmt::CStringRef format_str, fmt::basic_format_args args) { fmt::MemoryWriter writer; - CustomFormatter formatter(args, writer); - formatter.format(format_str); + vformat(writer, format_str, args); } template diff --git a/test/ostream-test.cc b/test/ostream-test.cc index 224540b1..17c9d079 100644 --- a/test/ostream-test.cc +++ b/test/ostream-test.cc @@ -59,17 +59,18 @@ TEST(OStreamTest, Enum) { } struct TestArgFormatter : fmt::BasicArgFormatter { - TestArgFormatter(fmt::basic_formatter &f, + TestArgFormatter(fmt::Writer &w, + fmt::basic_formatter &f, fmt::FormatSpec &s, const char *fmt) - : fmt::BasicArgFormatter(f, s, fmt) {} + : fmt::BasicArgFormatter(w, f, s, fmt) {} }; TEST(OStreamTest, CustomArg) { fmt::MemoryWriter writer; typedef fmt::basic_formatter Formatter; - Formatter formatter(fmt::basic_format_args(), writer); + Formatter formatter((fmt::basic_format_args())); fmt::FormatSpec spec; - TestArgFormatter af(formatter, spec, "}"); + TestArgFormatter af(writer, formatter, spec, "}"); af.visit(fmt::internal::MakeArg(TestEnum())); EXPECT_EQ("TestEnum", writer.str()); } diff --git a/test/util-test.cc b/test/util-test.cc index 33603340..87ad25e7 100644 --- a/test/util-test.cc +++ b/test/util-test.cc @@ -567,9 +567,9 @@ TEST(ArgTest, MakeArg) { EXPECT_EQ(fmt::internal::Arg::CUSTOM, arg.type); EXPECT_EQ(&t, arg.custom.value); fmt::MemoryWriter w; - fmt::basic_formatter formatter(fmt::format_args(), w); + fmt::basic_formatter formatter((fmt::format_args())); const char *s = "}"; - arg.custom.format(&formatter.writer(), &formatter, &t, &s); + arg.custom.format(&w, &formatter, &t, &s); EXPECT_EQ("test", w.str()); } From 9998f66f8c00e348dd007d5b50baf3bf144a1c86 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sun, 6 Nov 2016 16:11:24 -0800 Subject: [PATCH 036/340] Replace formatter with context --- fmt/format.cc | 7 +- fmt/format.h | 282 +++++++++++++++++----------------- fmt/ostream.h | 11 +- fmt/posix.h | 2 +- fmt/printf.h | 69 ++++----- fmt/time.h | 16 +- test/custom-formatter-test.cc | 20 +-- test/format-test.cc | 22 +-- test/ostream-test.cc | 14 +- test/util-test.cc | 22 ++- 10 files changed, 223 insertions(+), 242 deletions(-) diff --git a/fmt/format.cc b/fmt/format.cc index 55ece67c..5ec8e41b 100644 --- a/fmt/format.cc +++ b/fmt/format.cc @@ -446,7 +446,7 @@ void printf(BasicWriter &w, BasicCStringRef format, format_args args); FMT_FUNC int vfprintf(std::FILE *f, CStringRef format, - basic_format_args> args) { + basic_format_args> args) { MemoryWriter w; printf(w, format, args); std::size_t size = w.size(); @@ -463,7 +463,7 @@ template void internal::FixedBuffer::grow(std::size_t); template void internal::ArgMap::init(const format_args &args); -template void PrintfFormatter::format(Writer &writer, CStringRef format); +template void printf_context::format(Writer &writer); template int internal::CharTraits::format_float( char *buffer, std::size_t size, const char *format, @@ -479,8 +479,7 @@ template void internal::FixedBuffer::grow(std::size_t); template void internal::ArgMap::init(const format_args &args); -template void PrintfFormatter::format(WWriter &writer, - WCStringRef format); +template void printf_context::format(WWriter &writer); template int internal::CharTraits::format_float( wchar_t *buffer, std::size_t size, const wchar_t *format, diff --git a/fmt/format.h b/fmt/format.h index 9d9359bc..303091fa 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -377,8 +377,11 @@ class ArgFormatter; template class BasicPrintfArgFormatter; -template > -class basic_formatter; +template +class basic_format_context; + +typedef basic_format_context format_context; +typedef basic_format_context wformat_context; /** \rst @@ -993,7 +996,7 @@ struct Value { }; typedef void (*FormatFunc)( - void *writer, const void *arg, void *formatter, void *format_str_ptr); + void *writer, const void *arg, void *ctx); struct CustomValue { const void *value; @@ -1230,10 +1233,10 @@ template constexpr Type type() { return gettype::type>(); } // Makes an Arg object from any type. -template +template class MakeValue : public Arg { public: - typedef typename Formatter::char_type Char; + typedef typename Context::char_type Char; private: // The following two methods are private to disallow formatting of @@ -1271,12 +1274,10 @@ class MakeValue : public Arg { // Formats an argument of a custom type, such as a user-defined class. template static void format_custom_arg( - void *writer, const void *arg, void *formatter, void *format_str_ptr) { - typedef BasicWriter Writer; - format_value(*static_cast(writer), + void *writer, const void *arg, void *context) { + format_value(*static_cast*>(writer), *static_cast(arg), - *static_cast(formatter), - *static_cast(format_str_ptr)); + *static_cast(context)); } public: @@ -1406,7 +1407,7 @@ struct NamedArg : Arg { template NamedArg(BasicStringRef argname, const T &value) - : Arg(MakeArg< basic_formatter >(value)), name(argname) {} + : Arg(MakeArg< basic_format_context >(value)), name(argname) {} }; class RuntimeError : public std::runtime_error { @@ -1430,7 +1431,7 @@ constexpr uint64_t make_type() { return 0; } enum { MAX_PACKED_ARGS = 16 }; } // namespace internal -template +template class format_arg_store { private: static const size_t NUM_ARGS = sizeof...(Args); @@ -1443,26 +1444,25 @@ class format_arg_store { std::array data_; template - friend format_arg_store make_format_args(const A & ... args); + friend format_arg_store make_format_args(const A & ... args); public: static const uint64_t TYPES = internal::make_type(); - format_arg_store(const Args &... args, Formatter *) - : data_{{internal::MakeValue(args)...}} {} + format_arg_store(const Args &... args) + : data_{{internal::MakeValue(args)...}} {} const value_type *data() const { return data_.data(); } }; -template -inline format_arg_store +template +inline format_arg_store make_format_args(const Args & ... args) { - Formatter *f = nullptr; - return format_arg_store(args..., f); + return format_arg_store(args...); } /** Formatting arguments. */ -template +template class basic_format_args { private: // To reduce compiled code size per formatting function call, types of first @@ -1496,7 +1496,7 @@ class basic_format_args { basic_format_args() : types_(0) {} template - basic_format_args(const format_arg_store &store) + basic_format_args(const format_arg_store &store) : types_(store.TYPES) { set_data(store.data()); } @@ -1527,8 +1527,8 @@ class basic_format_args { } }; -typedef basic_format_args> format_args; -typedef basic_format_args> wformat_args; +typedef basic_format_args> format_args; +typedef basic_format_args> wformat_args; #define FMT_DISPATCH(call) static_cast(this)->call @@ -2014,6 +2014,8 @@ class ArgFormatterBase : public ArgVisitor { } public: + typedef Char char_type; + ArgFormatterBase(BasicWriter &w, FormatSpec &s) : writer_(w), spec_(s) {} @@ -2082,21 +2084,35 @@ class ArgFormatterBase : public ArgVisitor { } }; -template -class FormatterBase { -private: - basic_format_args args_; +template +inline void write(BasicWriter &w, const Char *start, const Char *end) { + if (start != end) + w << BasicStringRef(start, internal::to_unsigned(end - start)); +} + +template +class format_context_base { + private: + const Char *ptr_; + basic_format_args args_; int next_arg_index_; + protected: + format_context_base(const Char *format_str, basic_format_args args) + : ptr_(format_str), args_(args), next_arg_index_(0) {} + ~format_context_base() {} + + basic_format_args args() const { return args_; } + // Returns the argument with specified index. - Arg do_get_arg(unsigned arg_index, const char *&error) { - Arg arg = args_[arg_index]; + format_arg do_get_arg(unsigned arg_index, const char *&error) { + format_arg arg = args_[arg_index]; switch (arg.type) { - case Arg::NONE: + case format_arg::NONE: error = "argument index out of range"; break; - case Arg::NAMED_ARG: - arg = *static_cast(arg.pointer); + case format_arg::NAMED_ARG: + arg = *static_cast(arg.pointer); break; default: /*nothing*/; @@ -2104,24 +2120,19 @@ private: return arg; } - protected: - FormatterBase(basic_format_args args) - : args_(args), next_arg_index_(0) {} - - const basic_format_args &args() const { return args_; } - - // Returns the next argument. - Arg next_arg(const char *&error) { - if (next_arg_index_ >= 0) - return do_get_arg(internal::to_unsigned(next_arg_index_++), error); - error = "cannot switch from manual to automatic argument indexing"; - return Arg(); - } - // Checks if manual indexing is used and returns the argument with // specified index. - Arg get_arg(unsigned arg_index, const char *&error) { - return check_no_auto_index(error) ? do_get_arg(arg_index, error) : Arg(); + format_arg get_arg(unsigned arg_index, const char *&error) { + return this->check_no_auto_index(error) ? + this->do_get_arg(arg_index, error) : format_arg(); + } + + // Returns the next argument. + format_arg next_arg(const char *&error) { + if (next_arg_index_ >= 0) + return this->do_get_arg(internal::to_unsigned(next_arg_index_++), error); + error = "cannot switch from manual to automatic argument indexing"; + return format_arg(); } bool check_no_auto_index(const char *&error) { @@ -2132,13 +2143,11 @@ private: next_arg_index_ = -1; return true; } -}; -template -inline void write(BasicWriter &w, const Char *start, const Char *end) { - if (start != end) - w << BasicStringRef(start, internal::to_unsigned(end - start)); -} + public: + // Returns a pointer to the current position in the format string. + const Char *&ptr() { return ptr_; } +}; } // namespace internal /** @@ -2161,8 +2170,7 @@ inline void write(BasicWriter &w, const Char *start, const Char *end) { template class BasicArgFormatter : public internal::ArgFormatterBase { private: - basic_formatter &formatter_; - const Char *format_; + basic_format_context &ctx_; public: /** @@ -2173,15 +2181,13 @@ class BasicArgFormatter : public internal::ArgFormatterBase { to the part of the format string being parsed for custom argument types. \endrst */ - BasicArgFormatter(BasicWriter &writer, - basic_formatter &formatter, - FormatSpec &spec, const Char *fmt) - : internal::ArgFormatterBase(writer, spec), - formatter_(formatter), format_(fmt) {} + BasicArgFormatter(BasicWriter &writer, basic_format_context &ctx, + FormatSpec &spec) + : internal::ArgFormatterBase(writer, spec), ctx_(ctx) {} /** Formats an argument of a custom (user-defined) type. */ void visit_custom(internal::Arg::CustomValue c) { - c.format(&this->writer(), c.value, &formatter_, &format_); + c.format(&this->writer(), c.value, &ctx_); } }; @@ -2190,49 +2196,45 @@ template class ArgFormatter : public BasicArgFormatter, Char> { public: /** Constructs an argument formatter object. */ - ArgFormatter(BasicWriter &writer, basic_formatter &formatter, - FormatSpec &spec, const Char *fmt) - : BasicArgFormatter, Char>(writer, formatter, spec, fmt) {} + ArgFormatter(BasicWriter &writer, basic_format_context &ctx, + FormatSpec &spec) + : BasicArgFormatter, Char>(writer, ctx, spec) {} }; -/** This template formats data and writes the output to a writer. */ -template -class basic_formatter : - private internal::FormatterBase> { - public: - /** The character type for the output. */ - typedef Char char_type; - +template +class basic_format_context : + public internal::format_context_base> { private: internal::ArgMap map_; - FMT_DISALLOW_COPY_AND_ASSIGN(basic_formatter); + FMT_DISALLOW_COPY_AND_ASSIGN(basic_format_context); + + typedef internal::format_context_base Base; - typedef internal::FormatterBase Base; using Base::get_arg; // Checks if manual indexing is used and returns the argument with // specified name. - internal::Arg get_arg(BasicStringRef arg_name, const char *&error); + format_arg get_arg(BasicStringRef name, const char *&error); public: + /** The character type for the output. */ + typedef Char char_type; + /** \rst - Constructs a ``basic_formatter`` object. References to the arguments are - stored in the formatter object so make sure they have appropriate lifetimes. + Constructs a ``basic_format_context`` object. References to the arguments are + stored in the object so make sure they have appropriate lifetimes. \endrst */ - basic_formatter(basic_format_args args) : Base(args) {} + basic_format_context(const Char *format_str, + basic_format_args args) + : Base(format_str, args) {} - // Parses argument index and returns corresponding argument. - internal::Arg parse_arg_index(const Char *&s); - - // Parses argument name and returns corresponding argument. - internal::Arg parse_arg_name(const Char *&s); + // Parses argument id and returns corresponding argument. + format_arg parse_arg_id(); - // Formats a single argument and advances format_str, a format string pointer. - const Char *format(BasicWriter &writer, const Char *&format_str, - const internal::Arg &arg); + using Base::ptr; }; /** @@ -2269,7 +2271,7 @@ class SystemError : public internal::RuntimeError { */ template SystemError(int error_code, CStringRef message, const Args & ... args) { - init(error_code, message, make_format_args>(args...)); + init(error_code, message, make_format_args(args...)); } ~SystemError() throw(); @@ -2464,10 +2466,7 @@ class BasicWriter { } void vwrite(BasicCStringRef format, - basic_format_args> args) { - vformat(*this, format, args); - } - + basic_format_args> args); /** \rst Writes formatted data. @@ -2495,7 +2494,7 @@ class BasicWriter { */ template void write(BasicCStringRef format, const Args & ... args) { - vwrite(format, make_format_args>(args...)); + vwrite(format, make_format_args>(args...)); } BasicWriter &operator<<(int value) { @@ -3123,7 +3122,7 @@ class WindowsError : public SystemError { */ template WindowsError(int error_code, CStringRef message, const Args & ... args) { - init(error_code, message, make_format_args>(args...)); + init(error_code, message, make_format_args(args...)); } }; @@ -3147,8 +3146,7 @@ FMT_API void vprint_colored(Color c, CStringRef format, format_args args); template inline void print_colored(Color c, CStringRef format_str, const Args & ... args) { - vprint_colored(c, format_str, - make_format_args>(args...)); + vprint_colored(c, format_str, make_format_args(args...)); } inline std::string vformat(CStringRef format_str, format_args args) { @@ -3168,7 +3166,7 @@ inline std::string vformat(CStringRef format_str, format_args args) { */ template inline std::string format(CStringRef format_str, const Args & ... args) { - return vformat(format_str, make_format_args>(args...)); + return vformat(format_str, make_format_args(args...)); } inline std::wstring vformat(WCStringRef format_str, wformat_args args) { @@ -3179,7 +3177,7 @@ inline std::wstring vformat(WCStringRef format_str, wformat_args args) { template inline std::wstring format(WCStringRef format_str, const Args & ... args) { - auto vargs = make_format_args>(args...); + auto vargs = make_format_args(args...); return vformat(format_str, vargs); } @@ -3196,7 +3194,7 @@ FMT_API void vprint(std::FILE *f, CStringRef format_str, format_args args); */ template inline void print(std::FILE *f, CStringRef format_str, const Args & ... args) { - vprint(f, format_str, make_format_args>(args...)); + vprint(f, format_str, make_format_args(args...)); } FMT_API void vprint(CStringRef format_str, format_args args); @@ -3212,7 +3210,7 @@ FMT_API void vprint(CStringRef format_str, format_args args); */ template inline void print(CStringRef format_str, const Args & ... args) { - vprint(format_str, make_format_args>(args...)); + vprint(format_str, make_format_args(args...)); } /** @@ -3405,57 +3403,55 @@ void check_sign(const Char *&s, const Arg &arg) { } } // namespace internal -template -inline internal::Arg basic_formatter::get_arg( - BasicStringRef arg_name, const char *&error) { +template +inline format_arg basic_format_context::get_arg( + BasicStringRef name, const char *&error) { if (this->check_no_auto_index(error)) { map_.init(this->args()); - const internal::Arg *arg = map_.find(arg_name); + const internal::Arg *arg = map_.find(name); if (arg) return *arg; error = "argument not found"; } - return internal::Arg(); + return format_arg(); } -template -inline internal::Arg basic_formatter::parse_arg_index( - const Char *&s) { - const char *error = 0; - internal::Arg arg = *s < '0' || *s > '9' ? - this->next_arg(error) : get_arg(internal::parse_nonnegative_int(s), error); - if (error) { - FMT_THROW(format_error( - *s != '}' && *s != ':' ? "invalid format string" : error)); +template +inline format_arg basic_format_context::parse_arg_id() { + const Char *&s = this->ptr(); + if (!internal::is_name_start(*s)) { + const char *error = 0; + format_arg arg = *s < '0' || *s > '9' ? + this->next_arg(error) : get_arg(internal::parse_nonnegative_int(s), error); + if (error) { + FMT_THROW(format_error( + *s != '}' && *s != ':' ? "invalid format string" : error)); + } + return arg; } - return arg; -} - -template -inline internal::Arg basic_formatter::parse_arg_name(const Char *&s) { - assert(internal::is_name_start(*s)); const Char *start = s; Char c; do { c = *++s; } while (internal::is_name_start(c) || ('0' <= c && c <= '9')); const char *error = 0; - internal::Arg arg = get_arg(BasicStringRef(start, s - start), error); + format_arg arg = get_arg(BasicStringRef(start, s - start), error); if (error) FMT_THROW(format_error(error)); return arg; } -template -const Char *basic_formatter::format( - BasicWriter &writer, const Char *&format_str, const internal::Arg &arg) { +// Formats a single argument. +template +void format_arg(BasicWriter &writer, const internal::Arg &arg, + Context &ctx) { using internal::Arg; - const Char *s = format_str; + const Char *&s = ctx.ptr(); FormatSpec spec; if (*s == ':') { if (arg.type == Arg::CUSTOM) { - arg.custom.format(&writer, arg.custom.value, this, &s); - return s; + arg.custom.format(&writer, arg.custom.value, &ctx); + return; } ++s; // Parse fill and alignment. @@ -3527,8 +3523,7 @@ const Char *basic_formatter::format( spec.width_ = internal::parse_nonnegative_int(s); } else if (*s == '{') { ++s; - Arg width_arg = internal::is_name_start(*s) ? - parse_arg_name(s) : parse_arg_index(s); + Arg width_arg = ctx.parse_arg_id(); if (*s++ != '}') FMT_THROW(format_error("invalid format string")); ULongLong value = 0; @@ -3565,8 +3560,7 @@ const Char *basic_formatter::format( spec.precision_ = internal::parse_nonnegative_int(s); } else if (*s == '{') { ++s; - Arg precision_arg = internal::is_name_start(*s) ? - parse_arg_name(s) : parse_arg_index(s); + Arg precision_arg = ctx.parse_arg_id(); if (*s++ != '}') FMT_THROW(format_error("invalid format string")); ULongLong value = 0; @@ -3608,20 +3602,19 @@ const Char *basic_formatter::format( spec.type_ = static_cast(*s++); } - if (*s++ != '}') + if (*s != '}') FMT_THROW(format_error("missing '}' in format string")); // Format argument. - ArgFormatter(writer, *this, spec, s - 1).visit(arg); - return s; + ArgFormatter(writer, ctx, spec).visit(arg); } /** Formats arguments and writes the output to the writer. */ -template +template void vformat(BasicWriter &writer, BasicCStringRef format_str, - basic_format_args> args) { - basic_formatter formatter(args); - const Char *s = format_str.c_str(); + basic_format_args args) { + basic_format_context ctx(format_str.c_str(), args); + const Char *&s = ctx.ptr(); const Char *start = s; while (*s) { Char c = *s++; @@ -3634,12 +3627,19 @@ void vformat(BasicWriter &writer, BasicCStringRef format_str, if (c == '}') FMT_THROW(format_error("unmatched '}' in format string")); internal::write(writer, start, s - 1); - internal::Arg arg = internal::is_name_start(*s) ? - formatter.parse_arg_name(s) : formatter.parse_arg_index(s); - start = s = formatter.format(writer, s, arg); + format_arg(writer, ctx.parse_arg_id(), ctx); + assert(*s == '}'); + start = ++s; } internal::write(writer, start, s); } + +template +inline void BasicWriter::vwrite( + BasicCStringRef format, + basic_format_args> args) { + vformat>(*this, format, args); +} } // namespace fmt #if FMT_USE_USER_DEFINED_LITERALS diff --git a/fmt/ostream.h b/fmt/ostream.h index 6173e688..feafc3b4 100644 --- a/fmt/ostream.h +++ b/fmt/ostream.h @@ -82,14 +82,13 @@ BasicStringRef format_value( } // namespace internal // Formats a value. -template +template void format_value(BasicWriter &w, const T &value, - basic_formatter &f, - const Char *&format_str) { + basic_format_context &ctx) { internal::MemoryBuffer buffer; auto str = internal::format_value(buffer, value); - typedef internal::MakeArg< basic_formatter > MakeArg; - format_str = f.format(w, format_str, MakeArg(str)); + typedef internal::MakeArg< basic_format_context > MakeArg; + format_arg< ArgFormatter >(w, MakeArg(str), ctx); } FMT_API void vprint(std::ostream &os, CStringRef format_str, format_args args); @@ -106,7 +105,7 @@ FMT_API void vprint(std::ostream &os, CStringRef format_str, format_args args); template inline void print(std::ostream &os, CStringRef format_str, const Args & ... args) { - vprint(os, format_str, make_format_args>(args...)); + vprint(os, format_str, make_format_args(args...)); } } // namespace fmt diff --git a/fmt/posix.h b/fmt/posix.h index 5fd17859..c6c6c13a 100644 --- a/fmt/posix.h +++ b/fmt/posix.h @@ -172,7 +172,7 @@ public: template inline void print(CStringRef format_str, const Args & ... args) { - vprint(format_str, make_format_args>(args...)); + vprint(format_str, make_format_args(args...)); } }; diff --git a/fmt/printf.h b/fmt/printf.h index 7d171255..42728b78 100644 --- a/fmt/printf.h +++ b/fmt/printf.h @@ -262,11 +262,10 @@ class BasicPrintfArgFormatter : public internal::ArgFormatterBase { /** Formats an argument of a custom (user-defined) type. */ void visit_custom(internal::Arg::CustomValue c) { - typedef basic_formatter Formatter; - Formatter formatter((basic_format_args())); - const Char format_str[] = {'}', 0}; - const Char *format = format_str; - c.format(&this->writer(), c.value, &formatter, &format); + const Char format_str[] = {'}', '\0'}; + auto args = basic_format_args>(); + basic_format_context ctx(format_str, args); + c.format(&this->writer(), c.value, &ctx); } }; @@ -283,14 +282,15 @@ class PrintfArgFormatter /** This template formats data and writes the output to a writer. */ template > -class PrintfFormatter : - private internal::FormatterBase> { +class printf_context : + private internal::format_context_base< + Char, printf_context> { public: /** The character type for the output. */ typedef Char char_type; private: - typedef internal::FormatterBase Base; + typedef internal::format_context_base Base; void parse_flags(FormatSpec &spec, const Char *&s); @@ -306,21 +306,21 @@ class PrintfFormatter : public: /** \rst - Constructs a ``PrintfFormatter`` object. References to the arguments and - the writer are stored in the formatter object so make sure they have + Constructs a ``printf_context`` object. References to the arguments and + the writer are stored in the context object so make sure they have appropriate lifetimes. \endrst */ - explicit PrintfFormatter(basic_format_args args) - : Base(args) {} - + explicit printf_context(BasicCStringRef format_str, + basic_format_args args) + : Base(format_str.c_str(), args) {} + /** Formats stored arguments and writes the output to the writer. */ - FMT_API void format(BasicWriter &writer, - BasicCStringRef format_str); + FMT_API void format(BasicWriter &writer); }; template -void PrintfFormatter::parse_flags(FormatSpec &spec, const Char *&s) { +void printf_context::parse_flags(FormatSpec &spec, const Char *&s) { for (;;) { switch (*s++) { case '-': @@ -346,8 +346,8 @@ void PrintfFormatter::parse_flags(FormatSpec &spec, const Char *&s) { } template -internal::Arg PrintfFormatter::get_arg(const Char *s, - unsigned arg_index) { +internal::Arg printf_context::get_arg(const Char *s, + unsigned arg_index) { (void)s; const char *error = 0; internal::Arg arg = arg_index == std::numeric_limits::max() ? @@ -358,7 +358,7 @@ internal::Arg PrintfFormatter::get_arg(const Char *s, } template -unsigned PrintfFormatter::parse_header( +unsigned printf_context::parse_header( const Char *&s, FormatSpec &spec) { unsigned arg_index = std::numeric_limits::max(); Char c = *s; @@ -392,9 +392,8 @@ unsigned PrintfFormatter::parse_header( } template -void PrintfFormatter::format(BasicWriter &writer, - BasicCStringRef format_str) { - const Char *start = format_str.c_str(); +void printf_context::format(BasicWriter &writer) { + const Char *start = this->ptr(); const Char *s = start; while (*s) { Char c = *s++; @@ -495,19 +494,19 @@ void PrintfFormatter::format(BasicWriter &writer, // Formats a value. template void format_value(BasicWriter &w, const T &value, - PrintfFormatter &f, const Char *&) { + printf_context& ctx) { internal::MemoryBuffer buffer; w << internal::format_value(buffer, value); } template void printf(BasicWriter &w, BasicCStringRef format, - basic_format_args> args) { - PrintfFormatter(args).format(w, format); + basic_format_args> args) { + printf_context(format, args).format(w); } inline std::string vsprintf(CStringRef format, - basic_format_args> args) { + basic_format_args> args) { MemoryWriter w; printf(w, format, args); return w.str(); @@ -524,11 +523,11 @@ inline std::string vsprintf(CStringRef format, */ template inline std::string sprintf(CStringRef format_str, const Args & ... args) { - return vsprintf(format_str, make_format_args>(args...)); + return vsprintf(format_str, make_format_args>(args...)); } inline std::wstring vsprintf(WCStringRef format, - basic_format_args> args) { + basic_format_args> args) { WMemoryWriter w; printf(w, format, args); return w.str(); @@ -536,12 +535,12 @@ inline std::wstring vsprintf(WCStringRef format, template inline std::wstring sprintf(WCStringRef format_str, const Args & ... args) { - auto vargs = make_format_args>(args...); + auto vargs = make_format_args>(args...); return vsprintf(format_str, vargs); } FMT_API int vfprintf(std::FILE *f, CStringRef format, - basic_format_args> args); + basic_format_args> args); /** \rst @@ -554,12 +553,12 @@ FMT_API int vfprintf(std::FILE *f, CStringRef format, */ template inline int fprintf(std::FILE *f, CStringRef format_str, const Args & ... args) { - auto vargs = make_format_args>(args...); + auto vargs = make_format_args>(args...); return vfprintf(f, format_str, vargs); } inline int vprintf(CStringRef format, - basic_format_args> args) { + basic_format_args> args) { return vfprintf(stdout, format, args); } @@ -574,11 +573,11 @@ inline int vprintf(CStringRef format, */ template inline int printf(CStringRef format_str, const Args & ... args) { - return vprintf(format_str, make_format_args>(args...)); + return vprintf(format_str, make_format_args>(args...)); } inline int vfprintf(std::ostream &os, CStringRef format_str, - basic_format_args> args) { + basic_format_args> args) { MemoryWriter w; printf(w, format_str, args); internal::write(os, w); @@ -597,7 +596,7 @@ inline int vfprintf(std::ostream &os, CStringRef format_str, template inline int fprintf(std::ostream &os, CStringRef format_str, const Args & ... args) { - auto vargs = make_format_args>(args...); + auto vargs = make_format_args>(args...); return vfprintf(os, format_str, vargs); } } // namespace fmt diff --git a/fmt/time.h b/fmt/time.h index 5b40a93f..ad7ab9cf 100644 --- a/fmt/time.h +++ b/fmt/time.h @@ -15,19 +15,17 @@ namespace fmt { -template -void format_value(Writer &w, const std::tm &tm, - basic_formatter &f, - const char *&format_str) { - if (*format_str == ':') - ++format_str; - const char *end = format_str; +void format_value(Writer &w, const std::tm &tm, format_context &ctx) { + const char *&s = ctx.ptr(); + if (*s == ':') + ++s; + const char *end = s; while (*end && *end != '}') ++end; if (*end != '}') FMT_THROW(format_error("missing '}' in format string")); internal::MemoryBuffer format; - format.append(format_str, end + 1); + format.append(s, end + 1); format[format.size() - 1] = '\0'; Buffer &buffer = w.buffer(); std::size_t start = buffer.size(); @@ -48,7 +46,7 @@ void format_value(Writer &w, const std::tm &tm, const std::size_t MIN_GROWTH = 10; buffer.reserve(buffer.capacity() + (size > MIN_GROWTH ? size : MIN_GROWTH)); } - format_str = end + 1; + s = end; } } diff --git a/test/custom-formatter-test.cc b/test/custom-formatter-test.cc index 499e07a2..65888b28 100644 --- a/test/custom-formatter-test.cc +++ b/test/custom-formatter-test.cc @@ -17,10 +17,9 @@ using fmt::BasicPrintfArgFormatter; class CustomArgFormatter : public fmt::BasicArgFormatter { public: - CustomArgFormatter(fmt::Writer &w, - fmt::basic_formatter &f, - fmt::FormatSpec &s, const char *fmt) - : fmt::BasicArgFormatter(w, f, s, fmt) {} + CustomArgFormatter(fmt::Writer &w, fmt::basic_format_context &ctx, + fmt::FormatSpec &s) + : fmt::BasicArgFormatter(w, ctx, s) {} void visit_double(double value) { if (round(value * pow(10, spec().precision())) == 0) @@ -46,10 +45,7 @@ class CustomPrintfArgFormatter : } }; -typedef fmt::basic_formatter CustomFormatter; - -std::string custom_vformat(fmt::CStringRef format_str, - fmt::basic_format_args args) { +std::string custom_vformat(fmt::CStringRef format_str, fmt::format_args args) { fmt::MemoryWriter writer; // Pass custom argument formatter as a template arg to vformat. fmt::vformat(writer, format_str, args); @@ -58,19 +54,19 @@ std::string custom_vformat(fmt::CStringRef format_str, template std::string custom_format(const char *format_str, const Args & ... args) { - auto va = fmt::make_format_args(args...); + auto va = fmt::make_format_args(args...); return custom_vformat(format_str, va); } -typedef fmt::PrintfFormatter +typedef fmt::printf_context CustomPrintfFormatter; std::string custom_vsprintf( const char* format_str, fmt::basic_format_args args) { fmt::MemoryWriter writer; - CustomPrintfFormatter formatter(args); - formatter.format(writer, format_str); + CustomPrintfFormatter formatter(format_str, args); + formatter.format(writer); return writer.str(); } diff --git a/test/format-test.cc b/test/format-test.cc index 4493d003..1e919b7e 100644 --- a/test/format-test.cc +++ b/test/format-test.cc @@ -1355,8 +1355,7 @@ TEST(FormatterTest, FormatCStringRef) { EXPECT_EQ("test", format("{0}", CStringRef("test"))); } -void format_value(fmt::Writer &w, const Date &d, fmt::basic_formatter &f, - const char *) { +void format_value(fmt::Writer &w, const Date &d, fmt::format_context &) { w << d.year() << '-' << d.month() << '-' << d.day(); } @@ -1369,8 +1368,7 @@ TEST(FormatterTest, FormatCustom) { class Answer {}; template -void format_value(BasicWriter &w, Answer, fmt::basic_formatter &f, - const Char *) { +void format_value(BasicWriter &w, Answer, fmt::format_context &) { w << "42"; } @@ -1561,7 +1559,7 @@ std::string vformat_message(int id, const char *format, fmt::format_args args) { template std::string format_message(int id, const char *format, const Args & ... args) { - auto va = fmt::make_format_args>(args...); + auto va = fmt::make_format_args(args...); return vformat_message(id, format, va); } @@ -1626,9 +1624,8 @@ class MockArgFormatter : public: typedef fmt::internal::ArgFormatterBase Base; - MockArgFormatter(fmt::Writer &w, - fmt::basic_formatter &f, - fmt::FormatSpec &s, const char *) + MockArgFormatter(fmt::Writer &w, fmt::format_context &ctx, + fmt::FormatSpec &s) : fmt::internal::ArgFormatterBase(w, s) { EXPECT_CALL(*this, visit_int(42)); } @@ -1636,17 +1633,14 @@ class MockArgFormatter : MOCK_METHOD1(visit_int, void (int value)); }; -typedef fmt::basic_formatter CustomFormatter; - -void custom_vformat(fmt::CStringRef format_str, - fmt::basic_format_args args) { +void custom_vformat(fmt::CStringRef format_str, fmt::format_args args) { fmt::MemoryWriter writer; - vformat(writer, format_str, args); + fmt::vformat(writer, format_str, args); } template void custom_format(const char *format_str, const Args & ... args) { - auto va = fmt::make_format_args(args...); + auto va = fmt::make_format_args(args...); return custom_vformat(format_str, va); } diff --git a/test/ostream-test.cc b/test/ostream-test.cc index 17c9d079..2d1ace63 100644 --- a/test/ostream-test.cc +++ b/test/ostream-test.cc @@ -59,19 +59,17 @@ TEST(OStreamTest, Enum) { } struct TestArgFormatter : fmt::BasicArgFormatter { - TestArgFormatter(fmt::Writer &w, - fmt::basic_formatter &f, - fmt::FormatSpec &s, const char *fmt) - : fmt::BasicArgFormatter(w, f, s, fmt) {} + TestArgFormatter(fmt::Writer &w, fmt::format_context &ctx, + fmt::FormatSpec &s) + : fmt::BasicArgFormatter(w, ctx, s) {} }; TEST(OStreamTest, CustomArg) { fmt::MemoryWriter writer; - typedef fmt::basic_formatter Formatter; - Formatter formatter((fmt::basic_format_args())); + fmt::format_context ctx("}", fmt::format_args()); fmt::FormatSpec spec; - TestArgFormatter af(writer, formatter, spec, "}"); - af.visit(fmt::internal::MakeArg(TestEnum())); + TestArgFormatter af(writer, ctx, spec); + af.visit(fmt::internal::MakeArg(TestEnum())); EXPECT_EQ("TestEnum", writer.str()); } diff --git a/test/util-test.cc b/test/util-test.cc index 87ad25e7..b553427c 100644 --- a/test/util-test.cc +++ b/test/util-test.cc @@ -65,13 +65,13 @@ struct Test {}; template void format_value(fmt::BasicWriter &w, Test, - fmt::basic_formatter &f, const Char *) { + fmt::basic_format_context &) { w << "test"; } template Arg make_arg(const T &value) { - typedef fmt::internal::MakeValue< fmt::basic_formatter > MakeValue; + typedef fmt::internal::MakeValue< fmt::basic_format_context > MakeValue; Arg arg = MakeValue(value); arg.type = fmt::internal::type(); return arg; @@ -567,9 +567,8 @@ TEST(ArgTest, MakeArg) { EXPECT_EQ(fmt::internal::Arg::CUSTOM, arg.type); EXPECT_EQ(&t, arg.custom.value); fmt::MemoryWriter w; - fmt::basic_formatter formatter((fmt::format_args())); - const char *s = "}"; - arg.custom.format(&w, &formatter, &t, &s); + fmt::format_context ctx("}", fmt::format_args()); + arg.custom.format(&w, &t, &ctx); EXPECT_EQ("test", w.str()); } @@ -580,21 +579,20 @@ TEST(UtilTest, FormatArgs) { struct CustomFormatter { typedef char char_type; + bool called; }; -void format_value(fmt::Writer &, const Test &, CustomFormatter &, - const char *&s) { - s = "custom_format"; +void format_value(fmt::Writer &, const Test &, CustomFormatter &ctx) { + ctx.called = true; } TEST(UtilTest, MakeValueWithCustomFormatter) { ::Test t; Arg arg = fmt::internal::MakeValue(t); - CustomFormatter formatter; - const char *s = ""; + CustomFormatter ctx = {false}; fmt::MemoryWriter w; - arg.custom.format(&w, &formatter, &t, &s); - EXPECT_STREQ("custom_format", s); + arg.custom.format(&w, &t, &ctx); + EXPECT_TRUE(ctx.called); } struct Result { From 85793a18cd5506d6f5d1ac6bacc7e60729b8f6db Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sun, 6 Nov 2016 19:27:14 -0800 Subject: [PATCH 037/340] Simplify API --- fmt/format.h | 27 +++++++++++++++------------ fmt/ostream.h | 2 +- fmt/posix.h | 2 +- fmt/printf.h | 10 +++++----- test/custom-formatter-test.cc | 4 ++-- test/format-test.cc | 4 ++-- 6 files changed, 26 insertions(+), 23 deletions(-) diff --git a/fmt/format.h b/fmt/format.h index 303091fa..fb3beb4c 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -1443,9 +1443,6 @@ class format_arg_store { // If the arguments are not packed, add one more element to mark the end. std::array data_; - template - friend format_arg_store make_format_args(const A & ... args); - public: static const uint64_t TYPES = internal::make_type(); @@ -1457,10 +1454,16 @@ class format_arg_store { template inline format_arg_store - make_format_args(const Args & ... args) { + make_xformat_args(const Args & ... args) { return format_arg_store(args...); } +template +inline format_arg_store + make_format_args(const Args & ... args) { + return format_arg_store(args...); +} + /** Formatting arguments. */ template class basic_format_args { @@ -2271,7 +2274,7 @@ class SystemError : public internal::RuntimeError { */ template SystemError(int error_code, CStringRef message, const Args & ... args) { - init(error_code, message, make_format_args(args...)); + init(error_code, message, make_format_args(args...)); } ~SystemError() throw(); @@ -2494,7 +2497,7 @@ class BasicWriter { */ template void write(BasicCStringRef format, const Args & ... args) { - vwrite(format, make_format_args>(args...)); + vwrite(format, make_xformat_args>(args...)); } BasicWriter &operator<<(int value) { @@ -3122,7 +3125,7 @@ class WindowsError : public SystemError { */ template WindowsError(int error_code, CStringRef message, const Args & ... args) { - init(error_code, message, make_format_args(args...)); + init(error_code, message, make_format_args(args...)); } }; @@ -3146,7 +3149,7 @@ FMT_API void vprint_colored(Color c, CStringRef format, format_args args); template inline void print_colored(Color c, CStringRef format_str, const Args & ... args) { - vprint_colored(c, format_str, make_format_args(args...)); + vprint_colored(c, format_str, make_format_args(args...)); } inline std::string vformat(CStringRef format_str, format_args args) { @@ -3166,7 +3169,7 @@ inline std::string vformat(CStringRef format_str, format_args args) { */ template inline std::string format(CStringRef format_str, const Args & ... args) { - return vformat(format_str, make_format_args(args...)); + return vformat(format_str, make_format_args(args...)); } inline std::wstring vformat(WCStringRef format_str, wformat_args args) { @@ -3177,7 +3180,7 @@ inline std::wstring vformat(WCStringRef format_str, wformat_args args) { template inline std::wstring format(WCStringRef format_str, const Args & ... args) { - auto vargs = make_format_args(args...); + auto vargs = make_xformat_args(args...); return vformat(format_str, vargs); } @@ -3194,7 +3197,7 @@ FMT_API void vprint(std::FILE *f, CStringRef format_str, format_args args); */ template inline void print(std::FILE *f, CStringRef format_str, const Args & ... args) { - vprint(f, format_str, make_format_args(args...)); + vprint(f, format_str, make_format_args(args...)); } FMT_API void vprint(CStringRef format_str, format_args args); @@ -3210,7 +3213,7 @@ FMT_API void vprint(CStringRef format_str, format_args args); */ template inline void print(CStringRef format_str, const Args & ... args) { - vprint(format_str, make_format_args(args...)); + vprint(format_str, make_format_args(args...)); } /** diff --git a/fmt/ostream.h b/fmt/ostream.h index feafc3b4..920d041f 100644 --- a/fmt/ostream.h +++ b/fmt/ostream.h @@ -105,7 +105,7 @@ FMT_API void vprint(std::ostream &os, CStringRef format_str, format_args args); template inline void print(std::ostream &os, CStringRef format_str, const Args & ... args) { - vprint(os, format_str, make_format_args(args...)); + vprint(os, format_str, make_format_args(args...)); } } // namespace fmt diff --git a/fmt/posix.h b/fmt/posix.h index c6c6c13a..4758a85b 100644 --- a/fmt/posix.h +++ b/fmt/posix.h @@ -172,7 +172,7 @@ public: template inline void print(CStringRef format_str, const Args & ... args) { - vprint(format_str, make_format_args(args...)); + vprint(format_str, make_format_args(args...)); } }; diff --git a/fmt/printf.h b/fmt/printf.h index 42728b78..85572c4e 100644 --- a/fmt/printf.h +++ b/fmt/printf.h @@ -523,7 +523,7 @@ inline std::string vsprintf(CStringRef format, */ template inline std::string sprintf(CStringRef format_str, const Args & ... args) { - return vsprintf(format_str, make_format_args>(args...)); + return vsprintf(format_str, make_xformat_args>(args...)); } inline std::wstring vsprintf(WCStringRef format, @@ -535,7 +535,7 @@ inline std::wstring vsprintf(WCStringRef format, template inline std::wstring sprintf(WCStringRef format_str, const Args & ... args) { - auto vargs = make_format_args>(args...); + auto vargs = make_xformat_args>(args...); return vsprintf(format_str, vargs); } @@ -553,7 +553,7 @@ FMT_API int vfprintf(std::FILE *f, CStringRef format, */ template inline int fprintf(std::FILE *f, CStringRef format_str, const Args & ... args) { - auto vargs = make_format_args>(args...); + auto vargs = make_xformat_args>(args...); return vfprintf(f, format_str, vargs); } @@ -573,7 +573,7 @@ inline int vprintf(CStringRef format, */ template inline int printf(CStringRef format_str, const Args & ... args) { - return vprintf(format_str, make_format_args>(args...)); + return vprintf(format_str, make_xformat_args>(args...)); } inline int vfprintf(std::ostream &os, CStringRef format_str, @@ -596,7 +596,7 @@ inline int vfprintf(std::ostream &os, CStringRef format_str, template inline int fprintf(std::ostream &os, CStringRef format_str, const Args & ... args) { - auto vargs = make_format_args>(args...); + auto vargs = make_xformat_args>(args...); return vfprintf(os, format_str, vargs); } } // namespace fmt diff --git a/test/custom-formatter-test.cc b/test/custom-formatter-test.cc index 65888b28..83648aba 100644 --- a/test/custom-formatter-test.cc +++ b/test/custom-formatter-test.cc @@ -54,7 +54,7 @@ std::string custom_vformat(fmt::CStringRef format_str, fmt::format_args args) { template std::string custom_format(const char *format_str, const Args & ... args) { - auto va = fmt::make_format_args(args...); + auto va = fmt::make_format_args(args...); return custom_vformat(format_str, va); } @@ -72,7 +72,7 @@ std::string custom_vsprintf( template std::string custom_sprintf(const char *format_str, const Args & ... args) { - auto va = fmt::make_format_args(args...); + auto va = fmt::make_xformat_args(args...); return custom_vsprintf(format_str, va); } diff --git a/test/format-test.cc b/test/format-test.cc index 1e919b7e..bb195a3c 100644 --- a/test/format-test.cc +++ b/test/format-test.cc @@ -1559,7 +1559,7 @@ std::string vformat_message(int id, const char *format, fmt::format_args args) { template std::string format_message(int id, const char *format, const Args & ... args) { - auto va = fmt::make_format_args(args...); + auto va = fmt::make_format_args(args...); return vformat_message(id, format, va); } @@ -1640,7 +1640,7 @@ void custom_vformat(fmt::CStringRef format_str, fmt::format_args args) { template void custom_format(const char *format_str, const Args & ... args) { - auto va = fmt::make_format_args(args...); + auto va = fmt::make_format_args(args...); return custom_vformat(format_str, va); } From 55a1ac503549805036c2375362cb28f3d5e1afcc Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Mon, 7 Nov 2016 08:55:40 -0800 Subject: [PATCH 038/340] Fix test --- fmt/format.h | 3 ++- test/format-test.cc | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/fmt/format.h b/fmt/format.h index fb3beb4c..0c038a53 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -3631,7 +3631,8 @@ void vformat(BasicWriter &writer, BasicCStringRef format_str, FMT_THROW(format_error("unmatched '}' in format string")); internal::write(writer, start, s - 1); format_arg(writer, ctx.parse_arg_id(), ctx); - assert(*s == '}'); + if (*s != '}') + FMT_THROW(format_error(fmt::format("unknown format specifier"))); start = ++s; } internal::write(writer, start, s); diff --git a/test/format-test.cc b/test/format-test.cc index bb195a3c..e7e72a1d 100644 --- a/test/format-test.cc +++ b/test/format-test.cc @@ -1362,7 +1362,7 @@ void format_value(fmt::Writer &w, const Date &d, fmt::format_context &) { TEST(FormatterTest, FormatCustom) { Date date(2012, 12, 9); EXPECT_THROW_MSG(fmt::format("{:s}", date), format_error, - "unmatched '}' in format string"); + "unknown format specifier"); } class Answer {}; From a1dd524b6fc0c5c0a3cce56609bcba9ec9cbc955 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Mon, 7 Nov 2016 18:22:21 -0800 Subject: [PATCH 039/340] format_arg -> do_format_arg --- fmt/format.h | 6 +++--- fmt/ostream.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/fmt/format.h b/fmt/format.h index 0c038a53..30d4c386 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -3446,8 +3446,8 @@ inline format_arg basic_format_context::parse_arg_id() { // Formats a single argument. template -void format_arg(BasicWriter &writer, const internal::Arg &arg, - Context &ctx) { +void do_format_arg(BasicWriter &writer, const internal::Arg &arg, + Context &ctx) { using internal::Arg; const Char *&s = ctx.ptr(); FormatSpec spec; @@ -3630,7 +3630,7 @@ void vformat(BasicWriter &writer, BasicCStringRef format_str, if (c == '}') FMT_THROW(format_error("unmatched '}' in format string")); internal::write(writer, start, s - 1); - format_arg(writer, ctx.parse_arg_id(), ctx); + do_format_arg(writer, ctx.parse_arg_id(), ctx); if (*s != '}') FMT_THROW(format_error(fmt::format("unknown format specifier"))); start = ++s; diff --git a/fmt/ostream.h b/fmt/ostream.h index 920d041f..c623b542 100644 --- a/fmt/ostream.h +++ b/fmt/ostream.h @@ -88,7 +88,7 @@ void format_value(BasicWriter &w, const T &value, internal::MemoryBuffer buffer; auto str = internal::format_value(buffer, value); typedef internal::MakeArg< basic_format_context > MakeArg; - format_arg< ArgFormatter >(w, MakeArg(str), ctx); + do_format_arg< ArgFormatter >(w, MakeArg(str), ctx); } FMT_API void vprint(std::ostream &os, CStringRef format_str, format_args args); From 6d241167638e6e7ad6761483ace9cfc8bbf4a395 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sun, 13 Nov 2016 09:42:17 -0800 Subject: [PATCH 040/340] Improve visitor API --- fmt/format.h | 125 ++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 90 insertions(+), 35 deletions(-) diff --git a/fmt/format.h b/fmt/format.h index 30d4c386..848d79a4 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -1535,6 +1535,43 @@ typedef basic_format_args> wformat_args; #define FMT_DISPATCH(call) static_cast(this)->call +template +typename std::result_of::type visit(Visitor &&vis, format_arg arg) { + switch (arg.type) { + case format_arg::NONE: + case format_arg::NAMED_ARG: + FMT_ASSERT(false, "invalid argument type"); + break; + case format_arg::INT: + return vis(arg.int_value); + case format_arg::UINT: + return vis(arg.uint_value); + case format_arg::LONG_LONG: + return vis(arg.long_long_value); + case format_arg::ULONG_LONG: + return vis(arg.ulong_long_value); + case format_arg::BOOL: + return vis(arg.int_value != 0); + case format_arg::CHAR: + return vis(static_cast(arg.int_value)); + case format_arg::DOUBLE: + return vis(arg.double_value); + case format_arg::LONG_DOUBLE: + return vis(arg.long_double_value); + case format_arg::CSTRING: + return vis(arg.string.value); + case format_arg::STRING: + return vis(arg.string); + case format_arg::WSTRING: + return vis(arg.wstring); + case format_arg::POINTER: + return vis(arg.pointer); + case format_arg::CUSTOM: + return vis(arg.custom); + } + return typename std::result_of::type(); +} + /** \rst An argument visitor based on the `curiously recurring template pattern @@ -1649,6 +1686,58 @@ class ArgVisitor { return FMT_DISPATCH(visit_unhandled_arg()); } + Result operator()(int value) { + return FMT_DISPATCH(visit_int(value)); + } + + Result operator()(unsigned value) { + return FMT_DISPATCH(visit_uint(value)); + } + + Result operator()(fmt::LongLong value) { + return FMT_DISPATCH(visit_long_long(value)); + } + + Result operator()(fmt::ULongLong value) { + return FMT_DISPATCH(visit_ulong_long(value)); + } + + Result operator()(bool value) { + return FMT_DISPATCH(visit_bool(value)); + } + + Result operator()(wchar_t value) { + return FMT_DISPATCH(visit_char(value)); + } + + Result operator()(double value) { + return FMT_DISPATCH(visit_double(value)); + } + + Result operator()(long double value) { + return FMT_DISPATCH(visit_long_double(value)); + } + + Result operator()(const char *value) { + return FMT_DISPATCH(visit_cstring(value)); + } + + Result operator()(format_arg::StringValue value) { + return FMT_DISPATCH(visit_string(value)); + } + + Result operator()(format_arg::StringValue value) { + return FMT_DISPATCH(visit_wstring(value)); + } + + Result operator()(const void *value) { + return FMT_DISPATCH(visit_pointer(value)); + } + + Result operator()(format_arg::CustomValue value) { + return FMT_DISPATCH(visit_custom(value)); + } + /** \rst Visits an argument dispatching to the appropriate visit method based on @@ -1657,41 +1746,7 @@ class ArgVisitor { called. \endrst */ - Result visit(const Arg &arg) { - switch (arg.type) { - case Arg::NONE: - case Arg::NAMED_ARG: - FMT_ASSERT(false, "invalid argument type"); - break; - case Arg::INT: - return FMT_DISPATCH(visit_int(arg.int_value)); - case Arg::UINT: - return FMT_DISPATCH(visit_uint(arg.uint_value)); - case Arg::LONG_LONG: - return FMT_DISPATCH(visit_long_long(arg.long_long_value)); - case Arg::ULONG_LONG: - return FMT_DISPATCH(visit_ulong_long(arg.ulong_long_value)); - case Arg::BOOL: - return FMT_DISPATCH(visit_bool(arg.int_value != 0)); - case Arg::CHAR: - return FMT_DISPATCH(visit_char(arg.int_value)); - case Arg::DOUBLE: - return FMT_DISPATCH(visit_double(arg.double_value)); - case Arg::LONG_DOUBLE: - return FMT_DISPATCH(visit_long_double(arg.long_double_value)); - case Arg::CSTRING: - return FMT_DISPATCH(visit_cstring(arg.string.value)); - case Arg::STRING: - return FMT_DISPATCH(visit_string(arg.string)); - case Arg::WSTRING: - return FMT_DISPATCH(visit_wstring(arg.wstring)); - case Arg::POINTER: - return FMT_DISPATCH(visit_pointer(arg.pointer)); - case Arg::CUSTOM: - return FMT_DISPATCH(visit_custom(arg.custom)); - } - return Result(); - } + Result visit(const format_arg &arg) { return fmt::visit(*this, arg); } }; enum Alignment { From 95a53e1f62d874aaa987b3f0750361d3393874b8 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sat, 19 Nov 2016 07:39:07 -0800 Subject: [PATCH 041/340] Refactor argument visitor API (#422) --- fmt/format.h | 41 ++++++++++++++++++++++++++++++----------- fmt/printf.h | 16 +++++++++------- 2 files changed, 39 insertions(+), 18 deletions(-) diff --git a/fmt/format.h b/fmt/format.h index 848d79a4..0eb1f457 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -1536,7 +1536,8 @@ typedef basic_format_args> wformat_args; #define FMT_DISPATCH(call) static_cast(this)->call template -typename std::result_of::type visit(Visitor &&vis, format_arg arg) { +typename std::result_of::type visit(Visitor &&vis, + format_arg arg) { switch (arg.type) { case format_arg::NONE: case format_arg::NAMED_ARG: @@ -1746,7 +1747,9 @@ class ArgVisitor { called. \endrst */ - Result visit(const format_arg &arg) { return fmt::visit(*this, arg); } + Result visit(const format_arg &arg) { + return fmt::visit(*static_cast(this), arg); + } }; enum Alignment { @@ -2056,6 +2059,22 @@ class ArgFormatterBase : public ArgVisitor { writer_.write_int(reinterpret_cast(p), spec_); } + template + void write_str(Arg::StringValue value, + typename EnableIf< + std::is_same::value && + std::is_same::value, int>::type = 0) { + writer_.write_str(value, spec_); + } + + template + void write_str(Arg::StringValue value, + typename EnableIf< + !std::is_same::value || + !std::is_same::value, int>::type = 0) { + // Do nothing. + } + protected: BasicWriter &writer() { return writer_; } FormatSpec &spec() { return spec_; } @@ -2083,13 +2102,15 @@ class ArgFormatterBase : public ArgVisitor { template void visit_any_double(T value) { writer_.write_double(value, spec_); } - void visit_bool(bool value) { + using ArgVisitor::operator(); + + void operator()(bool value) { if (spec_.type_) return visit_any_int(value); write(value); } - void visit_char(int value) { + void operator()(wchar_t value) { if (spec_.type_ && spec_.type_ != 'c') { spec_.flags_ |= CHAR_FLAG; writer_.write_int(value, spec_); @@ -2119,23 +2140,21 @@ class ArgFormatterBase : public ArgVisitor { *out = internal::CharTraits::cast(value); } - void visit_cstring(const char *value) { + void operator()(const char *value) { if (spec_.type_ == 'p') return write_pointer(value); write(value); } - void visit_string(Arg::StringValue value) { + void operator()(Arg::StringValue value) { writer_.write_str(value, spec_); } - using ArgVisitor::visit_wstring; - - void visit_wstring(Arg::StringValue value) { - writer_.write_str(value, spec_); + void operator()(Arg::StringValue value) { + write_str(value); } - void visit_pointer(const void *value) { + void operator()(const void *value) { if (spec_.type_ && spec_.type_ != 'p') report_unknown_type(spec_.type_, "pointer"); write_pointer(value); diff --git a/fmt/printf.h b/fmt/printf.h index 85572c4e..8f9278fe 100644 --- a/fmt/printf.h +++ b/fmt/printf.h @@ -210,8 +210,10 @@ class BasicPrintfArgFormatter : public internal::ArgFormatterBase { BasicPrintfArgFormatter(BasicWriter &writer, FormatSpec &spec) : internal::ArgFormatterBase(writer, spec) {} + using Base::operator(); + /** Formats an argument of type ``bool``. */ - void visit_bool(bool value) { + void operator()(bool value) { FormatSpec &fmt_spec = this->spec(); if (fmt_spec.type_ != 's') return this->visit_any_int(value); @@ -220,7 +222,7 @@ class BasicPrintfArgFormatter : public internal::ArgFormatterBase { } /** Formats a character. */ - void visit_char(int value) { + void operator()(wchar_t value) { const FormatSpec &fmt_spec = this->spec(); BasicWriter &w = this->writer(); if (fmt_spec.type_ && fmt_spec.type_ != 'c') @@ -243,9 +245,9 @@ class BasicPrintfArgFormatter : public internal::ArgFormatterBase { } /** Formats a null-terminated C string. */ - void visit_cstring(const char *value) { + void operator()(const char *value) { if (value) - Base::visit_cstring(value); + Base::operator()(value); else if (this->spec().type_ == 'p') write_null_pointer(); else @@ -253,15 +255,15 @@ class BasicPrintfArgFormatter : public internal::ArgFormatterBase { } /** Formats a pointer. */ - void visit_pointer(const void *value) { + void operator()(const void *value) { if (value) - return Base::visit_pointer(value); + return Base::operator()(value); this->spec().type_ = 0; write_null_pointer(); } /** Formats an argument of a custom (user-defined) type. */ - void visit_custom(internal::Arg::CustomValue c) { + void operator()(internal::Arg::CustomValue c) { const Char format_str[] = {'}', '\0'}; auto args = basic_format_args>(); basic_format_context ctx(format_str, args); From caa60b9c998cc49eedfa6d8536149bc8376013e1 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sat, 19 Nov 2016 07:41:28 -0800 Subject: [PATCH 042/340] Update comment --- fmt/format.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fmt/format.h b/fmt/format.h index 0eb1f457..d0a01468 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -1743,8 +1743,8 @@ class ArgVisitor { \rst Visits an argument dispatching to the appropriate visit method based on the argument type. For example, if the argument type is ``double`` then - the `~fmt::ArgVisitor::visit_double()` method of the *Impl* class will be - called. + the `~fmt::ArgVisitor::operator()(double)` method of the *Impl* class will + be called. \endrst */ Result visit(const format_arg &arg) { From c9dc41ab3f8d46dc143d6d4187d03c6a790a8231 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sat, 19 Nov 2016 07:59:54 -0800 Subject: [PATCH 043/340] Replace ArgVisitor::visit with a free visit function --- fmt/format.h | 21 ++++++++------------- fmt/printf.h | 26 +++++++++++++------------- test/format-impl-test.cc | 2 +- test/ostream-test.cc | 2 +- test/util-test.cc | 10 +++++----- 5 files changed, 28 insertions(+), 33 deletions(-) diff --git a/fmt/format.h b/fmt/format.h index d0a01468..e6f01725 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -1535,6 +1535,13 @@ typedef basic_format_args> wformat_args; #define FMT_DISPATCH(call) static_cast(this)->call +/** + \rst + Visits an argument dispatching to the appropriate visit method based on + the argument type. For example, if the argument type is ``double`` then + ``vis(value)`` will be called with the value of type ``double``. + \endrst + */ template typename std::result_of::type visit(Visitor &&vis, format_arg arg) { @@ -1738,18 +1745,6 @@ class ArgVisitor { Result operator()(format_arg::CustomValue value) { return FMT_DISPATCH(visit_custom(value)); } - - /** - \rst - Visits an argument dispatching to the appropriate visit method based on - the argument type. For example, if the argument type is ``double`` then - the `~fmt::ArgVisitor::operator()(double)` method of the *Impl* class will - be called. - \endrst - */ - Result visit(const format_arg &arg) { - return fmt::visit(*static_cast(this), arg); - } }; enum Alignment { @@ -3683,7 +3678,7 @@ void do_format_arg(BasicWriter &writer, const internal::Arg &arg, FMT_THROW(format_error("missing '}' in format string")); // Format argument. - ArgFormatter(writer, ctx, spec).visit(arg); + visit(ArgFormatter(writer, ctx, spec), arg); } /** Formats arguments and writes the output to the writer. */ diff --git a/fmt/printf.h b/fmt/printf.h index 8f9278fe..c8d7b3dc 100644 --- a/fmt/printf.h +++ b/fmt/printf.h @@ -388,7 +388,7 @@ unsigned printf_context::parse_header( spec.width_ = internal::parse_nonnegative_int(s); } else if (*s == '*') { ++s; - spec.width_ = internal::WidthHandler(spec).visit(get_arg(s)); + spec.width_ = visit(internal::WidthHandler(spec), get_arg(s)); } return arg_index; } @@ -420,13 +420,13 @@ void printf_context::format(BasicWriter &writer) { spec.precision_ = static_cast(internal::parse_nonnegative_int(s)); } else if (*s == '*') { ++s; - spec.precision_ = internal::PrecisionHandler().visit(get_arg(s)); + spec.precision_ = visit(internal::PrecisionHandler(), get_arg(s)); } } using internal::Arg; Arg arg = get_arg(s, arg_index); - if (spec.flag(HASH_FLAG) && internal::IsZeroInt().visit(arg)) + if (spec.flag(HASH_FLAG) && visit(internal::IsZeroInt(), arg)) spec.flags_ &= ~internal::to_unsigned(HASH_FLAG); if (spec.fill_ == '0') { if (arg.type <= Arg::LAST_NUMERIC_TYPE) @@ -440,24 +440,24 @@ void printf_context::format(BasicWriter &writer) { switch (*s++) { case 'h': if (*s == 'h') - ArgConverter(arg, *++s).visit(arg); + visit(ArgConverter(arg, *++s), arg); else - ArgConverter(arg, *s).visit(arg); + visit(ArgConverter(arg, *s), arg); break; case 'l': if (*s == 'l') - ArgConverter(arg, *++s).visit(arg); + visit(ArgConverter(arg, *++s), arg); else - ArgConverter(arg, *s).visit(arg); + visit(ArgConverter(arg, *s), arg); break; case 'j': - ArgConverter(arg, *s).visit(arg); + visit(ArgConverter(arg, *s), arg); break; case 'z': - ArgConverter(arg, *s).visit(arg); + visit(ArgConverter(arg, *s), arg); break; case 't': - ArgConverter(arg, *s).visit(arg); + visit(ArgConverter(arg, *s), arg); break; case 'L': // printf produces garbage when 'L' is omitted for long double, no @@ -465,7 +465,7 @@ void printf_context::format(BasicWriter &writer) { break; default: --s; - ArgConverter(arg, *s).visit(arg); + visit(ArgConverter(arg, *s), arg); } // Parse type. @@ -480,7 +480,7 @@ void printf_context::format(BasicWriter &writer) { break; case 'c': // TODO: handle wchar_t - internal::CharConverter(arg).visit(arg); + visit(internal::CharConverter(arg), arg); break; } } @@ -488,7 +488,7 @@ void printf_context::format(BasicWriter &writer) { start = s; // Format argument. - AF(writer, spec).visit(arg); + visit(AF(writer, spec), arg); } internal::write(writer, start, s); } diff --git a/test/format-impl-test.cc b/test/format-impl-test.cc index e29a6fe6..4ad2bccf 100644 --- a/test/format-impl-test.cc +++ b/test/format-impl-test.cc @@ -46,7 +46,7 @@ TEST(FormatTest, ArgConverter) { Arg arg = Arg(); arg.type = Arg::LONG_LONG; arg.long_long_value = std::numeric_limits::max(); - fmt::internal::ArgConverter(arg, 'd').visit(arg); + visit(fmt::internal::ArgConverter(arg, 'd'), arg); EXPECT_EQ(Arg::LONG_LONG, arg.type); } diff --git a/test/ostream-test.cc b/test/ostream-test.cc index 2d1ace63..d600714c 100644 --- a/test/ostream-test.cc +++ b/test/ostream-test.cc @@ -69,7 +69,7 @@ TEST(OStreamTest, CustomArg) { fmt::format_context ctx("}", fmt::format_args()); fmt::FormatSpec spec; TestArgFormatter af(writer, ctx, spec); - af.visit(fmt::internal::MakeArg(TestEnum())); + visit(af, fmt::internal::MakeArg(TestEnum())); EXPECT_EQ("TestEnum", writer.str()); } diff --git a/test/util-test.cc b/test/util-test.cc index b553427c..7bca57e4 100644 --- a/test/util-test.cc +++ b/test/util-test.cc @@ -628,7 +628,7 @@ struct TestVisitor : fmt::ArgVisitor { #define EXPECT_RESULT_(Char, type_code, value) { \ Arg arg = make_arg(value); \ - Result result = TestVisitor().visit(arg); \ + Result result = fmt::visit(TestVisitor(), arg); \ EXPECT_EQ(Arg::type_code, result.arg.type); \ EXPECT_EQ(value, ArgInfo::get(result.arg)); \ } @@ -653,7 +653,7 @@ TEST(ArgVisitorTest, VisitAll) { const void *p = STR; EXPECT_RESULT(POINTER, p); ::Test t; - Result result = TestVisitor().visit(make_arg(t)); + Result result = visit(TestVisitor(), make_arg(t)); EXPECT_EQ(Arg::CUSTOM, result.arg.type); EXPECT_EQ(&t, result.arg.custom.value); } @@ -668,7 +668,7 @@ struct TestAnyVisitor : fmt::ArgVisitor { #undef EXPECT_RESULT #define EXPECT_RESULT(type_code, value) { \ - Result result = TestAnyVisitor().visit(make_arg(value)); \ + Result result = visit(TestAnyVisitor(), make_arg(value)); \ EXPECT_EQ(Arg::type_code, result.arg.type); \ EXPECT_EQ(value, ArgInfo::get(result.arg)); \ } @@ -688,7 +688,7 @@ struct TestUnhandledVisitor : }; #define EXPECT_UNHANDLED(value) \ - EXPECT_STREQ("test", TestUnhandledVisitor().visit(make_arg(value))); + EXPECT_STREQ("test", visit(TestUnhandledVisitor(), make_arg(value))); TEST(ArgVisitorTest, VisitUnhandledArg) { EXPECT_UNHANDLED(42); @@ -710,7 +710,7 @@ TEST(ArgVisitorTest, VisitUnhandledArg) { TEST(ArgVisitorTest, VisitInvalidArg) { Arg arg = Arg(); arg.type = static_cast(Arg::NONE); - EXPECT_ASSERT(TestVisitor().visit(arg), "invalid argument type"); + EXPECT_ASSERT(visit(TestVisitor(), arg), "invalid argument type"); } // Tests fmt::internal::count_digits for integer type Int. From 751ff64bdbb60e2baa6045b6763e0445875e18aa Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sat, 19 Nov 2016 08:40:24 -0800 Subject: [PATCH 044/340] Update ArgConverter to the new visitor API --- fmt/printf.h | 50 ++++++++++++++++++++++++++++++-------------------- 1 file changed, 30 insertions(+), 20 deletions(-) diff --git a/fmt/printf.h b/fmt/printf.h index c8d7b3dc..83f5fa37 100644 --- a/fmt/printf.h +++ b/fmt/printf.h @@ -71,29 +71,24 @@ struct is_same { enum { value = 1 }; }; -// An argument visitor that converts an integer argument to T for printf, -// if T is an integral type. If T is void, the argument is converted to -// corresponding signed or unsigned type depending on the type specifier: -// 'd' and 'i' - signed, other - unsigned) -template -class ArgConverter : public ArgVisitor, void> { +template +class ArgConverter { private: internal::Arg &arg_; wchar_t type_; - FMT_DISALLOW_COPY_AND_ASSIGN(ArgConverter); - public: ArgConverter(internal::Arg &arg, wchar_t type) : arg_(arg), type_(type) {} - void visit_bool(bool value) { + void operator()(bool value) { if (type_ != 's') - visit_any_int(value); + operator()(value); } template - void visit_any_int(U value) { + typename std::enable_if::value>::type + operator()(U value) { bool is_signed = type_ == 'd' || type_ == 'i'; using internal::Arg; typedef typename internal::Conditional< @@ -122,8 +117,23 @@ class ArgConverter : public ArgVisitor, void> { } } } + + template + typename std::enable_if::value>::type + operator()(U value) { + // No coversion needed for non-integral types. + } }; +// Converts an integer argument to T for printf, if T is an integral type. +// If T is void, the argument is converted to corresponding signed or unsigned +// type depending on the type specifier: 'd' and 'i' - signed, other - +// unsigned). +template +void convert_arg(format_arg &arg, wchar_t type) { + visit(ArgConverter(arg, type), arg); +} + // Converts an integer argument to char for printf. class CharConverter : public ArgVisitor { private: @@ -436,28 +446,28 @@ void printf_context::format(BasicWriter &writer) { } // Parse length and convert the argument to the required type. - using internal::ArgConverter; + using internal::convert_arg; switch (*s++) { case 'h': if (*s == 'h') - visit(ArgConverter(arg, *++s), arg); + convert_arg(arg, *++s); else - visit(ArgConverter(arg, *s), arg); + convert_arg(arg, *s); break; case 'l': if (*s == 'l') - visit(ArgConverter(arg, *++s), arg); + convert_arg(arg, *++s); else - visit(ArgConverter(arg, *s), arg); + convert_arg(arg, *s); break; case 'j': - visit(ArgConverter(arg, *s), arg); + convert_arg(arg, *s); break; case 'z': - visit(ArgConverter(arg, *s), arg); + convert_arg(arg, *s); break; case 't': - visit(ArgConverter(arg, *s), arg); + convert_arg(arg, *s); break; case 'L': // printf produces garbage when 'L' is omitted for long double, no @@ -465,7 +475,7 @@ void printf_context::format(BasicWriter &writer) { break; default: --s; - visit(ArgConverter(arg, *s), arg); + convert_arg(arg, *s); } // Parse type. From e2dfd39c756e16ebabc75314728864ca35e2933f Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sat, 19 Nov 2016 09:29:09 -0800 Subject: [PATCH 045/340] Update arg visitors --- fmt/printf.h | 56 +++++++++++++++++++++++++++++++++++----------------- 1 file changed, 38 insertions(+), 18 deletions(-) diff --git a/fmt/printf.h b/fmt/printf.h index 83f5fa37..c8ae99b2 100644 --- a/fmt/printf.h +++ b/fmt/printf.h @@ -40,25 +40,34 @@ struct IntChecker { static bool fits_in_int(int) { return true; } }; -class PrecisionHandler : public ArgVisitor { +class PrecisionHandler { public: - void report_unhandled_arg() { - FMT_THROW(format_error("precision is not integer")); - } - template - int visit_any_int(T value) { + typename std::enable_if::value, int>::type + operator()(T value) { if (!IntChecker::is_signed>::fits_in_int(value)) FMT_THROW(format_error("number is too big")); return static_cast(value); } + + template + typename std::enable_if::value, int>::type + operator()(T) { + FMT_THROW(format_error("precision is not integer")); + return 0; + } }; -// IsZeroInt::visit(arg) returns true iff arg is a zero integer. -class IsZeroInt : public ArgVisitor { +// An argument visitor that returns true iff arg is a zero integer. +class IsZeroInt { public: template - bool visit_any_int(T value) { return value == 0; } + typename std::enable_if::value, bool>::type + operator()(T value) { return value == 0; } + + template + typename std::enable_if::value, bool>::type + operator()(T value) { return false; } }; template @@ -120,7 +129,7 @@ class ArgConverter { template typename std::enable_if::value>::type - operator()(U value) { + operator()(U value) { // No coversion needed for non-integral types. } }; @@ -135,7 +144,7 @@ void convert_arg(format_arg &arg, wchar_t type) { } // Converts an integer argument to char for printf. -class CharConverter : public ArgVisitor { +class CharConverter { private: internal::Arg &arg_; @@ -145,15 +154,22 @@ class CharConverter : public ArgVisitor { explicit CharConverter(internal::Arg &arg) : arg_(arg) {} template - void visit_any_int(T value) { + typename std::enable_if::value>::type + operator()(T value) { arg_.type = internal::Arg::CHAR; arg_.int_value = static_cast(value); } + + template + typename std::enable_if::value>::type + operator()(T value) { + // No coversion needed for non-integral types. + } }; // Checks if an argument is a valid printf width specifier and sets // left alignment if it is negative. -class WidthHandler : public ArgVisitor { +class WidthHandler { private: FormatSpec &spec_; @@ -162,12 +178,9 @@ class WidthHandler : public ArgVisitor { public: explicit WidthHandler(FormatSpec &spec) : spec_(spec) {} - void report_unhandled_arg() { - FMT_THROW(format_error("width is not integer")); - } - template - unsigned visit_any_int(T value) { + typename std::enable_if::value, unsigned>::type + operator()(T value) { typedef typename internal::IntTraits::MainType UnsignedType; UnsignedType width = static_cast(value); if (internal::is_negative(value)) { @@ -179,6 +192,13 @@ class WidthHandler : public ArgVisitor { FMT_THROW(format_error("number is too big")); return static_cast(width); } + + template + typename std::enable_if::value, unsigned>::type + operator()(T value) { + FMT_THROW(format_error("width is not integer")); + return 0; + } }; } // namespace internal From d58cc8a4a80079348cc1c6edbe220dec7568738c Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sun, 20 Nov 2016 07:42:38 -0800 Subject: [PATCH 046/340] Merge BasicPrintfArgFormatter and PrintfArgFormatter --- fmt/format.h | 8 ++++---- fmt/printf.h | 37 ++++++++--------------------------- test/custom-formatter-test.cc | 15 +++++++------- 3 files changed, 19 insertions(+), 41 deletions(-) diff --git a/fmt/format.h b/fmt/format.h index e6f01725..4ce0c1b1 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -374,8 +374,8 @@ typedef BasicWriter WWriter; template class ArgFormatter; -template -class BasicPrintfArgFormatter; +template +class PrintfArgFormatter; template class basic_format_context; @@ -2489,8 +2489,8 @@ class BasicWriter { template friend class internal::ArgFormatterBase; - template - friend class BasicPrintfArgFormatter; + template + friend class PrintfArgFormatter; protected: /** diff --git a/fmt/printf.h b/fmt/printf.h index c8ae99b2..f0adf71c 100644 --- a/fmt/printf.h +++ b/fmt/printf.h @@ -204,30 +204,19 @@ class WidthHandler { /** \rst - A ``printf`` argument formatter based on the `curiously recurring template - pattern `_. - - To use `~fmt::BasicPrintfArgFormatter` define a subclass that implements some - or all of the visit methods with the same signatures as the methods in - `~fmt::ArgVisitor`, for example, `~fmt::ArgVisitor::visit_int()`. - Pass the subclass as the *Impl* template parameter. When a formatting - function processes an argument, it will dispatch to a visit method - specific to the argument type. For example, if the argument type is - ``double`` then the `~fmt::ArgVisitor::visit_double()` method of a subclass - will be called. If the subclass doesn't contain a method with this signature, - then a corresponding method of `~fmt::BasicPrintfArgFormatter` or its - superclass will be called. + The ``printf`` argument formatter. \endrst */ -template -class BasicPrintfArgFormatter : public internal::ArgFormatterBase { +template +class PrintfArgFormatter : + public internal::ArgFormatterBase, Char> { private: void write_null_pointer() { this->spec().type_ = 0; this->write("(nil)"); } - typedef internal::ArgFormatterBase Base; + typedef internal::ArgFormatterBase, Char> Base; public: /** @@ -237,8 +226,8 @@ class BasicPrintfArgFormatter : public internal::ArgFormatterBase { specifier information for standard argument types. \endrst */ - BasicPrintfArgFormatter(BasicWriter &writer, FormatSpec &spec) - : internal::ArgFormatterBase(writer, spec) {} + PrintfArgFormatter(BasicWriter &writer, FormatSpec &spec) + : internal::ArgFormatterBase, Char>(writer, spec) {} using Base::operator(); @@ -246,7 +235,7 @@ class BasicPrintfArgFormatter : public internal::ArgFormatterBase { void operator()(bool value) { FormatSpec &fmt_spec = this->spec(); if (fmt_spec.type_ != 's') - return this->visit_any_int(value); + return (*this)(value ? 1 : 0); fmt_spec.type_ = 0; this->write(value); } @@ -301,16 +290,6 @@ class BasicPrintfArgFormatter : public internal::ArgFormatterBase { } }; -/** The default printf argument formatter. */ -template -class PrintfArgFormatter - : public BasicPrintfArgFormatter, Char> { - public: - /** Constructs an argument formatter object. */ - PrintfArgFormatter(BasicWriter &w, FormatSpec &s) - : BasicPrintfArgFormatter, Char>(w, s) {} -}; - /** This template formats data and writes the output to a writer. */ template > diff --git a/test/custom-formatter-test.cc b/test/custom-formatter-test.cc index 83648aba..779c1ea2 100644 --- a/test/custom-formatter-test.cc +++ b/test/custom-formatter-test.cc @@ -10,7 +10,7 @@ #include "fmt/printf.h" #include "gtest-extra.h" -using fmt::BasicPrintfArgFormatter; +using fmt::PrintfArgFormatter; // A custom argument formatter that doesn't print `-` for floating-point values // rounded to 0. @@ -30,18 +30,17 @@ class CustomArgFormatter // A custom argument formatter that doesn't print `-` for floating-point values // rounded to 0. -class CustomPrintfArgFormatter : - public BasicPrintfArgFormatter { +class CustomPrintfArgFormatter : public PrintfArgFormatter { public: - typedef BasicPrintfArgFormatter Base; - CustomPrintfArgFormatter(fmt::BasicWriter &w, fmt::FormatSpec &spec) - : Base(w, spec) {} + : PrintfArgFormatter(w, spec) {} - void visit_double(double value) { + using PrintfArgFormatter::operator(); + + void operator()(double value) { if (round(value * pow(10, spec().precision())) == 0) value = 0; - Base::visit_double(value); + PrintfArgFormatter::operator()(value); } }; From d4084ac5b135b86ee6afb3b614039b9d39989842 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sun, 20 Nov 2016 08:47:24 -0800 Subject: [PATCH 047/340] Get rid of ArgVisitor --- fmt/format.h | 201 ++-------------------------------- test/custom-formatter-test.cc | 6 +- test/format-test.cc | 11 +- test/util-test.cc | 75 +++---------- 4 files changed, 36 insertions(+), 257 deletions(-) diff --git a/fmt/format.h b/fmt/format.h index 4ce0c1b1..dd3ac296 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -1580,173 +1580,6 @@ typename std::result_of::type visit(Visitor &&vis, return typename std::result_of::type(); } -/** - \rst - An argument visitor based on the `curiously recurring template pattern - `_. - - To use `~fmt::ArgVisitor` define a subclass that implements some or all of the - visit methods with the same signatures as the methods in `~fmt::ArgVisitor`, - for example, `~fmt::ArgVisitor::visit_int()`. - Pass the subclass as the *Impl* template parameter. Then calling - `~fmt::ArgVisitor::visit` for some argument will dispatch to a visit method - specific to the argument type. For example, if the argument type is - ``double`` then the `~fmt::ArgVisitor::visit_double()` method of a subclass - will be called. If the subclass doesn't contain a method with this signature, - then a corresponding method of `~fmt::ArgVisitor` will be called. - - **Example**:: - - class MyArgVisitor : public fmt::ArgVisitor { - public: - void visit_int(int value) { fmt::print("{}", value); } - void visit_double(double value) { fmt::print("{}", value ); } - }; - \endrst - */ -template -class ArgVisitor { - private: - typedef internal::Arg Arg; - - public: - void report_unhandled_arg() {} - - Result visit_unhandled_arg() { - FMT_DISPATCH(report_unhandled_arg()); - return Result(); - } - - /** Visits an ``int`` argument. **/ - Result visit_int(int value) { - return FMT_DISPATCH(visit_any_int(value)); - } - - /** Visits a ``long long`` argument. **/ - Result visit_long_long(LongLong value) { - return FMT_DISPATCH(visit_any_int(value)); - } - - /** Visits an ``unsigned`` argument. **/ - Result visit_uint(unsigned value) { - return FMT_DISPATCH(visit_any_int(value)); - } - - /** Visits an ``unsigned long long`` argument. **/ - Result visit_ulong_long(ULongLong value) { - return FMT_DISPATCH(visit_any_int(value)); - } - - /** Visits a ``bool`` argument. **/ - Result visit_bool(bool value) { - return FMT_DISPATCH(visit_any_int(value)); - } - - /** Visits a ``char`` or ``wchar_t`` argument. **/ - Result visit_char(int value) { - return FMT_DISPATCH(visit_any_int(value)); - } - - /** Visits an argument of any integral type. **/ - template - Result visit_any_int(T) { - return FMT_DISPATCH(visit_unhandled_arg()); - } - - /** Visits a ``double`` argument. **/ - Result visit_double(double value) { - return FMT_DISPATCH(visit_any_double(value)); - } - - /** Visits a ``long double`` argument. **/ - Result visit_long_double(long double value) { - return FMT_DISPATCH(visit_any_double(value)); - } - - /** Visits a ``double`` or ``long double`` argument. **/ - template - Result visit_any_double(T) { - return FMT_DISPATCH(visit_unhandled_arg()); - } - - /** Visits a null-terminated C string (``const char *``) argument. **/ - Result visit_cstring(const char *) { - return FMT_DISPATCH(visit_unhandled_arg()); - } - - /** Visits a string argument. **/ - Result visit_string(Arg::StringValue) { - return FMT_DISPATCH(visit_unhandled_arg()); - } - - /** Visits a wide string argument. **/ - Result visit_wstring(Arg::StringValue) { - return FMT_DISPATCH(visit_unhandled_arg()); - } - - /** Visits a pointer argument. **/ - Result visit_pointer(const void *) { - return FMT_DISPATCH(visit_unhandled_arg()); - } - - /** Visits an argument of a custom (user-defined) type. **/ - Result visit_custom(Arg::CustomValue) { - return FMT_DISPATCH(visit_unhandled_arg()); - } - - Result operator()(int value) { - return FMT_DISPATCH(visit_int(value)); - } - - Result operator()(unsigned value) { - return FMT_DISPATCH(visit_uint(value)); - } - - Result operator()(fmt::LongLong value) { - return FMT_DISPATCH(visit_long_long(value)); - } - - Result operator()(fmt::ULongLong value) { - return FMT_DISPATCH(visit_ulong_long(value)); - } - - Result operator()(bool value) { - return FMT_DISPATCH(visit_bool(value)); - } - - Result operator()(wchar_t value) { - return FMT_DISPATCH(visit_char(value)); - } - - Result operator()(double value) { - return FMT_DISPATCH(visit_double(value)); - } - - Result operator()(long double value) { - return FMT_DISPATCH(visit_long_double(value)); - } - - Result operator()(const char *value) { - return FMT_DISPATCH(visit_cstring(value)); - } - - Result operator()(format_arg::StringValue value) { - return FMT_DISPATCH(visit_string(value)); - } - - Result operator()(format_arg::StringValue value) { - return FMT_DISPATCH(visit_wstring(value)); - } - - Result operator()(const void *value) { - return FMT_DISPATCH(visit_pointer(value)); - } - - Result operator()(format_arg::CustomValue value) { - return FMT_DISPATCH(visit_custom(value)); - } -}; - enum Alignment { ALIGN_DEFAULT, ALIGN_LEFT, ALIGN_RIGHT, ALIGN_CENTER, ALIGN_NUMERIC }; @@ -2041,7 +1874,7 @@ void ArgMap::init(const basic_format_args &args) { } template -class ArgFormatterBase : public ArgVisitor { +class ArgFormatterBase { private: BasicWriter &writer_; FormatSpec &spec_; @@ -2092,16 +1925,16 @@ class ArgFormatterBase : public ArgVisitor { : writer_(w), spec_(s) {} template - void visit_any_int(T value) { writer_.write_int(value, spec_); } + typename std::enable_if::value>::type + operator()(T value) { writer_.write_int(value, spec_); } template - void visit_any_double(T value) { writer_.write_double(value, spec_); } - - using ArgVisitor::operator(); + typename std::enable_if::value>::type + operator()(T value) { writer_.write_double(value, spec_); } void operator()(bool value) { if (spec_.type_) - return visit_any_int(value); + return (*this)(value ? 1 : 0); write(value); } @@ -2222,23 +2055,7 @@ class format_context_base { }; } // namespace internal -/** - \rst - An argument formatter based on the `curiously recurring template pattern - `_. - - To use `~fmt::BasicArgFormatter` define a subclass that implements some or - all of the visit methods with the same signatures as the methods in - `~fmt::ArgVisitor`, for example, `~fmt::ArgVisitor::visit_int()`. - Pass the subclass as the *Impl* template parameter. When a formatting - function processes an argument, it will dispatch to a visit method - specific to the argument type. For example, if the argument type is - ``double`` then the `~fmt::ArgVisitor::visit_double()` method of a subclass - will be called. If the subclass doesn't contain a method with this signature, - then a corresponding method of `~fmt::BasicArgFormatter` or its superclass - will be called. - \endrst - */ +/** An argument formatter. */ template class BasicArgFormatter : public internal::ArgFormatterBase { private: @@ -2257,8 +2074,10 @@ class BasicArgFormatter : public internal::ArgFormatterBase { FormatSpec &spec) : internal::ArgFormatterBase(writer, spec), ctx_(ctx) {} + using internal::ArgFormatterBase::operator(); + /** Formats an argument of a custom (user-defined) type. */ - void visit_custom(internal::Arg::CustomValue c) { + void operator()(internal::Arg::CustomValue c) { c.format(&this->writer(), c.value, &ctx_); } }; diff --git a/test/custom-formatter-test.cc b/test/custom-formatter-test.cc index 779c1ea2..9c568523 100644 --- a/test/custom-formatter-test.cc +++ b/test/custom-formatter-test.cc @@ -21,10 +21,12 @@ class CustomArgFormatter fmt::FormatSpec &s) : fmt::BasicArgFormatter(w, ctx, s) {} - void visit_double(double value) { + using fmt::BasicArgFormatter::operator(); + + void operator()(double value) { if (round(value * pow(10, spec().precision())) == 0) value = 0; - fmt::BasicArgFormatter::visit_double(value); + fmt::BasicArgFormatter::operator()(value); } }; diff --git a/test/format-test.cc b/test/format-test.cc index e7e72a1d..2ce9d7f3 100644 --- a/test/format-test.cc +++ b/test/format-test.cc @@ -1621,16 +1621,23 @@ TEST(FormatTest, Enum) { class MockArgFormatter : public fmt::internal::ArgFormatterBase { + private: + MOCK_METHOD1(call, void (int value)); + public: typedef fmt::internal::ArgFormatterBase Base; MockArgFormatter(fmt::Writer &w, fmt::format_context &ctx, fmt::FormatSpec &s) : fmt::internal::ArgFormatterBase(w, s) { - EXPECT_CALL(*this, visit_int(42)); + EXPECT_CALL(*this, call(42)); } - MOCK_METHOD1(visit_int, void (int value)); + using Base::operator(); + + void operator()(int value) { call(value); } + + void operator()(fmt::internal::Arg::CustomValue) {} }; void custom_vformat(fmt::CStringRef format_str, fmt::format_args args) { diff --git a/test/util-test.cc b/test/util-test.cc index 7bca57e4..2b144b95 100644 --- a/test/util-test.cc +++ b/test/util-test.cc @@ -605,23 +605,23 @@ struct Result { Result(const wchar_t *s) : arg(make_arg(s)) {} }; -struct TestVisitor : fmt::ArgVisitor { - Result visit_int(int value) { return value; } - Result visit_uint(unsigned value) { return value; } - Result visit_long_long(fmt::LongLong value) { return value; } - Result visit_ulong_long(fmt::ULongLong value) { return value; } - Result visit_double(double value) { return value; } - Result visit_long_double(long double value) { return value; } - Result visit_char(int value) { return static_cast(value); } - Result visit_cstring(const char *s) { return s; } - Result visit_string(fmt::internal::Arg::StringValue s) { +struct TestVisitor { + Result operator()(int value) { return value; } + Result operator()(unsigned value) { return value; } + Result operator()(fmt::LongLong value) { return value; } + Result operator()(fmt::ULongLong value) { return value; } + Result operator()(double value) { return value; } + Result operator()(long double value) { return value; } + Result operator()(wchar_t value) { return static_cast(value); } + Result operator()(const char *s) { return s; } + Result operator()(fmt::format_arg::StringValue s) { return s.value; } - Result visit_wstring(fmt::internal::Arg::StringValue s) { + Result operator()(fmt::format_arg::StringValue s) { return s.value; } - Result visit_pointer(const void *p) { return p; } - Result visit_custom(fmt::internal::Arg::CustomValue c) { + Result operator()(const void *p) { return p; } + Result operator()(fmt::format_arg::CustomValue c) { return *static_cast(c.value); } }; @@ -658,55 +658,6 @@ TEST(ArgVisitorTest, VisitAll) { EXPECT_EQ(&t, result.arg.custom.value); } -struct TestAnyVisitor : fmt::ArgVisitor { - template - Result visit_any_int(T value) { return value; } - - template - Result visit_any_double(T value) { return value; } -}; - -#undef EXPECT_RESULT -#define EXPECT_RESULT(type_code, value) { \ - Result result = visit(TestAnyVisitor(), make_arg(value)); \ - EXPECT_EQ(Arg::type_code, result.arg.type); \ - EXPECT_EQ(value, ArgInfo::get(result.arg)); \ -} - -TEST(ArgVisitorTest, VisitAny) { - EXPECT_RESULT(INT, 42); - EXPECT_RESULT(UINT, 42u); - EXPECT_RESULT(LONG_LONG, 42ll); - EXPECT_RESULT(ULONG_LONG, 42ull); - EXPECT_RESULT(DOUBLE, 4.2); - EXPECT_RESULT(LONG_DOUBLE, 4.2l); -} - -struct TestUnhandledVisitor : - fmt::ArgVisitor { - const char *visit_unhandled_arg() { return "test"; } -}; - -#define EXPECT_UNHANDLED(value) \ - EXPECT_STREQ("test", visit(TestUnhandledVisitor(), make_arg(value))); - -TEST(ArgVisitorTest, VisitUnhandledArg) { - EXPECT_UNHANDLED(42); - EXPECT_UNHANDLED(42u); - EXPECT_UNHANDLED(42ll); - EXPECT_UNHANDLED(42ull); - EXPECT_UNHANDLED(4.2); - EXPECT_UNHANDLED(4.2l); - EXPECT_UNHANDLED('x'); - const char STR[] = "abc"; - EXPECT_UNHANDLED(STR); - const wchar_t WSTR[] = L"abc"; - EXPECT_UNHANDLED(WSTR); - const void *p = STR; - EXPECT_UNHANDLED(p); - EXPECT_UNHANDLED(::Test()); -} - TEST(ArgVisitorTest, VisitInvalidArg) { Arg arg = Arg(); arg.type = static_cast(Arg::NONE); From 284297019fc9abbb9cc1b6c5c4c6772260515a8e Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sun, 20 Nov 2016 09:36:27 -0800 Subject: [PATCH 048/340] Merge BasicArgFormatter and ArgFormatter --- fmt/format.h | 42 +++++++++++++---------------------- fmt/printf.h | 7 +++--- test/custom-formatter-test.cc | 9 ++++---- test/format-test.cc | 9 ++++---- test/ostream-test.cc | 4 ++-- 5 files changed, 29 insertions(+), 42 deletions(-) diff --git a/fmt/format.h b/fmt/format.h index dd3ac296..26ed0bbf 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -1873,7 +1873,7 @@ void ArgMap::init(const basic_format_args &args) { } } -template +template class ArgFormatterBase { private: BasicWriter &writer_; @@ -2055,9 +2055,9 @@ class format_context_base { }; } // namespace internal -/** An argument formatter. */ -template -class BasicArgFormatter : public internal::ArgFormatterBase { +/** The default argument formatter. */ +template +class ArgFormatter : public internal::ArgFormatterBase { private: basic_format_context &ctx_; @@ -2065,31 +2065,21 @@ class BasicArgFormatter : public internal::ArgFormatterBase { /** \rst Constructs an argument formatter object. - *formatter* is a reference to the main formatter object, *spec* contains - format specifier information for standard argument types, and *fmt* points - to the part of the format string being parsed for custom argument types. + *writer* is a reference to the writer to be used for output, + *ctx* is a reference to the formatting context, *spec* contains + format specifier information for standard argument types. \endrst */ - BasicArgFormatter(BasicWriter &writer, basic_format_context &ctx, - FormatSpec &spec) - : internal::ArgFormatterBase(writer, spec), ctx_(ctx) {} - - using internal::ArgFormatterBase::operator(); - - /** Formats an argument of a custom (user-defined) type. */ - void operator()(internal::Arg::CustomValue c) { - c.format(&this->writer(), c.value, &ctx_); - } -}; - -/** The default argument formatter. */ -template -class ArgFormatter : public BasicArgFormatter, Char> { - public: - /** Constructs an argument formatter object. */ ArgFormatter(BasicWriter &writer, basic_format_context &ctx, FormatSpec &spec) - : BasicArgFormatter, Char>(writer, ctx, spec) {} + : internal::ArgFormatterBase(writer, spec), ctx_(ctx) {} + + using internal::ArgFormatterBase::operator(); + + /** Formats an argument of a custom (user-defined) type. */ + void operator()(format_arg::CustomValue c) { + c.format(&this->writer(), c.value, &ctx_); + } }; template @@ -2305,7 +2295,7 @@ class BasicWriter { template void append_float_length(Char *&, T) {} - template + template friend class internal::ArgFormatterBase; template diff --git a/fmt/printf.h b/fmt/printf.h index f0adf71c..30b80953 100644 --- a/fmt/printf.h +++ b/fmt/printf.h @@ -208,15 +208,14 @@ class WidthHandler { \endrst */ template -class PrintfArgFormatter : - public internal::ArgFormatterBase, Char> { +class PrintfArgFormatter : public internal::ArgFormatterBase { private: void write_null_pointer() { this->spec().type_ = 0; this->write("(nil)"); } - typedef internal::ArgFormatterBase, Char> Base; + typedef internal::ArgFormatterBase Base; public: /** @@ -227,7 +226,7 @@ class PrintfArgFormatter : \endrst */ PrintfArgFormatter(BasicWriter &writer, FormatSpec &spec) - : internal::ArgFormatterBase, Char>(writer, spec) {} + : internal::ArgFormatterBase(writer, spec) {} using Base::operator(); diff --git a/test/custom-formatter-test.cc b/test/custom-formatter-test.cc index 9c568523..7601aeb5 100644 --- a/test/custom-formatter-test.cc +++ b/test/custom-formatter-test.cc @@ -14,19 +14,18 @@ using fmt::PrintfArgFormatter; // A custom argument formatter that doesn't print `-` for floating-point values // rounded to 0. -class CustomArgFormatter - : public fmt::BasicArgFormatter { +class CustomArgFormatter : public fmt::ArgFormatter { public: CustomArgFormatter(fmt::Writer &w, fmt::basic_format_context &ctx, fmt::FormatSpec &s) - : fmt::BasicArgFormatter(w, ctx, s) {} + : fmt::ArgFormatter(w, ctx, s) {} - using fmt::BasicArgFormatter::operator(); + using fmt::ArgFormatter::operator(); void operator()(double value) { if (round(value * pow(10, spec().precision())) == 0) value = 0; - fmt::BasicArgFormatter::operator()(value); + fmt::ArgFormatter::operator()(value); } }; diff --git a/test/format-test.cc b/test/format-test.cc index 2ce9d7f3..b8e991b0 100644 --- a/test/format-test.cc +++ b/test/format-test.cc @@ -1619,17 +1619,16 @@ TEST(FormatTest, Enum) { EXPECT_EQ("0", fmt::format("{}", A)); } -class MockArgFormatter : - public fmt::internal::ArgFormatterBase { +class MockArgFormatter : public fmt::internal::ArgFormatterBase { private: MOCK_METHOD1(call, void (int value)); public: - typedef fmt::internal::ArgFormatterBase Base; + typedef fmt::internal::ArgFormatterBase Base; MockArgFormatter(fmt::Writer &w, fmt::format_context &ctx, fmt::FormatSpec &s) - : fmt::internal::ArgFormatterBase(w, s) { + : fmt::internal::ArgFormatterBase(w, s) { EXPECT_CALL(*this, call(42)); } @@ -1637,7 +1636,7 @@ class MockArgFormatter : void operator()(int value) { call(value); } - void operator()(fmt::internal::Arg::CustomValue) {} + void operator()(fmt::format_arg::CustomValue) {} }; void custom_vformat(fmt::CStringRef format_str, fmt::format_args args) { diff --git a/test/ostream-test.cc b/test/ostream-test.cc index d600714c..b46418b4 100644 --- a/test/ostream-test.cc +++ b/test/ostream-test.cc @@ -58,10 +58,10 @@ TEST(OStreamTest, Enum) { EXPECT_EQ("0", fmt::format("{}", A)); } -struct TestArgFormatter : fmt::BasicArgFormatter { +struct TestArgFormatter : fmt::ArgFormatter { TestArgFormatter(fmt::Writer &w, fmt::format_context &ctx, fmt::FormatSpec &s) - : fmt::BasicArgFormatter(w, ctx, s) {} + : fmt::ArgFormatter(w, ctx, s) {} }; TEST(OStreamTest, CustomArg) { From 41d4bcf0cc55b40fe6df80881a3b76ca0174ea76 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sun, 20 Nov 2016 10:11:12 -0800 Subject: [PATCH 049/340] Ingore Xcode files --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index c57070c5..b9ea0fea 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ bin/ /_CPack_Packages +/CMakeScripts /doc/doxyxml /doc/html virtualenv @@ -8,6 +9,7 @@ virtualenv *~ *.a *.so* +*.xcodeproj *.zip cmake_install.cmake CPack*.cmake @@ -15,5 +17,6 @@ fmt-*.cmake CTestTestfile.cmake CMakeCache.txt CMakeFiles +FMT.build Makefile run-msbuild.bat From 5f022ae081cde9084980b4d40fd26402248b1985 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sun, 20 Nov 2016 10:14:23 -0800 Subject: [PATCH 050/340] Remove FMT_DISPATCH --- fmt/format.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/fmt/format.h b/fmt/format.h index 26ed0bbf..bed2a706 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -1533,8 +1533,6 @@ class basic_format_args { typedef basic_format_args> format_args; typedef basic_format_args> wformat_args; -#define FMT_DISPATCH(call) static_cast(this)->call - /** \rst Visits an argument dispatching to the appropriate visit method based on From 9cf6c8fdc6ede9b59c04bf48bfc625ec282d89ec Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sat, 26 Nov 2016 10:21:31 -0800 Subject: [PATCH 051/340] Get rid of fmt::internal::Arg --- fmt/format.cc | 2 - fmt/format.h | 191 +++++++++++++++++++++------------------ fmt/printf.h | 36 ++++---- test/format-impl-test.cc | 8 +- test/util-test.cc | 52 +++++------ 5 files changed, 152 insertions(+), 137 deletions(-) diff --git a/fmt/format.cc b/fmt/format.cc index 5ec8e41b..499e8382 100644 --- a/fmt/format.cc +++ b/fmt/format.cc @@ -51,8 +51,6 @@ # endif #endif -using fmt::internal::Arg; - #if FMT_EXCEPTIONS # define FMT_TRY try # define FMT_CATCH(x) catch (x) diff --git a/fmt/format.h b/fmt/format.h index bed2a706..e03c66aa 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -1039,8 +1039,6 @@ struct format_arg : internal::Value { namespace internal { -typedef format_arg Arg; - template struct NamedArg; @@ -1180,61 +1178,80 @@ typedef Value::Type Type; template constexpr Type gettype() { + typedef format_arg Arg; return IsNamedArg::value ? Arg::NAMED_ARG : (ConvertToInt::value ? Arg::INT : Arg::CUSTOM); } -template <> constexpr Type gettype() { return Arg::BOOL; } -template <> constexpr Type gettype() { return Arg::INT; } -template <> constexpr Type gettype() { return Arg::UINT; } -template <> constexpr Type gettype() { return Arg::INT; } -template <> constexpr Type gettype() { return Arg::UINT; } +template <> constexpr Type gettype() { return format_arg::BOOL; } +template <> constexpr Type gettype() { return format_arg::INT; } +template <> constexpr Type gettype() { + return format_arg::UINT; +} +template <> constexpr Type gettype() { return format_arg::INT; } +template <> constexpr Type gettype() { return format_arg::UINT; } template <> constexpr Type gettype() { - return sizeof(long) == sizeof(int) ? Arg::INT : Arg::LONG_LONG; + return sizeof(long) == sizeof(int) ? format_arg::INT : format_arg::LONG_LONG; } template <> constexpr Type gettype() { return sizeof(unsigned long) == sizeof(unsigned) ? - Arg::UINT : Arg::ULONG_LONG; + format_arg::UINT : format_arg::ULONG_LONG; } -template <> constexpr Type gettype() { return Arg::LONG_LONG; } -template <> constexpr Type gettype() { return Arg::ULONG_LONG; } -template <> constexpr Type gettype() { return Arg::DOUBLE; } -template <> constexpr Type gettype() { return Arg::DOUBLE; } -template <> constexpr Type gettype() { return Arg::LONG_DOUBLE; } -template <> constexpr Type gettype() { return Arg::INT; } -template <> constexpr Type gettype() { return Arg::UINT; } -template <> constexpr Type gettype() { return Arg::CHAR; } +template <> constexpr Type gettype() { return format_arg::LONG_LONG; } +template <> constexpr Type gettype() { + return format_arg::ULONG_LONG; +} +template <> constexpr Type gettype() { return format_arg::DOUBLE; } +template <> constexpr Type gettype() { return format_arg::DOUBLE; } +template <> constexpr Type gettype() { + return format_arg::LONG_DOUBLE; +} +template <> constexpr Type gettype() { return format_arg::INT; } +template <> constexpr Type gettype() { return format_arg::UINT; } +template <> constexpr Type gettype() { return format_arg::CHAR; } #if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED) -template <> constexpr Type gettype() { return Arg::CHAR; } +template <> constexpr Type gettype() { return format_arg::CHAR; } #endif -template <> constexpr Type gettype() { return Arg::CSTRING; } -template <> constexpr Type gettype() { return Arg::CSTRING; } -template <> constexpr Type gettype() { return Arg::CSTRING; } +template <> constexpr Type gettype() { return format_arg::CSTRING; } +template <> constexpr Type gettype() { + return format_arg::CSTRING; +} +template <> constexpr Type gettype() { + return format_arg::CSTRING; +} template <> constexpr Type gettype() { - return Arg::CSTRING; + return format_arg::CSTRING; +} +template <> constexpr Type gettype() { + return format_arg::CSTRING; } -template <> constexpr Type gettype() { return Arg::CSTRING; } template <> constexpr Type gettype() { - return Arg::CSTRING; + return format_arg::CSTRING; +} +template <> constexpr Type gettype() { return format_arg::STRING; } +template <> constexpr Type gettype() { return format_arg::STRING; } +template <> constexpr Type gettype() { return format_arg::CSTRING; } +template <> constexpr Type gettype() { return format_arg::WSTRING; } +template <> constexpr Type gettype() { + return format_arg::WSTRING; +} +template <> constexpr Type gettype() { + return format_arg::WSTRING; +} +template <> constexpr Type gettype() { return format_arg::WSTRING; } +template <> constexpr Type gettype() { return format_arg::POINTER; } +template <> constexpr Type gettype() { + return format_arg::POINTER; } -template <> constexpr Type gettype() { return Arg::STRING; } -template <> constexpr Type gettype() { return Arg::STRING; } -template <> constexpr Type gettype() { return Arg::CSTRING; } -template <> constexpr Type gettype() { return Arg::WSTRING; } -template <> constexpr Type gettype() { return Arg::WSTRING; } -template <> constexpr Type gettype() { return Arg::WSTRING; } -template <> constexpr Type gettype() { return Arg::WSTRING; } -template <> constexpr Type gettype() { return Arg::POINTER; } -template <> constexpr Type gettype() { return Arg::POINTER; } template constexpr Type type() { return gettype::type>(); } -// Makes an Arg object from any type. +// Makes a format_arg object from any type. template -class MakeValue : public Arg { +class MakeValue : public format_arg { public: typedef typename Context::char_type Char; @@ -1387,27 +1404,27 @@ class MakeValue : public Arg { } }; -template -class MakeArg : public Arg { +template +class MakeArg : public format_arg { public: MakeArg() { - type = Arg::NONE; + type = format_arg::NONE; } template MakeArg(const T &value) - : Arg(MakeValue(value)) { + : format_arg(MakeValue(value)) { type = internal::type(); } }; template -struct NamedArg : Arg { +struct NamedArg : format_arg { BasicStringRef name; template NamedArg(BasicStringRef argname, const T &value) - : Arg(MakeArg< basic_format_context >(value)), name(argname) {} + : format_arg(MakeArg< basic_format_context >(value)), name(argname) {} }; class RuntimeError : public std::runtime_error { @@ -1438,7 +1455,7 @@ class format_arg_store { static const bool IS_PACKED = NUM_ARGS <= internal::MAX_PACKED_ARGS; typedef typename std::conditional< - IS_PACKED, internal::Value, internal::Arg>::type value_type; + IS_PACKED, internal::Value, format_arg>::type value_type; // If the arguments are not packed, add one more element to mark the end. std::array data_; @@ -1805,7 +1822,7 @@ template class ArgMap { private: typedef std::vector< - std::pair, internal::Arg> > MapType; + std::pair, format_arg> > MapType; typedef typename MapType::value_type Pair; MapType map_; @@ -1814,7 +1831,7 @@ class ArgMap { template void init(const basic_format_args &args); - const internal::Arg* find(const fmt::BasicStringRef &name) const { + const format_arg *find(const fmt::BasicStringRef &name) const { // The list is unsorted, so just return the first matching name. for (typename MapType::const_iterator it = map_.begin(), end = map_.end(); it != end; ++it) { @@ -1833,14 +1850,14 @@ void ArgMap::init(const basic_format_args &args) { typedef internal::NamedArg NamedArg; const NamedArg *named_arg = 0; bool use_values = - args.type(MAX_PACKED_ARGS - 1) == internal::Arg::NONE; + args.type(MAX_PACKED_ARGS - 1) == format_arg::NONE; if (use_values) { for (unsigned i = 0;/*nothing*/; ++i) { - internal::Arg::Type arg_type = args.type(i); + format_arg::Type arg_type = args.type(i); switch (arg_type) { - case internal::Arg::NONE: + case format_arg::NONE: return; - case internal::Arg::NAMED_ARG: + case format_arg::NAMED_ARG: named_arg = static_cast(args.values_[i].pointer); map_.push_back(Pair(named_arg->name, *named_arg)); break; @@ -1851,17 +1868,17 @@ void ArgMap::init(const basic_format_args &args) { return; } for (unsigned i = 0; i != MAX_PACKED_ARGS; ++i) { - internal::Arg::Type arg_type = args.type(i); - if (arg_type == internal::Arg::NAMED_ARG) { + format_arg::Type arg_type = args.type(i); + if (arg_type == format_arg::NAMED_ARG) { named_arg = static_cast(args.args_[i].pointer); map_.push_back(Pair(named_arg->name, *named_arg)); } } for (unsigned i = MAX_PACKED_ARGS;/*nothing*/; ++i) { switch (args.args_[i].type) { - case internal::Arg::NONE: + case format_arg::NONE: return; - case internal::Arg::NAMED_ARG: + case format_arg::NAMED_ARG: named_arg = static_cast(args.args_[i].pointer); map_.push_back(Pair(named_arg->name, *named_arg)); break; @@ -1886,18 +1903,18 @@ class ArgFormatterBase { } template - void write_str(Arg::StringValue value, - typename EnableIf< - std::is_same::value && - std::is_same::value, int>::type = 0) { + void write_str(format_arg::StringValue value, + typename EnableIf< + std::is_same::value && + std::is_same::value, int>::type = 0) { writer_.write_str(value, spec_); } template - void write_str(Arg::StringValue value, - typename EnableIf< - !std::is_same::value || - !std::is_same::value, int>::type = 0) { + void write_str(format_arg::StringValue value, + typename EnableIf< + !std::is_same::value || + !std::is_same::value, int>::type = 0) { // Do nothing. } @@ -1907,12 +1924,14 @@ class ArgFormatterBase { void write(bool value) { const char *str_value = value ? "true" : "false"; - Arg::StringValue str = { str_value, std::strlen(str_value) }; + format_arg::StringValue str = { str_value, std::strlen(str_value) }; writer_.write_str(str, spec_); } void write(const char *value) { - Arg::StringValue str = {value, value != 0 ? std::strlen(value) : 0}; + format_arg::StringValue str = { + value, value != 0 ? std::strlen(value) : 0 + }; writer_.write_str(str, spec_); } @@ -1972,11 +1991,11 @@ class ArgFormatterBase { write(value); } - void operator()(Arg::StringValue value) { + void operator()(format_arg::StringValue value) { writer_.write_str(value, spec_); } - void operator()(Arg::StringValue value) { + void operator()(format_arg::StringValue value) { write_str(value); } @@ -2273,7 +2292,7 @@ class BasicWriter { CharPtr write_str(const StrChar *s, std::size_t size, const AlignSpec &spec); template - void write_str(const internal::Arg::StringValue &str, + void write_str(const format_arg::StringValue &str, const FormatSpec &spec); // This following methods are private to disallow writing wide characters @@ -2497,7 +2516,7 @@ typename BasicWriter::CharPtr BasicWriter::write_str( template template void BasicWriter::write_str( - const internal::Arg::StringValue &s, const FormatSpec &spec) { + const format_arg::StringValue &s, const FormatSpec &spec) { // Check if StrChar is convertible to Char. internal::CharTraits::convert(StrChar()); if (spec.type_ && spec.type_ != 's') @@ -3262,8 +3281,8 @@ unsigned parse_nonnegative_int(const Char *&s) { return value; } -inline void require_numeric_argument(const Arg &arg, char spec) { - if (arg.type > Arg::LAST_NUMERIC_TYPE) { +inline void require_numeric_argument(const format_arg &arg, char spec) { + if (arg.type > format_arg::LAST_NUMERIC_TYPE) { std::string message = fmt::format("format specifier '{}' requires numeric argument", spec); FMT_THROW(fmt::format_error(message)); @@ -3271,10 +3290,10 @@ inline void require_numeric_argument(const Arg &arg, char spec) { } template -void check_sign(const Char *&s, const Arg &arg) { +void check_sign(const Char *&s, const format_arg &arg) { char sign = static_cast(*s); require_numeric_argument(arg, sign); - if (arg.type == Arg::UINT || arg.type == Arg::ULONG_LONG) { + if (arg.type == format_arg::UINT || arg.type == format_arg::ULONG_LONG) { FMT_THROW(format_error(fmt::format( "format specifier '{}' requires signed argument", sign))); } @@ -3287,7 +3306,7 @@ inline format_arg basic_format_context::get_arg( BasicStringRef name, const char *&error) { if (this->check_no_auto_index(error)) { map_.init(this->args()); - const internal::Arg *arg = map_.find(name); + const format_arg *arg = map_.find(name); if (arg) return *arg; error = "argument not found"; @@ -3322,13 +3341,12 @@ inline format_arg basic_format_context::parse_arg_id() { // Formats a single argument. template -void do_format_arg(BasicWriter &writer, const internal::Arg &arg, +void do_format_arg(BasicWriter &writer, const format_arg &arg, Context &ctx) { - using internal::Arg; const Char *&s = ctx.ptr(); FormatSpec spec; if (*s == ':') { - if (arg.type == Arg::CUSTOM) { + if (arg.type == format_arg::CUSTOM) { arg.custom.format(&writer, arg.custom.value, &ctx); return; } @@ -3402,25 +3420,25 @@ void do_format_arg(BasicWriter &writer, const internal::Arg &arg, spec.width_ = internal::parse_nonnegative_int(s); } else if (*s == '{') { ++s; - Arg width_arg = ctx.parse_arg_id(); + format_arg width_arg = ctx.parse_arg_id(); if (*s++ != '}') FMT_THROW(format_error("invalid format string")); ULongLong value = 0; switch (width_arg.type) { - case Arg::INT: + case format_arg::INT: if (width_arg.int_value < 0) FMT_THROW(format_error("negative width")); value = width_arg.int_value; break; - case Arg::UINT: + case format_arg::UINT: value = width_arg.uint_value; break; - case Arg::LONG_LONG: + case format_arg::LONG_LONG: if (width_arg.long_long_value < 0) FMT_THROW(format_error("negative width")); value = width_arg.long_long_value; break; - case Arg::ULONG_LONG: + case format_arg::ULONG_LONG: value = width_arg.ulong_long_value; break; default: @@ -3439,25 +3457,25 @@ void do_format_arg(BasicWriter &writer, const internal::Arg &arg, spec.precision_ = internal::parse_nonnegative_int(s); } else if (*s == '{') { ++s; - Arg precision_arg = ctx.parse_arg_id(); + format_arg precision_arg = ctx.parse_arg_id(); if (*s++ != '}') FMT_THROW(format_error("invalid format string")); ULongLong value = 0; switch (precision_arg.type) { - case Arg::INT: + case format_arg::INT: if (precision_arg.int_value < 0) FMT_THROW(format_error("negative precision")); value = precision_arg.int_value; break; - case Arg::UINT: + case format_arg::UINT: value = precision_arg.uint_value; break; - case Arg::LONG_LONG: + case format_arg::LONG_LONG: if (precision_arg.long_long_value < 0) FMT_THROW(format_error("negative precision")); value = precision_arg.long_long_value; break; - case Arg::ULONG_LONG: + case format_arg::ULONG_LONG: value = precision_arg.ulong_long_value; break; default: @@ -3469,10 +3487,11 @@ void do_format_arg(BasicWriter &writer, const internal::Arg &arg, } else { FMT_THROW(format_error("missing precision specifier")); } - if (arg.type <= Arg::LAST_INTEGER_TYPE || arg.type == Arg::POINTER) { + if (arg.type <= format_arg::LAST_INTEGER_TYPE || + arg.type == format_arg::POINTER) { FMT_THROW(format_error( fmt::format("precision not allowed in {} format specifier", - arg.type == Arg::POINTER ? "pointer" : "integer"))); + arg.type == format_arg::POINTER ? "pointer" : "integer"))); } } diff --git a/fmt/printf.h b/fmt/printf.h index 30b80953..386acf98 100644 --- a/fmt/printf.h +++ b/fmt/printf.h @@ -83,11 +83,11 @@ struct is_same { template class ArgConverter { private: - internal::Arg &arg_; + format_arg &arg_; wchar_t type_; public: - ArgConverter(internal::Arg &arg, wchar_t type) + ArgConverter(format_arg &arg, wchar_t type) : arg_(arg), type_(type) {} void operator()(bool value) { @@ -99,28 +99,27 @@ class ArgConverter { typename std::enable_if::value>::type operator()(U value) { bool is_signed = type_ == 'd' || type_ == 'i'; - using internal::Arg; typedef typename internal::Conditional< is_same::value, U, T>::type TargetType; if (sizeof(TargetType) <= sizeof(int)) { // Extra casts are used to silence warnings. if (is_signed) { - arg_.type = Arg::INT; + arg_.type = format_arg::INT; arg_.int_value = static_cast(static_cast(value)); } else { - arg_.type = Arg::UINT; + arg_.type = format_arg::UINT; typedef typename internal::MakeUnsigned::Type Unsigned; arg_.uint_value = static_cast(static_cast(value)); } } else { if (is_signed) { - arg_.type = Arg::LONG_LONG; + arg_.type = format_arg::LONG_LONG; // glibc's printf doesn't sign extend arguments of smaller types: // std::printf("%lld", -42); // prints "4294967254" // but we don't have to do the same because it's a UB. arg_.long_long_value = static_cast(value); } else { - arg_.type = Arg::ULONG_LONG; + arg_.type = format_arg::ULONG_LONG; arg_.ulong_long_value = static_cast::Type>(value); } @@ -146,17 +145,17 @@ void convert_arg(format_arg &arg, wchar_t type) { // Converts an integer argument to char for printf. class CharConverter { private: - internal::Arg &arg_; + format_arg &arg_; FMT_DISALLOW_COPY_AND_ASSIGN(CharConverter); public: - explicit CharConverter(internal::Arg &arg) : arg_(arg) {} + explicit CharConverter(format_arg &arg) : arg_(arg) {} template typename std::enable_if::value>::type operator()(T value) { - arg_.type = internal::Arg::CHAR; + arg_.type = format_arg::CHAR; arg_.int_value = static_cast(value); } @@ -281,7 +280,7 @@ class PrintfArgFormatter : public internal::ArgFormatterBase { } /** Formats an argument of a custom (user-defined) type. */ - void operator()(internal::Arg::CustomValue c) { + void operator()(format_arg::CustomValue c) { const Char format_str[] = {'}', '\0'}; auto args = basic_format_args>(); basic_format_context ctx(format_str, args); @@ -306,7 +305,7 @@ class printf_context : // Returns the argument with specified index or, if arg_index is equal // to the maximum unsigned value, the next argument. - internal::Arg get_arg( + format_arg get_arg( const Char *s, unsigned arg_index = (std::numeric_limits::max)()); @@ -356,11 +355,11 @@ void printf_context::parse_flags(FormatSpec &spec, const Char *&s) { } template -internal::Arg printf_context::get_arg(const Char *s, - unsigned arg_index) { +format_arg printf_context::get_arg(const Char *s, + unsigned arg_index) { (void)s; const char *error = 0; - internal::Arg arg = arg_index == std::numeric_limits::max() ? + format_arg arg = arg_index == std::numeric_limits::max() ? this->next_arg(error) : Base::get_arg(arg_index - 1, error); if (error) FMT_THROW(format_error(!*s ? "invalid format string" : error)); @@ -432,12 +431,11 @@ void printf_context::format(BasicWriter &writer) { } } - using internal::Arg; - Arg arg = get_arg(s, arg_index); + format_arg arg = get_arg(s, arg_index); if (spec.flag(HASH_FLAG) && visit(internal::IsZeroInt(), arg)) spec.flags_ &= ~internal::to_unsigned(HASH_FLAG); if (spec.fill_ == '0') { - if (arg.type <= Arg::LAST_NUMERIC_TYPE) + if (arg.type <= format_arg::LAST_NUMERIC_TYPE) spec.align_ = ALIGN_NUMERIC; else spec.fill_ = ' '; // Ignore '0' flag for non-numeric types. @@ -480,7 +478,7 @@ void printf_context::format(BasicWriter &writer) { if (!*s) FMT_THROW(format_error("invalid format string")); spec.type_ = static_cast(*s++); - if (arg.type <= Arg::LAST_INTEGER_TYPE) { + if (arg.type <= format_arg::LAST_INTEGER_TYPE) { // Normalize type. switch (spec.type_) { case 'i': case 'u': diff --git a/test/format-impl-test.cc b/test/format-impl-test.cc index 4ad2bccf..c63b6b97 100644 --- a/test/format-impl-test.cc +++ b/test/format-impl-test.cc @@ -42,12 +42,12 @@ #undef max TEST(FormatTest, ArgConverter) { - using fmt::internal::Arg; - Arg arg = Arg(); - arg.type = Arg::LONG_LONG; + using fmt::format_arg; + format_arg arg = format_arg(); + arg.type = format_arg::LONG_LONG; arg.long_long_value = std::numeric_limits::max(); visit(fmt::internal::ArgConverter(arg, 'd'), arg); - EXPECT_EQ(Arg::LONG_LONG, arg.type); + EXPECT_EQ(format_arg::LONG_LONG, arg.type); } TEST(FormatTest, FormatNegativeNaN) { diff --git a/test/util-test.cc b/test/util-test.cc index 2b144b95..3371ef20 100644 --- a/test/util-test.cc +++ b/test/util-test.cc @@ -51,9 +51,9 @@ #undef max -using fmt::StringRef; -using fmt::internal::Arg; +using fmt::format_arg; using fmt::Buffer; +using fmt::StringRef; using fmt::internal::MemoryBuffer; using testing::Return; @@ -70,9 +70,9 @@ void format_value(fmt::BasicWriter &w, Test, } template -Arg make_arg(const T &value) { +format_arg make_arg(const T &value) { typedef fmt::internal::MakeValue< fmt::basic_format_context > MakeValue; - Arg arg = MakeValue(value); + format_arg arg = MakeValue(value); arg.type = fmt::internal::type(); return arg; } @@ -406,13 +406,13 @@ TEST(UtilTest, Increment) { EXPECT_STREQ("200", s); } -template +template struct ArgInfo; #define ARG_INFO(type_code, Type, field) \ template <> \ - struct ArgInfo { \ - static Type get(const Arg &arg) { return arg.field; } \ + struct ArgInfo { \ + static Type get(const format_arg &arg) { return arg.field; } \ } ARG_INFO(INT, int, int_value); @@ -427,12 +427,12 @@ ARG_INFO(CSTRING, const char *, string.value); ARG_INFO(STRING, const char *, string.value); ARG_INFO(WSTRING, const wchar_t *, wstring.value); ARG_INFO(POINTER, const void *, pointer); -ARG_INFO(CUSTOM, Arg::CustomValue, custom); +ARG_INFO(CUSTOM, format_arg::CustomValue, custom); #define CHECK_ARG_INFO(Type, field, value) { \ - Arg arg = Arg(); \ + format_arg arg = format_arg(); \ arg.field = value; \ - EXPECT_EQ(value, ArgInfo::get(arg)); \ + EXPECT_EQ(value, ArgInfo::get(arg)); \ } TEST(ArgTest, ArgInfo) { @@ -449,17 +449,17 @@ TEST(ArgTest, ArgInfo) { CHECK_ARG_INFO(WSTRING, wstring.value, WSTR); int p = 0; CHECK_ARG_INFO(POINTER, pointer, &p); - Arg arg = Arg(); + format_arg arg = format_arg(); arg.custom.value = &p; - EXPECT_EQ(&p, ArgInfo::get(arg).value); + EXPECT_EQ(&p, ArgInfo::get(arg).value); } #define EXPECT_ARG_(Char, type_code, MakeArgType, ExpectedType, value) { \ MakeArgType input = static_cast(value); \ - Arg arg = make_arg(input); \ - EXPECT_EQ(Arg::type_code, arg.type); \ + format_arg arg = make_arg(input); \ + EXPECT_EQ(format_arg::type_code, arg.type); \ ExpectedType expected_value = static_cast(value); \ - EXPECT_EQ(expected_value, ArgInfo::get(arg)); \ + EXPECT_EQ(expected_value, ArgInfo::get(arg)); \ } #define EXPECT_ARG(type_code, Type, value) \ @@ -563,8 +563,8 @@ TEST(ArgTest, MakeArg) { EXPECT_ARG(POINTER, const void*, &n); ::Test t; - Arg arg = make_arg(t); - EXPECT_EQ(fmt::internal::Arg::CUSTOM, arg.type); + format_arg arg = make_arg(t); + EXPECT_EQ(format_arg::CUSTOM, arg.type); EXPECT_EQ(&t, arg.custom.value); fmt::MemoryWriter w; fmt::format_context ctx("}", fmt::format_args()); @@ -574,7 +574,7 @@ TEST(ArgTest, MakeArg) { TEST(UtilTest, FormatArgs) { fmt::format_args args; - EXPECT_EQ(Arg::NONE, args[1].type); + EXPECT_EQ(format_arg::NONE, args[1].type); } struct CustomFormatter { @@ -588,7 +588,7 @@ void format_value(fmt::Writer &, const Test &, CustomFormatter &ctx) { TEST(UtilTest, MakeValueWithCustomFormatter) { ::Test t; - Arg arg = fmt::internal::MakeValue(t); + format_arg arg = fmt::internal::MakeValue(t); CustomFormatter ctx = {false}; fmt::MemoryWriter w; arg.custom.format(&w, &t, &ctx); @@ -596,7 +596,7 @@ TEST(UtilTest, MakeValueWithCustomFormatter) { } struct Result { - Arg arg; + format_arg arg; Result() : arg(make_arg(0xdeadbeef)) {} @@ -627,10 +627,10 @@ struct TestVisitor { }; #define EXPECT_RESULT_(Char, type_code, value) { \ - Arg arg = make_arg(value); \ + format_arg arg = make_arg(value); \ Result result = fmt::visit(TestVisitor(), arg); \ - EXPECT_EQ(Arg::type_code, result.arg.type); \ - EXPECT_EQ(value, ArgInfo::get(result.arg)); \ + EXPECT_EQ(format_arg::type_code, result.arg.type); \ + EXPECT_EQ(value, ArgInfo::get(result.arg)); \ } #define EXPECT_RESULT(type_code, value) \ @@ -654,13 +654,13 @@ TEST(ArgVisitorTest, VisitAll) { EXPECT_RESULT(POINTER, p); ::Test t; Result result = visit(TestVisitor(), make_arg(t)); - EXPECT_EQ(Arg::CUSTOM, result.arg.type); + EXPECT_EQ(format_arg::CUSTOM, result.arg.type); EXPECT_EQ(&t, result.arg.custom.value); } TEST(ArgVisitorTest, VisitInvalidArg) { - Arg arg = Arg(); - arg.type = static_cast(Arg::NONE); + format_arg arg = format_arg(); + arg.type = static_cast(format_arg::NONE); EXPECT_ASSERT(visit(TestVisitor(), arg), "invalid argument type"); } From 0854f8c3bf8e9bdacc12a33831e58e4f4c6f7452 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sun, 11 Dec 2016 13:22:45 -0800 Subject: [PATCH 052/340] Parameterize formatting argument on char type. --- fmt/format.cc | 5 +- fmt/format.h | 496 ++++++++++++++++++++-------------- fmt/printf.h | 97 +++---- test/custom-formatter-test.cc | 2 +- test/format-impl-test.cc | 22 +- test/util-test.cc | 388 +++++++++++--------------- 6 files changed, 515 insertions(+), 495 deletions(-) diff --git a/fmt/format.cc b/fmt/format.cc index 499e8382..3e2a6eec 100644 --- a/fmt/format.cc +++ b/fmt/format.cc @@ -443,8 +443,7 @@ template void printf(BasicWriter &w, BasicCStringRef format, format_args args); -FMT_FUNC int vfprintf(std::FILE *f, CStringRef format, - basic_format_args> args) { +FMT_FUNC int vfprintf(std::FILE *f, CStringRef format, printf_args args) { MemoryWriter w; printf(w, format, args); std::size_t size = w.size(); @@ -475,7 +474,7 @@ template int internal::CharTraits::format_float( template void internal::FixedBuffer::grow(std::size_t); -template void internal::ArgMap::init(const format_args &args); +template void internal::ArgMap::init(const wformat_args &args); template void printf_context::format(WWriter &writer); diff --git a/fmt/format.h b/fmt/format.h index e03c66aa..ed706466 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -414,6 +414,8 @@ class BasicStringRef { std::size_t size_; public: + BasicStringRef() : data_(0), size_(0) {} + /** Constructs a string reference object from a C string and a size. */ BasicStringRef(const Char *s, std::size_t size) : data_(s), size_(size) {} @@ -1027,16 +1029,102 @@ struct Value { CSTRING, STRING, WSTRING, POINTER, CUSTOM }; }; + +template +class ArgMap; } // namespace internal +template +class basic_format_args; + // A formatting argument. It is a trivially copyable/constructible type to // allow storage in internal::MemoryBuffer. -struct format_arg : internal::Value { - Type type; +template +class basic_format_arg : public internal::Value { + protected: + Type type_; - explicit operator bool() const noexcept { return type != NONE; } + template + friend typename std::result_of::type + visit(Visitor &&vis, basic_format_arg arg); + + template + friend class basic_format_args; + + template + friend class internal::ArgMap; + + void check_type() const { + FMT_ASSERT(type_ > NAMED_ARG, "invalid argument type"); + } + + public: + explicit operator bool() const noexcept { return type_ != NONE; } + + bool is_integral() const { + check_type(); + return type_ <= LAST_INTEGER_TYPE; + } + + bool is_numeric() const { + check_type(); + return type_ <= LAST_NUMERIC_TYPE; + } + + bool is_pointer() const { + check_type(); + return type_ == POINTER; + } }; +typedef basic_format_arg format_arg; +typedef basic_format_arg wformat_arg; + +/** + \rst + Visits an argument dispatching to the appropriate visit method based on + the argument type. For example, if the argument type is ``double`` then + ``vis(value)`` will be called with the value of type ``double``. + \endrst + */ +template +typename std::result_of::type + visit(Visitor &&vis, basic_format_arg arg) { + switch (arg.type_) { + case format_arg::NONE: + case format_arg::NAMED_ARG: + FMT_ASSERT(false, "invalid argument type"); + break; + case format_arg::INT: + return vis(arg.int_value); + case format_arg::UINT: + return vis(arg.uint_value); + case format_arg::LONG_LONG: + return vis(arg.long_long_value); + case format_arg::ULONG_LONG: + return vis(arg.ulong_long_value); + case format_arg::BOOL: + return vis(arg.int_value != 0); + case format_arg::CHAR: + return vis(static_cast(arg.int_value)); + case format_arg::DOUBLE: + return vis(arg.double_value); + case format_arg::LONG_DOUBLE: + return vis(arg.long_double_value); + case format_arg::CSTRING: + return vis(arg.string.value); + case format_arg::STRING: + return vis(arg.string); + case format_arg::WSTRING: + return vis(arg.wstring); + case format_arg::POINTER: + return vis(arg.pointer); + case format_arg::CUSTOM: + return vis(arg.custom); + } + return typename std::result_of::type(); +} + namespace internal { template @@ -1251,7 +1339,7 @@ constexpr Type type() { return gettype::type>(); } // Makes a format_arg object from any type. template -class MakeValue : public format_arg { +class MakeValue : public basic_format_arg { public: typedef typename Context::char_type Char; @@ -1279,13 +1367,13 @@ class MakeValue : public format_arg { MakeValue(typename WCharHelper::Unsupported); void set_string(StringRef str) { - string.value = str.data(); - string.size = str.size(); + this->string.value = str.data(); + this->string.size = str.size(); } void set_string(WStringRef str) { - wstring.value = str.data(); - wstring.size = str.size(); + this->wstring.value = str.data(); + this->wstring.size = str.size(); } // Formats an argument of a custom type, such as a user-defined class. @@ -1302,8 +1390,8 @@ class MakeValue : public format_arg { #define FMT_MAKE_VALUE_(Type, field, TYPE, rhs) \ MakeValue(Type value) { \ - static_assert(internal::type() == TYPE, "invalid type"); \ - field = rhs; \ + static_assert(internal::type() == MakeValue::TYPE, "invalid type"); \ + this->field = rhs; \ } #define FMT_MAKE_VALUE(Type, field, TYPE) \ @@ -1319,16 +1407,16 @@ class MakeValue : public format_arg { // To minimize the number of types we need to deal with, long is // translated either to int or to long long depending on its size. if (const_check(sizeof(long) == sizeof(int))) - int_value = static_cast(value); + this->int_value = static_cast(value); else - long_long_value = value; + this->long_long_value = value; } MakeValue(unsigned long value) { if (const_check(sizeof(unsigned long) == sizeof(unsigned))) - uint_value = static_cast(value); + this->uint_value = static_cast(value); else - ulong_long_value = value; + this->ulong_long_value = value; } FMT_MAKE_VALUE(LongLong, long_long_value, LONG_LONG) @@ -1343,14 +1431,14 @@ class MakeValue : public format_arg { #if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED) typedef typename WCharHelper::Supported WChar; MakeValue(WChar value) { - static_assert(internal::type() == CHAR, "invalid type"); - int_value = value; + static_assert(internal::type() == MakeValue::CHAR, "invalid type"); + this->int_value = value; } #endif #define FMT_MAKE_STR_VALUE(Type, TYPE) \ MakeValue(Type value) { \ - static_assert(internal::type() == TYPE, "invalid type"); \ + static_assert(internal::type() == MakeValue::TYPE, "invalid type"); \ set_string(value); \ } @@ -1366,7 +1454,7 @@ class MakeValue : public format_arg { #define FMT_MAKE_WSTR_VALUE(Type, TYPE) \ MakeValue(typename WCharHelper::Supported value) { \ - static_assert(internal::type() == TYPE, "invalid type"); \ + static_assert(internal::type() == MakeValue::TYPE, "invalid type"); \ set_string(value); \ } @@ -1382,49 +1470,51 @@ class MakeValue : public format_arg { MakeValue(const T &value, typename EnableIf::value>::value, int>::type = 0) { - static_assert(internal::type() == CUSTOM, "invalid type"); - custom.value = &value; - custom.format = &format_custom_arg; + static_assert(internal::type() == MakeValue::CUSTOM, "invalid type"); + this->custom.value = &value; + this->custom.format = &format_custom_arg; } template MakeValue(const T &value, typename EnableIf::value, int>::type = 0) { - static_assert(internal::type() == INT, "invalid type"); - int_value = value; + static_assert(internal::type() == MakeValue::INT, "invalid type"); + this->int_value = value; } // Additional template param `Char_` is needed here because make_type always // uses char. template MakeValue(const NamedArg &value) { - static_assert(internal::type &>() == NAMED_ARG, - "invalid type"); - pointer = &value; + static_assert( + internal::type &>() == MakeValue::NAMED_ARG, + "invalid type"); + this->pointer = &value; } }; template -class MakeArg : public format_arg { + class MakeArg : public basic_format_arg { public: MakeArg() { - type = format_arg::NONE; + this->type_ = format_arg::NONE; } template MakeArg(const T &value) - : format_arg(MakeValue(value)) { - type = internal::type(); + : basic_format_arg(MakeValue(value)) { + this->type_ = internal::type(); } }; template -struct NamedArg : format_arg { +struct NamedArg : basic_format_arg { BasicStringRef name; template NamedArg(BasicStringRef argname, const T &value) - : format_arg(MakeArg< basic_format_context >(value)), name(argname) {} + : basic_format_arg(MakeArg< basic_format_context >(value)), + name(argname) {} }; class RuntimeError : public std::runtime_error { @@ -1433,9 +1523,6 @@ class RuntimeError : public std::runtime_error { ~RuntimeError() throw(); }; -template -class ArgMap; - template constexpr uint64_t make_type() { return type() | (make_type() << 4); @@ -1482,8 +1569,12 @@ inline format_arg_store } /** Formatting arguments. */ -template +template class basic_format_args { + public: + typedef unsigned size_type; + typedef basic_format_arg format_arg; + private: // To reduce compiled code size per formatting function call, types of first // MAX_PACKED_ARGS arguments are passed in the types_ field. @@ -1498,21 +1589,43 @@ class basic_format_args { const format_arg *args_; }; - format_arg::Type type(unsigned index) const { + typename format_arg::Type type(unsigned index) const { unsigned shift = index * 4; uint64_t mask = 0xf; - return static_cast((types_ & (mask << shift)) >> shift); + return static_cast( + (types_ & (mask << shift)) >> shift); } - template - friend class internal::ArgMap; + friend class internal::ArgMap; void set_data(const internal::Value *values) { values_ = values; } void set_data(const format_arg *args) { args_ = args; } - public: - typedef unsigned size_type; + format_arg get(size_type index) const { + format_arg arg; + bool use_values = type(internal::MAX_PACKED_ARGS - 1) == format_arg::NONE; + if (index < internal::MAX_PACKED_ARGS) { + typename format_arg::Type arg_type = type(index); + internal::Value &val = arg; + if (arg_type != format_arg::NONE) + val = use_values ? values_[index] : args_[index]; + arg.type_ = arg_type; + return arg; + } + if (use_values) { + // The index is greater than the number of arguments that can be stored + // in values, so return a "none" argument. + arg.type_ = format_arg::NONE; + return arg; + } + for (unsigned i = internal::MAX_PACKED_ARGS; i <= index; ++i) { + if (args_[i].type_ == format_arg::NONE) + return args_[i]; + } + return args_[index]; + } + public: basic_format_args() : types_(0) {} template @@ -1523,77 +1636,14 @@ class basic_format_args { /** Returns the argument at specified index. */ format_arg operator[](size_type index) const { - format_arg arg; - bool use_values = type(internal::MAX_PACKED_ARGS - 1) == format_arg::NONE; - if (index < internal::MAX_PACKED_ARGS) { - format_arg::Type arg_type = type(index); - internal::Value &val = arg; - if (arg_type != format_arg::NONE) - val = use_values ? values_[index] : args_[index]; - arg.type = arg_type; - return arg; - } - if (use_values) { - // The index is greater than the number of arguments that can be stored - // in values, so return a "none" argument. - arg.type = format_arg::NONE; - return arg; - } - for (unsigned i = internal::MAX_PACKED_ARGS; i <= index; ++i) { - if (args_[i].type == format_arg::NONE) - return args_[i]; - } - return args_[index]; + format_arg arg = get(index); + return arg.type_ == format_arg::NAMED_ARG ? + *static_cast(arg.pointer) : arg; } }; -typedef basic_format_args> format_args; -typedef basic_format_args> wformat_args; - -/** - \rst - Visits an argument dispatching to the appropriate visit method based on - the argument type. For example, if the argument type is ``double`` then - ``vis(value)`` will be called with the value of type ``double``. - \endrst - */ -template -typename std::result_of::type visit(Visitor &&vis, - format_arg arg) { - switch (arg.type) { - case format_arg::NONE: - case format_arg::NAMED_ARG: - FMT_ASSERT(false, "invalid argument type"); - break; - case format_arg::INT: - return vis(arg.int_value); - case format_arg::UINT: - return vis(arg.uint_value); - case format_arg::LONG_LONG: - return vis(arg.long_long_value); - case format_arg::ULONG_LONG: - return vis(arg.ulong_long_value); - case format_arg::BOOL: - return vis(arg.int_value != 0); - case format_arg::CHAR: - return vis(static_cast(arg.int_value)); - case format_arg::DOUBLE: - return vis(arg.double_value); - case format_arg::LONG_DOUBLE: - return vis(arg.long_double_value); - case format_arg::CSTRING: - return vis(arg.string.value); - case format_arg::STRING: - return vis(arg.string); - case format_arg::WSTRING: - return vis(arg.wstring); - case format_arg::POINTER: - return vis(arg.pointer); - case format_arg::CUSTOM: - return vis(arg.custom); - } - return typename std::result_of::type(); -} +typedef basic_format_args, char> format_args; +typedef basic_format_args, wchar_t> wformat_args; enum Alignment { ALIGN_DEFAULT, ALIGN_LEFT, ALIGN_RIGHT, ALIGN_CENTER, ALIGN_NUMERIC @@ -1822,16 +1872,17 @@ template class ArgMap { private: typedef std::vector< - std::pair, format_arg> > MapType; + std::pair, basic_format_arg > > MapType; typedef typename MapType::value_type Pair; MapType map_; public: - template - void init(const basic_format_args &args); + template + void init(const basic_format_args &args); - const format_arg *find(const fmt::BasicStringRef &name) const { + const basic_format_arg + *find(const fmt::BasicStringRef &name) const { // The list is unsorted, so just return the first matching name. for (typename MapType::const_iterator it = map_.begin(), end = map_.end(); it != end; ++it) { @@ -1843,8 +1894,8 @@ class ArgMap { }; template -template -void ArgMap::init(const basic_format_args &args) { +template +void ArgMap::init(const basic_format_args &args) { if (!map_.empty()) return; typedef internal::NamedArg NamedArg; @@ -1874,8 +1925,8 @@ void ArgMap::init(const basic_format_args &args) { map_.push_back(Pair(named_arg->name, *named_arg)); } } - for (unsigned i = MAX_PACKED_ARGS;/*nothing*/; ++i) { - switch (args.args_[i].type) { + for (unsigned i = MAX_PACKED_ARGS; ; ++i) { + switch (args.args_[i].type_) { case format_arg::NONE: return; case format_arg::NAMED_ARG: @@ -1955,7 +2006,7 @@ class ArgFormatterBase { write(value); } - void operator()(wchar_t value) { + void operator()(Char value) { if (spec_.type_ && spec_.type_ != 'c') { spec_.flags_ |= CHAR_FLAG; writer_.write_int(value, spec_); @@ -2016,29 +2067,24 @@ template class format_context_base { private: const Char *ptr_; - basic_format_args args_; + basic_format_args args_; int next_arg_index_; protected: - format_context_base(const Char *format_str, basic_format_args args) + typedef basic_format_arg format_arg; + + format_context_base(const Char *format_str, + basic_format_args args) : ptr_(format_str), args_(args), next_arg_index_(0) {} ~format_context_base() {} - basic_format_args args() const { return args_; } + basic_format_args args() const { return args_; } // Returns the argument with specified index. format_arg do_get_arg(unsigned arg_index, const char *&error) { format_arg arg = args_[arg_index]; - switch (arg.type) { - case format_arg::NONE: - error = "argument index out of range"; - break; - case format_arg::NAMED_ARG: - arg = *static_cast(arg.pointer); - break; - default: - /*nothing*/; - } + if (!arg) + error = "argument index out of range"; return arg; } @@ -2107,13 +2153,14 @@ class basic_format_context : FMT_DISALLOW_COPY_AND_ASSIGN(basic_format_context); - typedef internal::format_context_base Base; + typedef internal::format_context_base> Base; + using typename Base::format_arg; using Base::get_arg; // Checks if manual indexing is used and returns the argument with // specified name. - format_arg get_arg(BasicStringRef name, const char *&error); + basic_format_arg get_arg(BasicStringRef name, const char *&error); public: /** The character type for the output. */ @@ -2126,11 +2173,11 @@ class basic_format_context : \endrst */ basic_format_context(const Char *format_str, - basic_format_args args) + basic_format_args args) : Base(format_str, args) {} // Parses argument id and returns corresponding argument. - format_arg parse_arg_id(); + basic_format_arg parse_arg_id(); using Base::ptr; }; @@ -2364,7 +2411,7 @@ class BasicWriter { } void vwrite(BasicCStringRef format, - basic_format_args> args); + basic_format_args, Char> args); /** \rst Writes formatted data. @@ -3281,45 +3328,121 @@ unsigned parse_nonnegative_int(const Char *&s) { return value; } -inline void require_numeric_argument(const format_arg &arg, char spec) { - if (arg.type > format_arg::LAST_NUMERIC_TYPE) { - std::string message = - fmt::format("format specifier '{}' requires numeric argument", spec); - FMT_THROW(fmt::format_error(message)); +template +inline void require_numeric_argument( + const basic_format_arg &arg, char spec) { + if (!arg.is_numeric()) { + FMT_THROW(fmt::format_error( + fmt::format("format specifier '{}' requires numeric argument", spec))); } } +struct IsUnsigned { + template + typename std::enable_if::value, bool>::type + operator()(T value) { + return true; + } + + template + typename std::enable_if::value, bool>::type + operator()(T value) { + return false; + } +}; + template -void check_sign(const Char *&s, const format_arg &arg) { +void check_sign(const Char *&s, const basic_format_arg &arg) { char sign = static_cast(*s); require_numeric_argument(arg, sign); - if (arg.type == format_arg::UINT || arg.type == format_arg::ULONG_LONG) { + if (visit(IsUnsigned(), arg)) { FMT_THROW(format_error(fmt::format( "format specifier '{}' requires signed argument", sign))); } ++s; } + +template +class CustomFormatter { + private: + BasicWriter &writer_; + Context &ctx_; + + public: + CustomFormatter(BasicWriter &writer, Context &ctx) + : writer_(writer), ctx_(ctx) {} + + bool operator()(format_arg::CustomValue custom) { + custom.format(&writer_, custom.value, &ctx_); + return true; + } + + template + bool operator()(T) { return false; } +}; + +template +struct IsInteger { + enum { + value = std::is_integral::value && !std::is_same::value && + !std::is_same::value && !std::is_same::value + }; +}; + +struct WidthHandler { + template + typename std::enable_if::value, ULongLong>::type + operator()(T value) { + if (is_negative(value)) + FMT_THROW(format_error("negative width")); + return value; + } + + template + typename std::enable_if::value, ULongLong>::type + operator()(T value) { + FMT_THROW(format_error("width is not integer")); + return 0; + } +}; + +struct PrecisionHandler { + template + typename std::enable_if::value, ULongLong>::type + operator()(T value) { + if (is_negative(value)) + FMT_THROW(format_error("negative precision")); + return value; + } + + template + typename std::enable_if::value, ULongLong>::type + operator()(T value) { + FMT_THROW(format_error("precision is not integer")); + return 0; + } +}; } // namespace internal template -inline format_arg basic_format_context::get_arg( +inline basic_format_arg basic_format_context::get_arg( BasicStringRef name, const char *&error) { if (this->check_no_auto_index(error)) { map_.init(this->args()); - const format_arg *arg = map_.find(name); + const basic_format_arg *arg = map_.find(name); if (arg) return *arg; error = "argument not found"; } - return format_arg(); + return basic_format_arg(); } template -inline format_arg basic_format_context::parse_arg_id() { +inline basic_format_arg basic_format_context::parse_arg_id() { const Char *&s = this->ptr(); if (!internal::is_name_start(*s)) { const char *error = 0; - format_arg arg = *s < '0' || *s > '9' ? + basic_format_arg arg = *s < '0' || *s > '9' ? this->next_arg(error) : get_arg(internal::parse_nonnegative_int(s), error); if (error) { FMT_THROW(format_error( @@ -3333,7 +3456,8 @@ inline format_arg basic_format_context::parse_arg_id() { c = *++s; } while (internal::is_name_start(c) || ('0' <= c && c <= '9')); const char *error = 0; - format_arg arg = get_arg(BasicStringRef(start, s - start), error); + basic_format_arg arg = + get_arg(BasicStringRef(start, s - start), error); if (error) FMT_THROW(format_error(error)); return arg; @@ -3341,15 +3465,13 @@ inline format_arg basic_format_context::parse_arg_id() { // Formats a single argument. template -void do_format_arg(BasicWriter &writer, const format_arg &arg, +void do_format_arg(BasicWriter &writer, const basic_format_arg &arg, Context &ctx) { const Char *&s = ctx.ptr(); FormatSpec spec; if (*s == ':') { - if (arg.type == format_arg::CUSTOM) { - arg.custom.format(&writer, arg.custom.value, &ctx); + if (visit(internal::CustomFormatter(writer, ctx), arg)) return; - } ++s; // Parse fill and alignment. if (Char c = *s) { @@ -3420,33 +3542,13 @@ void do_format_arg(BasicWriter &writer, const format_arg &arg, spec.width_ = internal::parse_nonnegative_int(s); } else if (*s == '{') { ++s; - format_arg width_arg = ctx.parse_arg_id(); + auto width_arg = ctx.parse_arg_id(); if (*s++ != '}') FMT_THROW(format_error("invalid format string")); - ULongLong value = 0; - switch (width_arg.type) { - case format_arg::INT: - if (width_arg.int_value < 0) - FMT_THROW(format_error("negative width")); - value = width_arg.int_value; - break; - case format_arg::UINT: - value = width_arg.uint_value; - break; - case format_arg::LONG_LONG: - if (width_arg.long_long_value < 0) - FMT_THROW(format_error("negative width")); - value = width_arg.long_long_value; - break; - case format_arg::ULONG_LONG: - value = width_arg.ulong_long_value; - break; - default: - FMT_THROW(format_error("width is not integer")); - } - if (value > (std::numeric_limits::max)()) + ULongLong width = visit(internal::WidthHandler(), width_arg); + if (width > (std::numeric_limits::max)()) FMT_THROW(format_error("number is too big")); - spec.width_ = static_cast(value); + spec.width_ = static_cast(width); } // Parse precision. @@ -3457,41 +3559,21 @@ void do_format_arg(BasicWriter &writer, const format_arg &arg, spec.precision_ = internal::parse_nonnegative_int(s); } else if (*s == '{') { ++s; - format_arg precision_arg = ctx.parse_arg_id(); + auto precision_arg = ctx.parse_arg_id(); if (*s++ != '}') FMT_THROW(format_error("invalid format string")); - ULongLong value = 0; - switch (precision_arg.type) { - case format_arg::INT: - if (precision_arg.int_value < 0) - FMT_THROW(format_error("negative precision")); - value = precision_arg.int_value; - break; - case format_arg::UINT: - value = precision_arg.uint_value; - break; - case format_arg::LONG_LONG: - if (precision_arg.long_long_value < 0) - FMT_THROW(format_error("negative precision")); - value = precision_arg.long_long_value; - break; - case format_arg::ULONG_LONG: - value = precision_arg.ulong_long_value; - break; - default: - FMT_THROW(format_error("precision is not integer")); - } - if (value > (std::numeric_limits::max)()) + ULongLong precision = + visit(internal::PrecisionHandler(), precision_arg); + if (precision > (std::numeric_limits::max)()) FMT_THROW(format_error("number is too big")); - spec.precision_ = static_cast(value); + spec.precision_ = static_cast(precision); } else { FMT_THROW(format_error("missing precision specifier")); } - if (arg.type <= format_arg::LAST_INTEGER_TYPE || - arg.type == format_arg::POINTER) { + if (arg.is_integral() || arg.is_pointer()) { FMT_THROW(format_error( fmt::format("precision not allowed in {} format specifier", - arg.type == format_arg::POINTER ? "pointer" : "integer"))); + arg.is_pointer() ? "pointer" : "integer"))); } } @@ -3510,7 +3592,7 @@ void do_format_arg(BasicWriter &writer, const format_arg &arg, /** Formats arguments and writes the output to the writer. */ template void vformat(BasicWriter &writer, BasicCStringRef format_str, - basic_format_args args) { + basic_format_args args) { basic_format_context ctx(format_str.c_str(), args); const Char *&s = ctx.ptr(); const Char *start = s; @@ -3536,7 +3618,7 @@ void vformat(BasicWriter &writer, BasicCStringRef format_str, template inline void BasicWriter::vwrite( BasicCStringRef format, - basic_format_args> args) { + basic_format_args, Char> args) { vformat>(*this, format, args); } } // namespace fmt diff --git a/fmt/printf.h b/fmt/printf.h index 386acf98..c6700185 100644 --- a/fmt/printf.h +++ b/fmt/printf.h @@ -40,7 +40,7 @@ struct IntChecker { static bool fits_in_int(int) { return true; } }; -class PrecisionHandler { +class PrintfPrecisionHandler { public: template typename std::enable_if::value, int>::type @@ -80,14 +80,14 @@ struct is_same { enum { value = 1 }; }; -template +template class ArgConverter { private: - format_arg &arg_; - wchar_t type_; + basic_format_arg &arg_; + Char type_; public: - ArgConverter(format_arg &arg, wchar_t type) + ArgConverter(basic_format_arg &arg, Char type) : arg_(arg), type_(type) {} void operator()(bool value) { @@ -101,27 +101,27 @@ class ArgConverter { bool is_signed = type_ == 'd' || type_ == 'i'; typedef typename internal::Conditional< is_same::value, U, T>::type TargetType; + typedef basic_format_context format_context; if (sizeof(TargetType) <= sizeof(int)) { // Extra casts are used to silence warnings. if (is_signed) { - arg_.type = format_arg::INT; - arg_.int_value = static_cast(static_cast(value)); + arg_ = internal::MakeArg( + static_cast(static_cast(value))); } else { - arg_.type = format_arg::UINT; typedef typename internal::MakeUnsigned::Type Unsigned; - arg_.uint_value = static_cast(static_cast(value)); + arg_ = internal::MakeArg( + static_cast(static_cast(value))); } } else { if (is_signed) { - arg_.type = format_arg::LONG_LONG; // glibc's printf doesn't sign extend arguments of smaller types: // std::printf("%lld", -42); // prints "4294967254" // but we don't have to do the same because it's a UB. - arg_.long_long_value = static_cast(value); + arg_ = internal::MakeArg( + static_cast(value)); } else { - arg_.type = format_arg::ULONG_LONG; - arg_.ulong_long_value = - static_cast::Type>(value); + arg_ = internal::MakeArg( + static_cast::Type>(value)); } } } @@ -137,26 +137,27 @@ class ArgConverter { // If T is void, the argument is converted to corresponding signed or unsigned // type depending on the type specifier: 'd' and 'i' - signed, other - // unsigned). -template -void convert_arg(format_arg &arg, wchar_t type) { - visit(ArgConverter(arg, type), arg); +template +void convert_arg(basic_format_arg &arg, Char type) { + visit(ArgConverter(arg, type), arg); } // Converts an integer argument to char for printf. +template class CharConverter { private: - format_arg &arg_; + basic_format_arg &arg_; FMT_DISALLOW_COPY_AND_ASSIGN(CharConverter); public: - explicit CharConverter(format_arg &arg) : arg_(arg) {} + explicit CharConverter(basic_format_arg &arg) : arg_(arg) {} template typename std::enable_if::value>::type operator()(T value) { - arg_.type = format_arg::CHAR; - arg_.int_value = static_cast(value); + arg_ = + internal::MakeArg>(static_cast(value)); } template @@ -168,14 +169,14 @@ class CharConverter { // Checks if an argument is a valid printf width specifier and sets // left alignment if it is negative. -class WidthHandler { +class PrintfWidthHandler { private: FormatSpec &spec_; - FMT_DISALLOW_COPY_AND_ASSIGN(WidthHandler); + FMT_DISALLOW_COPY_AND_ASSIGN(PrintfWidthHandler); public: - explicit WidthHandler(FormatSpec &spec) : spec_(spec) {} + explicit PrintfWidthHandler(FormatSpec &spec) : spec_(spec) {} template typename std::enable_if::value, unsigned>::type @@ -239,7 +240,7 @@ class PrintfArgFormatter : public internal::ArgFormatterBase { } /** Formats a character. */ - void operator()(wchar_t value) { + void operator()(Char value) { const FormatSpec &fmt_spec = this->spec(); BasicWriter &w = this->writer(); if (fmt_spec.type_ && fmt_spec.type_ != 'c') @@ -282,7 +283,7 @@ class PrintfArgFormatter : public internal::ArgFormatterBase { /** Formats an argument of a custom (user-defined) type. */ void operator()(format_arg::CustomValue c) { const Char format_str[] = {'}', '\0'}; - auto args = basic_format_args>(); + auto args = basic_format_args, Char>(); basic_format_context ctx(format_str, args); c.format(&this->writer(), c.value, &ctx); } @@ -305,7 +306,7 @@ class printf_context : // Returns the argument with specified index or, if arg_index is equal // to the maximum unsigned value, the next argument. - format_arg get_arg( + basic_format_arg get_arg( const Char *s, unsigned arg_index = (std::numeric_limits::max)()); @@ -321,7 +322,7 @@ class printf_context : \endrst */ explicit printf_context(BasicCStringRef format_str, - basic_format_args args) + basic_format_args args) : Base(format_str.c_str(), args) {} /** Formats stored arguments and writes the output to the writer. */ @@ -355,11 +356,12 @@ void printf_context::parse_flags(FormatSpec &spec, const Char *&s) { } template -format_arg printf_context::get_arg(const Char *s, - unsigned arg_index) { +basic_format_arg printf_context::get_arg( + const Char *s, unsigned arg_index) { (void)s; const char *error = 0; - format_arg arg = arg_index == std::numeric_limits::max() ? + basic_format_arg arg = + arg_index == std::numeric_limits::max() ? this->next_arg(error) : Base::get_arg(arg_index - 1, error); if (error) FMT_THROW(format_error(!*s ? "invalid format string" : error)); @@ -395,7 +397,7 @@ unsigned printf_context::parse_header( spec.width_ = internal::parse_nonnegative_int(s); } else if (*s == '*') { ++s; - spec.width_ = visit(internal::WidthHandler(spec), get_arg(s)); + spec.width_ = visit(internal::PrintfWidthHandler(spec), get_arg(s)); } return arg_index; } @@ -427,15 +429,15 @@ void printf_context::format(BasicWriter &writer) { spec.precision_ = static_cast(internal::parse_nonnegative_int(s)); } else if (*s == '*') { ++s; - spec.precision_ = visit(internal::PrecisionHandler(), get_arg(s)); + spec.precision_ = visit(internal::PrintfPrecisionHandler(), get_arg(s)); } } - format_arg arg = get_arg(s, arg_index); + basic_format_arg arg = get_arg(s, arg_index); if (spec.flag(HASH_FLAG) && visit(internal::IsZeroInt(), arg)) spec.flags_ &= ~internal::to_unsigned(HASH_FLAG); if (spec.fill_ == '0') { - if (arg.type <= format_arg::LAST_NUMERIC_TYPE) + if (arg.is_numeric()) spec.align_ = ALIGN_NUMERIC; else spec.fill_ = ' '; // Ignore '0' flag for non-numeric types. @@ -478,7 +480,7 @@ void printf_context::format(BasicWriter &writer) { if (!*s) FMT_THROW(format_error("invalid format string")); spec.type_ = static_cast(*s++); - if (arg.type <= format_arg::LAST_INTEGER_TYPE) { + if (arg.is_integral()) { // Normalize type. switch (spec.type_) { case 'i': case 'u': @@ -486,7 +488,7 @@ void printf_context::format(BasicWriter &writer) { break; case 'c': // TODO: handle wchar_t - visit(internal::CharConverter(arg), arg); + visit(internal::CharConverter(arg), arg); break; } } @@ -509,12 +511,13 @@ void format_value(BasicWriter &w, const T &value, template void printf(BasicWriter &w, BasicCStringRef format, - basic_format_args> args) { + basic_format_args, Char> args) { printf_context(format, args).format(w); } -inline std::string vsprintf(CStringRef format, - basic_format_args> args) { +typedef basic_format_args, char> printf_args; + +inline std::string vsprintf(CStringRef format, printf_args args) { MemoryWriter w; printf(w, format, args); return w.str(); @@ -534,8 +537,9 @@ inline std::string sprintf(CStringRef format_str, const Args & ... args) { return vsprintf(format_str, make_xformat_args>(args...)); } -inline std::wstring vsprintf(WCStringRef format, - basic_format_args> args) { +inline std::wstring vsprintf( + WCStringRef format, + basic_format_args, wchar_t> args) { WMemoryWriter w; printf(w, format, args); return w.str(); @@ -547,8 +551,7 @@ inline std::wstring sprintf(WCStringRef format_str, const Args & ... args) { return vsprintf(format_str, vargs); } -FMT_API int vfprintf(std::FILE *f, CStringRef format, - basic_format_args> args); +FMT_API int vfprintf(std::FILE *f, CStringRef format, printf_args args); /** \rst @@ -565,8 +568,7 @@ inline int fprintf(std::FILE *f, CStringRef format_str, const Args & ... args) { return vfprintf(f, format_str, vargs); } -inline int vprintf(CStringRef format, - basic_format_args> args) { +inline int vprintf(CStringRef format, printf_args args) { return vfprintf(stdout, format, args); } @@ -584,8 +586,7 @@ inline int printf(CStringRef format_str, const Args & ... args) { return vprintf(format_str, make_xformat_args>(args...)); } -inline int vfprintf(std::ostream &os, CStringRef format_str, - basic_format_args> args) { +inline int vfprintf(std::ostream &os, CStringRef format_str, printf_args args) { MemoryWriter w; printf(w, format_str, args); internal::write(os, w); diff --git a/test/custom-formatter-test.cc b/test/custom-formatter-test.cc index 7601aeb5..51bed768 100644 --- a/test/custom-formatter-test.cc +++ b/test/custom-formatter-test.cc @@ -63,7 +63,7 @@ typedef fmt::printf_context std::string custom_vsprintf( const char* format_str, - fmt::basic_format_args args) { + fmt::basic_format_args args) { fmt::MemoryWriter writer; CustomPrintfFormatter formatter(format_str, args); formatter.format(writer); diff --git a/test/format-impl-test.cc b/test/format-impl-test.cc index c63b6b97..ff702a53 100644 --- a/test/format-impl-test.cc +++ b/test/format-impl-test.cc @@ -41,13 +41,25 @@ #undef min #undef max +template +struct ValueExtractor { + T operator()(T value) { + return value; + } + + template + T operator()(U) { + throw std::runtime_error(fmt::format("invalid type {}", typeid(U).name())); + return T(); + } +}; + TEST(FormatTest, ArgConverter) { using fmt::format_arg; - format_arg arg = format_arg(); - arg.type = format_arg::LONG_LONG; - arg.long_long_value = std::numeric_limits::max(); - visit(fmt::internal::ArgConverter(arg, 'd'), arg); - EXPECT_EQ(format_arg::LONG_LONG, arg.type); + fmt::LongLong value = std::numeric_limits::max(); + format_arg arg = fmt::internal::MakeArg(value); + visit(fmt::internal::ArgConverter(arg, 'd'), arg); + EXPECT_EQ(value, visit(ValueExtractor(), arg)); } TEST(FormatTest, FormatNegativeNaN) { diff --git a/test/util-test.cc b/test/util-test.cc index 3371ef20..c39b0abf 100644 --- a/test/util-test.cc +++ b/test/util-test.cc @@ -49,13 +49,17 @@ #include "fmt/format.h" +#undef min #undef max +using fmt::basic_format_arg; using fmt::format_arg; using fmt::Buffer; using fmt::StringRef; using fmt::internal::MemoryBuffer; +using fmt::internal::Value; +using testing::_; using testing::Return; using testing::StrictMock; @@ -70,11 +74,9 @@ void format_value(fmt::BasicWriter &w, Test, } template -format_arg make_arg(const T &value) { - typedef fmt::internal::MakeValue< fmt::basic_format_context > MakeValue; - format_arg arg = MakeValue(value); - arg.type = fmt::internal::type(); - return arg; +basic_format_arg make_arg(const T &value) { + typedef fmt::internal::MakeArg< fmt::basic_format_context > MakeArg; + return MakeArg(value); } } // namespace @@ -406,175 +408,9 @@ TEST(UtilTest, Increment) { EXPECT_STREQ("200", s); } -template -struct ArgInfo; - -#define ARG_INFO(type_code, Type, field) \ - template <> \ - struct ArgInfo { \ - static Type get(const format_arg &arg) { return arg.field; } \ - } - -ARG_INFO(INT, int, int_value); -ARG_INFO(UINT, unsigned, uint_value); -ARG_INFO(LONG_LONG, fmt::LongLong, long_long_value); -ARG_INFO(ULONG_LONG, fmt::ULongLong, ulong_long_value); -ARG_INFO(BOOL, int, int_value); -ARG_INFO(CHAR, int, int_value); -ARG_INFO(DOUBLE, double, double_value); -ARG_INFO(LONG_DOUBLE, long double, long_double_value); -ARG_INFO(CSTRING, const char *, string.value); -ARG_INFO(STRING, const char *, string.value); -ARG_INFO(WSTRING, const wchar_t *, wstring.value); -ARG_INFO(POINTER, const void *, pointer); -ARG_INFO(CUSTOM, format_arg::CustomValue, custom); - -#define CHECK_ARG_INFO(Type, field, value) { \ - format_arg arg = format_arg(); \ - arg.field = value; \ - EXPECT_EQ(value, ArgInfo::get(arg)); \ -} - -TEST(ArgTest, ArgInfo) { - CHECK_ARG_INFO(INT, int_value, 42); - CHECK_ARG_INFO(UINT, uint_value, 42u); - CHECK_ARG_INFO(LONG_LONG, long_long_value, 42); - CHECK_ARG_INFO(ULONG_LONG, ulong_long_value, 42u); - CHECK_ARG_INFO(DOUBLE, double_value, 4.2); - CHECK_ARG_INFO(LONG_DOUBLE, long_double_value, 4.2); - CHECK_ARG_INFO(CHAR, int_value, 'x'); - const char STR[] = "abc"; - CHECK_ARG_INFO(CSTRING, string.value, STR); - const wchar_t WSTR[] = L"abc"; - CHECK_ARG_INFO(WSTRING, wstring.value, WSTR); - int p = 0; - CHECK_ARG_INFO(POINTER, pointer, &p); - format_arg arg = format_arg(); - arg.custom.value = &p; - EXPECT_EQ(&p, ArgInfo::get(arg).value); -} - -#define EXPECT_ARG_(Char, type_code, MakeArgType, ExpectedType, value) { \ - MakeArgType input = static_cast(value); \ - format_arg arg = make_arg(input); \ - EXPECT_EQ(format_arg::type_code, arg.type); \ - ExpectedType expected_value = static_cast(value); \ - EXPECT_EQ(expected_value, ArgInfo::get(arg)); \ -} - -#define EXPECT_ARG(type_code, Type, value) \ - EXPECT_ARG_(char, type_code, Type, Type, value) - -#define EXPECT_ARGW(type_code, Type, value) \ - EXPECT_ARG_(wchar_t, type_code, Type, Type, value) - -TEST(ArgTest, MakeArg) { - // Test bool. - EXPECT_ARG_(char, BOOL, bool, int, true); - EXPECT_ARG_(wchar_t, BOOL, bool, int, true); - - // Test char. - EXPECT_ARG(CHAR, char, 'a'); - EXPECT_ARG(CHAR, char, CHAR_MIN); - EXPECT_ARG(CHAR, char, CHAR_MAX); - - // Test wchar_t. - EXPECT_ARGW(CHAR, wchar_t, L'a'); - EXPECT_ARGW(CHAR, wchar_t, WCHAR_MIN); - EXPECT_ARGW(CHAR, wchar_t, WCHAR_MAX); - - // Test signed/unsigned char. - EXPECT_ARG(INT, signed char, 42); - EXPECT_ARG(INT, signed char, SCHAR_MIN); - EXPECT_ARG(INT, signed char, SCHAR_MAX); - EXPECT_ARG(UINT, unsigned char, 42); - EXPECT_ARG(UINT, unsigned char, UCHAR_MAX ); - - // Test short. - EXPECT_ARG(INT, short, 42); - EXPECT_ARG(INT, short, SHRT_MIN); - EXPECT_ARG(INT, short, SHRT_MAX); - EXPECT_ARG(UINT, unsigned short, 42); - EXPECT_ARG(UINT, unsigned short, USHRT_MAX); - - // Test int. - EXPECT_ARG(INT, int, 42); - EXPECT_ARG(INT, int, INT_MIN); - EXPECT_ARG(INT, int, INT_MAX); - EXPECT_ARG(UINT, unsigned, 42); - EXPECT_ARG(UINT, unsigned, UINT_MAX); - - // Test long. -#if LONG_MAX == INT_MAX -# define LONG INT -# define ULONG UINT -# define long_value int_value -# define ulong_value uint_value -#else -# define LONG LONG_LONG -# define ULONG ULONG_LONG -# define long_value long_long_value -# define ulong_value ulong_long_value -#endif - EXPECT_ARG(LONG, long, 42); - EXPECT_ARG(LONG, long, LONG_MIN); - EXPECT_ARG(LONG, long, LONG_MAX); - EXPECT_ARG(ULONG, unsigned long, 42); - EXPECT_ARG(ULONG, unsigned long, ULONG_MAX); - - // Test long long. - EXPECT_ARG(LONG_LONG, fmt::LongLong, 42); - EXPECT_ARG(LONG_LONG, fmt::LongLong, LLONG_MIN); - EXPECT_ARG(LONG_LONG, fmt::LongLong, LLONG_MAX); - EXPECT_ARG(ULONG_LONG, fmt::ULongLong, 42); - EXPECT_ARG(ULONG_LONG, fmt::ULongLong, ULLONG_MAX); - - // Test float. - EXPECT_ARG(DOUBLE, float, 4.2); - EXPECT_ARG(DOUBLE, float, FLT_MIN); - EXPECT_ARG(DOUBLE, float, FLT_MAX); - - // Test double. - EXPECT_ARG(DOUBLE, double, 4.2); - EXPECT_ARG(DOUBLE, double, DBL_MIN); - EXPECT_ARG(DOUBLE, double, DBL_MAX); - - // Test long double. - EXPECT_ARG(LONG_DOUBLE, long double, 4.2); - EXPECT_ARG(LONG_DOUBLE, long double, LDBL_MIN); - EXPECT_ARG(LONG_DOUBLE, long double, LDBL_MAX); - - // Test string. - char STR[] = "test"; - EXPECT_ARG(CSTRING, char*, STR); - EXPECT_ARG(CSTRING, const char*, STR); - EXPECT_ARG(STRING, std::string, STR); - EXPECT_ARG(STRING, fmt::StringRef, STR); - - // Test wide string. - wchar_t WSTR[] = L"test"; - EXPECT_ARGW(WSTRING, wchar_t*, WSTR); - EXPECT_ARGW(WSTRING, const wchar_t*, WSTR); - EXPECT_ARGW(WSTRING, std::wstring, WSTR); - EXPECT_ARGW(WSTRING, fmt::WStringRef, WSTR); - - int n = 42; - EXPECT_ARG(POINTER, void*, &n); - EXPECT_ARG(POINTER, const void*, &n); - - ::Test t; - format_arg arg = make_arg(t); - EXPECT_EQ(format_arg::CUSTOM, arg.type); - EXPECT_EQ(&t, arg.custom.value); - fmt::MemoryWriter w; - fmt::format_context ctx("}", fmt::format_args()); - arg.custom.format(&w, &t, &ctx); - EXPECT_EQ("test", w.str()); -} - TEST(UtilTest, FormatArgs) { fmt::format_args args; - EXPECT_EQ(format_arg::NONE, args[1].type); + EXPECT_FALSE(args[1]); } struct CustomFormatter { @@ -595,73 +431,163 @@ TEST(UtilTest, MakeValueWithCustomFormatter) { EXPECT_TRUE(ctx.called); } -struct Result { - format_arg arg; +namespace fmt { +namespace internal { - Result() : arg(make_arg(0xdeadbeef)) {} - - template - Result(const T& value) : arg(make_arg(value)) {} - Result(const wchar_t *s) : arg(make_arg(s)) {} -}; - -struct TestVisitor { - Result operator()(int value) { return value; } - Result operator()(unsigned value) { return value; } - Result operator()(fmt::LongLong value) { return value; } - Result operator()(fmt::ULongLong value) { return value; } - Result operator()(double value) { return value; } - Result operator()(long double value) { return value; } - Result operator()(wchar_t value) { return static_cast(value); } - Result operator()(const char *s) { return s; } - Result operator()(fmt::format_arg::StringValue s) { - return s.value; - } - Result operator()(fmt::format_arg::StringValue s) { - return s.value; - } - Result operator()(const void *p) { return p; } - Result operator()(fmt::format_arg::CustomValue c) { - return *static_cast(c.value); - } -}; - -#define EXPECT_RESULT_(Char, type_code, value) { \ - format_arg arg = make_arg(value); \ - Result result = fmt::visit(TestVisitor(), arg); \ - EXPECT_EQ(format_arg::type_code, result.arg.type); \ - EXPECT_EQ(value, ArgInfo::get(result.arg)); \ +bool operator==(Value::CustomValue lhs, Value::CustomValue rhs) { + return lhs.value == rhs.value; } -#define EXPECT_RESULT(type_code, value) \ - EXPECT_RESULT_(char, type_code, value) -#define EXPECT_RESULTW(type_code, value) \ - EXPECT_RESULT_(wchar_t, type_code, value) +template +bool operator==(Value::StringValue lhs, Value::StringValue rhs) { + return std::basic_string(lhs.value, lhs.size) == + std::basic_string(rhs.value, rhs.size); +} +} +} -TEST(ArgVisitorTest, VisitAll) { - EXPECT_RESULT(INT, 42); - EXPECT_RESULT(UINT, 42u); - EXPECT_RESULT(LONG_LONG, 42ll); - EXPECT_RESULT(ULONG_LONG, 42ull); - EXPECT_RESULT(DOUBLE, 4.2); - EXPECT_RESULT(LONG_DOUBLE, 4.2l); - EXPECT_RESULT(CHAR, 'x'); - const char STR[] = "abc"; - EXPECT_RESULT(CSTRING, STR); - const wchar_t WSTR[] = L"abc"; - EXPECT_RESULTW(WSTRING, WSTR); - const void *p = STR; - EXPECT_RESULT(POINTER, p); - ::Test t; - Result result = visit(TestVisitor(), make_arg(t)); - EXPECT_EQ(format_arg::CUSTOM, result.arg.type); - EXPECT_EQ(&t, result.arg.custom.value); +template +struct MockVisitor { + // Use a unique result type to make sure that there are no undesirable + // conversions. + struct Result {}; + + MockVisitor() { + ON_CALL(*this, visit(_)).WillByDefault(Return(Result())); + } + + MOCK_METHOD1_T(visit, Result (T value)); + MOCK_METHOD0_T(unexpected, void ()); + + Result operator()(T value) { return visit(value); } + + template + Result operator()(U value) { + unexpected(); + return Result(); + } +}; + +template +struct VisitType { typedef T Type; }; + +#define VISIT_TYPE(Type_, VisitType_) \ + template <> \ + struct VisitType { typedef VisitType_ Type; } + +VISIT_TYPE(signed char, int); +VISIT_TYPE(unsigned char, unsigned); +VISIT_TYPE(short, int); +VISIT_TYPE(unsigned short, unsigned); + +#if LONG_MAX == INT_MAX +VISIT_TYPE(long, int); +VISIT_TYPE(unsigned long, unsigned); +#else +VISIT_TYPE(long, fmt::LongLong); +VISIT_TYPE(unsigned long, fmt::ULongLong); +#endif + +VISIT_TYPE(float, double); + +#define CHECK_ARG_(Char, expected, value) { \ + testing::StrictMock> visitor; \ + EXPECT_CALL(visitor, visit(expected)); \ + fmt::visit(visitor, make_arg(value)); \ +} + +#define CHECK_ARG(value) { \ + typename VisitType::Type expected = value; \ + CHECK_ARG_(char, expected, value) \ + CHECK_ARG_(wchar_t, expected, value) \ +} + +template +class NumericArgTest : public testing::Test {}; + +typedef ::testing::Types< + bool, signed char, unsigned char, signed, unsigned short, + int, unsigned, long, unsigned long, fmt::LongLong, fmt::ULongLong, + float, double, long double> Types; +TYPED_TEST_CASE(NumericArgTest, Types); + +template +typename std::enable_if::value, T>::type test_value() { + return static_cast(42); +} + +template +typename std::enable_if::value, T>::type + test_value() { + return static_cast(4.2); +} + +TYPED_TEST(NumericArgTest, MakeAndVisit) { + CHECK_ARG(test_value()); + CHECK_ARG(std::numeric_limits::min()); + CHECK_ARG(std::numeric_limits::max()); +} + +TEST(UtilTest, CharArg) { + CHECK_ARG_(char, 'a', 'a'); + CHECK_ARG_(wchar_t, L'a', 'a'); + CHECK_ARG_(wchar_t, L'a', L'a'); +} + +TEST(UtilTest, StringArg) { + char str_data[] = "test"; + char *str = str_data; + const char *cstr = str; + CHECK_ARG_(char, cstr, str); + CHECK_ARG_(wchar_t, cstr, str); + CHECK_ARG(cstr); + + Value::StringValue strval = {str, 4}; + CHECK_ARG_(char, strval, std::string(str)); + CHECK_ARG_(wchar_t, strval, std::string(str)); + CHECK_ARG_(char, strval, fmt::StringRef(str)); + CHECK_ARG_(wchar_t, strval, fmt::StringRef(str)); +} + +TEST(UtilTest, WStringArg) { + wchar_t str_data[] = L"test"; + wchar_t *str = str_data; + const wchar_t *cstr = str; + + Value::StringValue strval = {str, 4}; + CHECK_ARG_(wchar_t, strval, str); + CHECK_ARG_(wchar_t, strval, cstr); + CHECK_ARG_(wchar_t, strval, std::wstring(str)); + CHECK_ARG_(wchar_t, strval, fmt::WStringRef(str)); +} + +TEST(UtilTest, PointerArg) { + void *p = 0; + const void *cp = 0; + CHECK_ARG_(char, cp, p); + CHECK_ARG_(wchar_t, cp, p); + CHECK_ARG(cp); +} + +TEST(UtilTest, CustomArg) { + ::Test test; + typedef MockVisitor Visitor; + testing::StrictMock visitor; + EXPECT_CALL(visitor, visit(_)).WillOnce( + testing::Invoke([&](Value::CustomValue custom) { + EXPECT_EQ(&test, custom.value); + fmt::MemoryWriter w; + fmt::format_context ctx("}", fmt::format_args()); + custom.format(&w, &test, &ctx); + EXPECT_EQ("test", w.str()); + return Visitor::Result(); + })); + fmt::visit(visitor, make_arg(test)); } TEST(ArgVisitorTest, VisitInvalidArg) { format_arg arg = format_arg(); - arg.type = static_cast(format_arg::NONE); - EXPECT_ASSERT(visit(TestVisitor(), arg), "invalid argument type"); + EXPECT_ASSERT(visit(MockVisitor(), arg), "invalid argument type"); } // Tests fmt::internal::count_digits for integer type Int. From e1ee5bf0ba4b9c389e31443f2d3905bb1b84eab9 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sun, 11 Dec 2016 21:13:54 -0800 Subject: [PATCH 053/340] Replace StringValue with StringRef --- fmt/format.h | 33 ++++++++++++++------------------- test/util-test.cc | 25 +++++++++---------------- 2 files changed, 23 insertions(+), 35 deletions(-) diff --git a/fmt/format.h b/fmt/format.h index ed706466..3767a955 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -1016,7 +1016,7 @@ struct Value { StringValue string; StringValue sstring; StringValue ustring; - StringValue wstring; + StringValue wstring; // TODO: Char CustomValue custom; }; @@ -1114,9 +1114,9 @@ typename std::result_of::type case format_arg::CSTRING: return vis(arg.string.value); case format_arg::STRING: - return vis(arg.string); + return vis(StringRef(arg.string.value, arg.string.size)); case format_arg::WSTRING: - return vis(arg.wstring); + return vis(WStringRef(arg.wstring.value, arg.wstring.size)); case format_arg::POINTER: return vis(arg.pointer); case format_arg::CUSTOM: @@ -1954,7 +1954,7 @@ class ArgFormatterBase { } template - void write_str(format_arg::StringValue value, + void write_str(BasicStringRef value, typename EnableIf< std::is_same::value && std::is_same::value, int>::type = 0) { @@ -1962,7 +1962,7 @@ class ArgFormatterBase { } template - void write_str(format_arg::StringValue value, + void write_str(BasicStringRef value, typename EnableIf< !std::is_same::value || !std::is_same::value, int>::type = 0) { @@ -1974,16 +1974,12 @@ class ArgFormatterBase { FormatSpec &spec() { return spec_; } void write(bool value) { - const char *str_value = value ? "true" : "false"; - format_arg::StringValue str = { str_value, std::strlen(str_value) }; - writer_.write_str(str, spec_); + writer_.write_str(StringRef(value ? "true" : "false"), spec_); } void write(const char *value) { - format_arg::StringValue str = { - value, value != 0 ? std::strlen(value) : 0 - }; - writer_.write_str(str, spec_); + writer_.write_str( + StringRef(value, value != 0 ? std::strlen(value) : 0), spec_); } public: @@ -2042,11 +2038,11 @@ class ArgFormatterBase { write(value); } - void operator()(format_arg::StringValue value) { + void operator()(StringRef value) { writer_.write_str(value, spec_); } - void operator()(format_arg::StringValue value) { + void operator()(BasicStringRef value) { write_str(value); } @@ -2339,8 +2335,7 @@ class BasicWriter { CharPtr write_str(const StrChar *s, std::size_t size, const AlignSpec &spec); template - void write_str(const format_arg::StringValue &str, - const FormatSpec &spec); + void write_str(BasicStringRef str, const FormatSpec &spec); // This following methods are private to disallow writing wide characters // and strings to a char stream. If you want to print a wide string as a @@ -2563,13 +2558,13 @@ typename BasicWriter::CharPtr BasicWriter::write_str( template template void BasicWriter::write_str( - const format_arg::StringValue &s, const FormatSpec &spec) { + BasicStringRef s, const FormatSpec &spec) { // Check if StrChar is convertible to Char. internal::CharTraits::convert(StrChar()); if (spec.type_ && spec.type_ != 's') internal::report_unknown_type(spec.type_, "string"); - const StrChar *str_value = s.value; - std::size_t str_size = s.size; + const StrChar *str_value = s.data(); + std::size_t str_size = s.size(); if (str_size == 0) { if (!str_value) { FMT_THROW(format_error("string pointer is null")); diff --git a/test/util-test.cc b/test/util-test.cc index c39b0abf..f550f3ae 100644 --- a/test/util-test.cc +++ b/test/util-test.cc @@ -437,12 +437,6 @@ namespace internal { bool operator==(Value::CustomValue lhs, Value::CustomValue rhs) { return lhs.value == rhs.value; } - -template -bool operator==(Value::StringValue lhs, Value::StringValue rhs) { - return std::basic_string(lhs.value, lhs.size) == - std::basic_string(rhs.value, rhs.size); -} } } @@ -542,11 +536,10 @@ TEST(UtilTest, StringArg) { CHECK_ARG_(wchar_t, cstr, str); CHECK_ARG(cstr); - Value::StringValue strval = {str, 4}; - CHECK_ARG_(char, strval, std::string(str)); - CHECK_ARG_(wchar_t, strval, std::string(str)); - CHECK_ARG_(char, strval, fmt::StringRef(str)); - CHECK_ARG_(wchar_t, strval, fmt::StringRef(str)); + StringRef sref(str); + CHECK_ARG_(char, sref, std::string(str)); + CHECK_ARG_(wchar_t, sref, std::string(str)); + CHECK_ARG(sref); } TEST(UtilTest, WStringArg) { @@ -554,11 +547,11 @@ TEST(UtilTest, WStringArg) { wchar_t *str = str_data; const wchar_t *cstr = str; - Value::StringValue strval = {str, 4}; - CHECK_ARG_(wchar_t, strval, str); - CHECK_ARG_(wchar_t, strval, cstr); - CHECK_ARG_(wchar_t, strval, std::wstring(str)); - CHECK_ARG_(wchar_t, strval, fmt::WStringRef(str)); + fmt::WStringRef sref(str); + CHECK_ARG_(wchar_t, sref, str); + CHECK_ARG_(wchar_t, sref, cstr); + CHECK_ARG_(wchar_t, sref, std::wstring(str)); + CHECK_ARG_(wchar_t, sref, fmt::WStringRef(str)); } TEST(UtilTest, PointerArg) { From 6cba8fe9ba8b68e7354e3cf2365f63de5b7f7494 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Thu, 15 Dec 2016 07:51:40 -0800 Subject: [PATCH 054/340] Move stuff out of internal::Value --- fmt/format.h | 206 ++++++++++++++++++++++---------------------- fmt/printf.h | 2 +- test/format-test.cc | 2 +- test/util-test.cc | 6 +- 4 files changed, 107 insertions(+), 109 deletions(-) diff --git a/fmt/format.h b/fmt/format.h index 3767a955..7e0ac68d 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -989,22 +989,30 @@ FMT_API void format_windows_error(fmt::Writer &out, int error_code, fmt::StringRef message) FMT_NOEXCEPT; #endif +enum Type { + NONE, NAMED_ARG, + // Integer types should go first, + INT, UINT, LONG_LONG, ULONG_LONG, BOOL, CHAR, LAST_INTEGER_TYPE = CHAR, + // followed by floating-point types. + DOUBLE, LONG_DOUBLE, LAST_NUMERIC_TYPE = LONG_DOUBLE, + CSTRING, STRING, WSTRING, POINTER, CUSTOM +}; + +template +struct StringValue { + const Char *value; + std::size_t size; +}; + +typedef void (*FormatFunc)(void *writer, const void *arg, void *ctx); + +struct CustomValue { + const void *value; + FormatFunc format; +}; + // A formatting argument value. struct Value { - template - struct StringValue { - const Char *value; - std::size_t size; - }; - - typedef void (*FormatFunc)( - void *writer, const void *arg, void *ctx); - - struct CustomValue { - const void *value; - FormatFunc format; - }; - union { int int_value; unsigned uint_value; @@ -1019,15 +1027,6 @@ struct Value { StringValue wstring; // TODO: Char CustomValue custom; }; - - enum Type { - NONE, NAMED_ARG, - // Integer types should go first, - INT, UINT, LONG_LONG, ULONG_LONG, BOOL, CHAR, LAST_INTEGER_TYPE = CHAR, - // followed by floating-point types. - DOUBLE, LONG_DOUBLE, LAST_NUMERIC_TYPE = LONG_DOUBLE, - CSTRING, STRING, WSTRING, POINTER, CUSTOM - }; }; template @@ -1042,7 +1041,7 @@ class basic_format_args; template class basic_format_arg : public internal::Value { protected: - Type type_; + internal::Type type_; template friend typename std::result_of::type @@ -1055,25 +1054,25 @@ class basic_format_arg : public internal::Value { friend class internal::ArgMap; void check_type() const { - FMT_ASSERT(type_ > NAMED_ARG, "invalid argument type"); + FMT_ASSERT(type_ > internal::NAMED_ARG, "invalid argument type"); } public: - explicit operator bool() const noexcept { return type_ != NONE; } + explicit operator bool() const noexcept { return type_ != internal::NONE; } bool is_integral() const { check_type(); - return type_ <= LAST_INTEGER_TYPE; + return type_ <= internal::LAST_INTEGER_TYPE; } bool is_numeric() const { check_type(); - return type_ <= LAST_NUMERIC_TYPE; + return type_ <= internal::LAST_NUMERIC_TYPE; } bool is_pointer() const { check_type(); - return type_ == POINTER; + return type_ == internal::POINTER; } }; @@ -1091,35 +1090,35 @@ template typename std::result_of::type visit(Visitor &&vis, basic_format_arg arg) { switch (arg.type_) { - case format_arg::NONE: - case format_arg::NAMED_ARG: + case internal::NONE: + case internal::NAMED_ARG: FMT_ASSERT(false, "invalid argument type"); break; - case format_arg::INT: + case internal::INT: return vis(arg.int_value); - case format_arg::UINT: + case internal::UINT: return vis(arg.uint_value); - case format_arg::LONG_LONG: + case internal::LONG_LONG: return vis(arg.long_long_value); - case format_arg::ULONG_LONG: + case internal::ULONG_LONG: return vis(arg.ulong_long_value); - case format_arg::BOOL: + case internal::BOOL: return vis(arg.int_value != 0); - case format_arg::CHAR: + case internal::CHAR: return vis(static_cast(arg.int_value)); - case format_arg::DOUBLE: + case internal::DOUBLE: return vis(arg.double_value); - case format_arg::LONG_DOUBLE: + case internal::LONG_DOUBLE: return vis(arg.long_double_value); - case format_arg::CSTRING: + case internal::CSTRING: return vis(arg.string.value); - case format_arg::STRING: + case internal::STRING: return vis(StringRef(arg.string.value, arg.string.size)); - case format_arg::WSTRING: + case internal::WSTRING: return vis(WStringRef(arg.wstring.value, arg.wstring.size)); - case format_arg::POINTER: + case internal::POINTER: return vis(arg.pointer); - case format_arg::CUSTOM: + case internal::CUSTOM: return vis(arg.custom); } return typename std::result_of::type(); @@ -1262,76 +1261,75 @@ struct IsNamedArg : std::false_type {}; template struct IsNamedArg< NamedArg > : std::true_type {}; -typedef Value::Type Type; - template constexpr Type gettype() { typedef format_arg Arg; return IsNamedArg::value ? - Arg::NAMED_ARG : (ConvertToInt::value ? Arg::INT : Arg::CUSTOM); + internal::NAMED_ARG : + (ConvertToInt::value ? internal::INT : internal::CUSTOM); } -template <> constexpr Type gettype() { return format_arg::BOOL; } -template <> constexpr Type gettype() { return format_arg::INT; } +template <> constexpr Type gettype() { return internal::BOOL; } +template <> constexpr Type gettype() { return internal::INT; } template <> constexpr Type gettype() { - return format_arg::UINT; + return internal::UINT; } -template <> constexpr Type gettype() { return format_arg::INT; } -template <> constexpr Type gettype() { return format_arg::UINT; } +template <> constexpr Type gettype() { return internal::INT; } +template <> constexpr Type gettype() { return internal::UINT; } template <> constexpr Type gettype() { - return sizeof(long) == sizeof(int) ? format_arg::INT : format_arg::LONG_LONG; + return sizeof(long) == sizeof(int) ? internal::INT : internal::LONG_LONG; } template <> constexpr Type gettype() { return sizeof(unsigned long) == sizeof(unsigned) ? - format_arg::UINT : format_arg::ULONG_LONG; + internal::UINT : internal::ULONG_LONG; } -template <> constexpr Type gettype() { return format_arg::LONG_LONG; } +template <> constexpr Type gettype() { return internal::LONG_LONG; } template <> constexpr Type gettype() { - return format_arg::ULONG_LONG; + return internal::ULONG_LONG; } -template <> constexpr Type gettype() { return format_arg::DOUBLE; } -template <> constexpr Type gettype() { return format_arg::DOUBLE; } +template <> constexpr Type gettype() { return internal::DOUBLE; } +template <> constexpr Type gettype() { return internal::DOUBLE; } template <> constexpr Type gettype() { - return format_arg::LONG_DOUBLE; + return internal::LONG_DOUBLE; } -template <> constexpr Type gettype() { return format_arg::INT; } -template <> constexpr Type gettype() { return format_arg::UINT; } -template <> constexpr Type gettype() { return format_arg::CHAR; } +template <> constexpr Type gettype() { return internal::INT; } +template <> constexpr Type gettype() { return internal::UINT; } +template <> constexpr Type gettype() { return internal::CHAR; } #if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED) -template <> constexpr Type gettype() { return format_arg::CHAR; } +template <> constexpr Type gettype() { return internal::CHAR; } #endif -template <> constexpr Type gettype() { return format_arg::CSTRING; } +template <> constexpr Type gettype() { return internal::CSTRING; } template <> constexpr Type gettype() { - return format_arg::CSTRING; + return internal::CSTRING; } template <> constexpr Type gettype() { - return format_arg::CSTRING; + return internal::CSTRING; } template <> constexpr Type gettype() { - return format_arg::CSTRING; + return internal::CSTRING; } template <> constexpr Type gettype() { - return format_arg::CSTRING; + return internal::CSTRING; } template <> constexpr Type gettype() { - return format_arg::CSTRING; + return internal::CSTRING; } -template <> constexpr Type gettype() { return format_arg::STRING; } -template <> constexpr Type gettype() { return format_arg::STRING; } -template <> constexpr Type gettype() { return format_arg::CSTRING; } -template <> constexpr Type gettype() { return format_arg::WSTRING; } +template <> constexpr Type gettype() { return internal::STRING; } +template <> constexpr Type gettype() { return internal::STRING; } +template <> constexpr Type gettype() { return internal::CSTRING; } +template <> constexpr Type gettype() { return internal::WSTRING; } template <> constexpr Type gettype() { - return format_arg::WSTRING; + return internal::WSTRING; } template <> constexpr Type gettype() { - return format_arg::WSTRING; + return internal::WSTRING; } -template <> constexpr Type gettype() { return format_arg::WSTRING; } -template <> constexpr Type gettype() { return format_arg::POINTER; } +template <> constexpr Type gettype() { return internal::WSTRING; } +template <> constexpr Type gettype() { return internal::POINTER; } template <> constexpr Type gettype() { - return format_arg::POINTER; + return internal::POINTER; } template @@ -1390,7 +1388,7 @@ class MakeValue : public basic_format_arg { #define FMT_MAKE_VALUE_(Type, field, TYPE, rhs) \ MakeValue(Type value) { \ - static_assert(internal::type() == MakeValue::TYPE, "invalid type"); \ + static_assert(internal::type() == internal::TYPE, "invalid type"); \ this->field = rhs; \ } @@ -1431,14 +1429,14 @@ class MakeValue : public basic_format_arg { #if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED) typedef typename WCharHelper::Supported WChar; MakeValue(WChar value) { - static_assert(internal::type() == MakeValue::CHAR, "invalid type"); + static_assert(internal::type() == internal::CHAR, "invalid type"); this->int_value = value; } #endif #define FMT_MAKE_STR_VALUE(Type, TYPE) \ MakeValue(Type value) { \ - static_assert(internal::type() == MakeValue::TYPE, "invalid type"); \ + static_assert(internal::type() == internal::TYPE, "invalid type"); \ set_string(value); \ } @@ -1454,7 +1452,7 @@ class MakeValue : public basic_format_arg { #define FMT_MAKE_WSTR_VALUE(Type, TYPE) \ MakeValue(typename WCharHelper::Supported value) { \ - static_assert(internal::type() == MakeValue::TYPE, "invalid type"); \ + static_assert(internal::type() == internal::TYPE, "invalid type"); \ set_string(value); \ } @@ -1470,7 +1468,7 @@ class MakeValue : public basic_format_arg { MakeValue(const T &value, typename EnableIf::value>::value, int>::type = 0) { - static_assert(internal::type() == MakeValue::CUSTOM, "invalid type"); + static_assert(internal::type() == internal::CUSTOM, "invalid type"); this->custom.value = &value; this->custom.format = &format_custom_arg; } @@ -1478,7 +1476,7 @@ class MakeValue : public basic_format_arg { template MakeValue(const T &value, typename EnableIf::value, int>::type = 0) { - static_assert(internal::type() == MakeValue::INT, "invalid type"); + static_assert(internal::type() == internal::INT, "invalid type"); this->int_value = value; } @@ -1487,7 +1485,7 @@ class MakeValue : public basic_format_arg { template MakeValue(const NamedArg &value) { static_assert( - internal::type &>() == MakeValue::NAMED_ARG, + internal::type &>() == internal::NAMED_ARG, "invalid type"); this->pointer = &value; } @@ -1497,7 +1495,7 @@ template class MakeArg : public basic_format_arg { public: MakeArg() { - this->type_ = format_arg::NONE; + this->type_ = internal::NONE; } template @@ -1589,10 +1587,10 @@ class basic_format_args { const format_arg *args_; }; - typename format_arg::Type type(unsigned index) const { + typename internal::Type type(unsigned index) const { unsigned shift = index * 4; uint64_t mask = 0xf; - return static_cast( + return static_cast( (types_ & (mask << shift)) >> shift); } @@ -1603,11 +1601,11 @@ class basic_format_args { format_arg get(size_type index) const { format_arg arg; - bool use_values = type(internal::MAX_PACKED_ARGS - 1) == format_arg::NONE; + bool use_values = type(internal::MAX_PACKED_ARGS - 1) == internal::NONE; if (index < internal::MAX_PACKED_ARGS) { - typename format_arg::Type arg_type = type(index); + typename internal::Type arg_type = type(index); internal::Value &val = arg; - if (arg_type != format_arg::NONE) + if (arg_type != internal::NONE) val = use_values ? values_[index] : args_[index]; arg.type_ = arg_type; return arg; @@ -1615,11 +1613,11 @@ class basic_format_args { if (use_values) { // The index is greater than the number of arguments that can be stored // in values, so return a "none" argument. - arg.type_ = format_arg::NONE; + arg.type_ = internal::NONE; return arg; } for (unsigned i = internal::MAX_PACKED_ARGS; i <= index; ++i) { - if (args_[i].type_ == format_arg::NONE) + if (args_[i].type_ == internal::NONE) return args_[i]; } return args_[index]; @@ -1637,7 +1635,7 @@ class basic_format_args { /** Returns the argument at specified index. */ format_arg operator[](size_type index) const { format_arg arg = get(index); - return arg.type_ == format_arg::NAMED_ARG ? + return arg.type_ == internal::NAMED_ARG ? *static_cast(arg.pointer) : arg; } }; @@ -1901,14 +1899,14 @@ void ArgMap::init(const basic_format_args &args) { typedef internal::NamedArg NamedArg; const NamedArg *named_arg = 0; bool use_values = - args.type(MAX_PACKED_ARGS - 1) == format_arg::NONE; + args.type(MAX_PACKED_ARGS - 1) == internal::NONE; if (use_values) { for (unsigned i = 0;/*nothing*/; ++i) { - format_arg::Type arg_type = args.type(i); + internal::Type arg_type = args.type(i); switch (arg_type) { - case format_arg::NONE: + case internal::NONE: return; - case format_arg::NAMED_ARG: + case internal::NAMED_ARG: named_arg = static_cast(args.values_[i].pointer); map_.push_back(Pair(named_arg->name, *named_arg)); break; @@ -1919,17 +1917,17 @@ void ArgMap::init(const basic_format_args &args) { return; } for (unsigned i = 0; i != MAX_PACKED_ARGS; ++i) { - format_arg::Type arg_type = args.type(i); - if (arg_type == format_arg::NAMED_ARG) { + internal::Type arg_type = args.type(i); + if (arg_type == internal::NAMED_ARG) { named_arg = static_cast(args.args_[i].pointer); map_.push_back(Pair(named_arg->name, *named_arg)); } } for (unsigned i = MAX_PACKED_ARGS; ; ++i) { switch (args.args_[i].type_) { - case format_arg::NONE: + case internal::NONE: return; - case format_arg::NAMED_ARG: + case internal::NAMED_ARG: named_arg = static_cast(args.args_[i].pointer); map_.push_back(Pair(named_arg->name, *named_arg)); break; @@ -2136,7 +2134,7 @@ class ArgFormatter : public internal::ArgFormatterBase { using internal::ArgFormatterBase::operator(); /** Formats an argument of a custom (user-defined) type. */ - void operator()(format_arg::CustomValue c) { + void operator()(internal::CustomValue c) { c.format(&this->writer(), c.value, &ctx_); } }; @@ -3367,7 +3365,7 @@ class CustomFormatter { CustomFormatter(BasicWriter &writer, Context &ctx) : writer_(writer), ctx_(ctx) {} - bool operator()(format_arg::CustomValue custom) { + bool operator()(internal::CustomValue custom) { custom.format(&writer_, custom.value, &ctx_); return true; } diff --git a/fmt/printf.h b/fmt/printf.h index c6700185..47d868e6 100644 --- a/fmt/printf.h +++ b/fmt/printf.h @@ -281,7 +281,7 @@ class PrintfArgFormatter : public internal::ArgFormatterBase { } /** Formats an argument of a custom (user-defined) type. */ - void operator()(format_arg::CustomValue c) { + void operator()(internal::CustomValue c) { const Char format_str[] = {'}', '\0'}; auto args = basic_format_args, Char>(); basic_format_context ctx(format_str, args); diff --git a/test/format-test.cc b/test/format-test.cc index b8e991b0..d3d449a3 100644 --- a/test/format-test.cc +++ b/test/format-test.cc @@ -1636,7 +1636,7 @@ class MockArgFormatter : public fmt::internal::ArgFormatterBase { void operator()(int value) { call(value); } - void operator()(fmt::format_arg::CustomValue) {} + void operator()(fmt::internal::CustomValue) {} }; void custom_vformat(fmt::CStringRef format_str, fmt::format_args args) { diff --git a/test/util-test.cc b/test/util-test.cc index f550f3ae..ec98ef5a 100644 --- a/test/util-test.cc +++ b/test/util-test.cc @@ -434,7 +434,7 @@ TEST(UtilTest, MakeValueWithCustomFormatter) { namespace fmt { namespace internal { -bool operator==(Value::CustomValue lhs, Value::CustomValue rhs) { +bool operator==(CustomValue lhs, CustomValue rhs) { return lhs.value == rhs.value; } } @@ -564,10 +564,10 @@ TEST(UtilTest, PointerArg) { TEST(UtilTest, CustomArg) { ::Test test; - typedef MockVisitor Visitor; + typedef MockVisitor Visitor; testing::StrictMock visitor; EXPECT_CALL(visitor, visit(_)).WillOnce( - testing::Invoke([&](Value::CustomValue custom) { + testing::Invoke([&](fmt::internal::CustomValue custom) { EXPECT_EQ(&test, custom.value); fmt::MemoryWriter w; fmt::format_context ctx("}", fmt::format_args()); From 763ca9780f68164d86b08a27cef2b7db4542466a Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Thu, 15 Dec 2016 08:26:10 -0800 Subject: [PATCH 055/340] Parameterize Value on character type --- fmt/format.h | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/fmt/format.h b/fmt/format.h index 7e0ac68d..e25c9712 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -1012,6 +1012,7 @@ struct CustomValue { }; // A formatting argument value. +template struct Value { union { int int_value; @@ -1039,7 +1040,7 @@ class basic_format_args; // A formatting argument. It is a trivially copyable/constructible type to // allow storage in internal::MemoryBuffer. template -class basic_format_arg : public internal::Value { +class basic_format_arg : public internal::Value { protected: internal::Type type_; @@ -1539,8 +1540,10 @@ class format_arg_store { static const size_t NUM_ARGS = sizeof...(Args); static const bool IS_PACKED = NUM_ARGS <= internal::MAX_PACKED_ARGS; - typedef typename std::conditional< - IS_PACKED, internal::Value, format_arg>::type value_type; + typedef typename Context::char_type char_type; + + typedef typename std::conditional, basic_format_arg>::type value_type; // If the arguments are not packed, add one more element to mark the end. std::array data_; @@ -1583,7 +1586,7 @@ class basic_format_args { // This is done to reduce compiled code size as storing larger objects // may require more code (at least on x86-64) even if the same amount of // data is actually copied to stack. It saves ~10% on the bloat test. - const internal::Value *values_; + const internal::Value *values_; const format_arg *args_; }; @@ -1596,7 +1599,7 @@ class basic_format_args { friend class internal::ArgMap; - void set_data(const internal::Value *values) { values_ = values; } + void set_data(const internal::Value *values) { values_ = values; } void set_data(const format_arg *args) { args_ = args; } format_arg get(size_type index) const { @@ -1604,7 +1607,7 @@ class basic_format_args { bool use_values = type(internal::MAX_PACKED_ARGS - 1) == internal::NONE; if (index < internal::MAX_PACKED_ARGS) { typename internal::Type arg_type = type(index); - internal::Value &val = arg; + internal::Value &val = arg; if (arg_type != internal::NONE) val = use_values ? values_[index] : args_[index]; arg.type_ = arg_type; From 1183621867c0c8f927ff4219422376733914c7f0 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Thu, 15 Dec 2016 08:36:18 -0800 Subject: [PATCH 056/340] Add support for exotic character types --- fmt/format.h | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/fmt/format.h b/fmt/format.h index e25c9712..8a0623f4 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -995,7 +995,7 @@ enum Type { INT, UINT, LONG_LONG, ULONG_LONG, BOOL, CHAR, LAST_INTEGER_TYPE = CHAR, // followed by floating-point types. DOUBLE, LONG_DOUBLE, LAST_NUMERIC_TYPE = LONG_DOUBLE, - CSTRING, STRING, WSTRING, POINTER, CUSTOM + CSTRING, STRING, TSTRING, POINTER, CUSTOM }; template @@ -1025,7 +1025,7 @@ struct Value { StringValue string; StringValue sstring; StringValue ustring; - StringValue wstring; // TODO: Char + StringValue tstring; CustomValue custom; }; }; @@ -1115,8 +1115,8 @@ typename std::result_of::type return vis(arg.string.value); case internal::STRING: return vis(StringRef(arg.string.value, arg.string.size)); - case internal::WSTRING: - return vis(WStringRef(arg.wstring.value, arg.wstring.size)); + case internal::TSTRING: + return vis(BasicStringRef(arg.tstring.value, arg.tstring.size)); case internal::POINTER: return vis(arg.pointer); case internal::CUSTOM: @@ -1320,14 +1320,14 @@ template <> constexpr Type gettype() { template <> constexpr Type gettype() { return internal::STRING; } template <> constexpr Type gettype() { return internal::STRING; } template <> constexpr Type gettype() { return internal::CSTRING; } -template <> constexpr Type gettype() { return internal::WSTRING; } +template <> constexpr Type gettype() { return internal::TSTRING; } template <> constexpr Type gettype() { - return internal::WSTRING; + return internal::TSTRING; } template <> constexpr Type gettype() { - return internal::WSTRING; + return internal::TSTRING; } -template <> constexpr Type gettype() { return internal::WSTRING; } +template <> constexpr Type gettype() { return internal::TSTRING; } template <> constexpr Type gettype() { return internal::POINTER; } template <> constexpr Type gettype() { return internal::POINTER; @@ -1371,8 +1371,8 @@ class MakeValue : public basic_format_arg { } void set_string(WStringRef str) { - this->wstring.value = str.data(); - this->wstring.size = str.size(); + this->tstring.value = str.data(); + this->tstring.size = str.size(); } // Formats an argument of a custom type, such as a user-defined class. @@ -1457,10 +1457,10 @@ class MakeValue : public basic_format_arg { set_string(value); \ } - FMT_MAKE_WSTR_VALUE(wchar_t *, WSTRING) - FMT_MAKE_WSTR_VALUE(const wchar_t *, WSTRING) - FMT_MAKE_WSTR_VALUE(const std::wstring &, WSTRING) - FMT_MAKE_WSTR_VALUE(WStringRef, WSTRING) + FMT_MAKE_WSTR_VALUE(wchar_t *, TSTRING) + FMT_MAKE_WSTR_VALUE(const wchar_t *, TSTRING) + FMT_MAKE_WSTR_VALUE(const std::wstring &, TSTRING) + FMT_MAKE_WSTR_VALUE(WStringRef, TSTRING) FMT_MAKE_VALUE(void *, pointer, POINTER) FMT_MAKE_VALUE(const void *, pointer, POINTER) From f05888692c9363550e2b4a1540541005f8410cff Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Fri, 23 Dec 2016 08:24:48 -0800 Subject: [PATCH 057/340] Fix handling of unpacked args (#437) --- fmt/format.h | 4 ++-- test/format-test.cc | 9 +++++---- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/fmt/format.h b/fmt/format.h index 8a0623f4..6a58f338 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -1538,7 +1538,7 @@ template class format_arg_store { private: static const size_t NUM_ARGS = sizeof...(Args); - static const bool IS_PACKED = NUM_ARGS <= internal::MAX_PACKED_ARGS; + static const bool IS_PACKED = NUM_ARGS < internal::MAX_PACKED_ARGS; typedef typename Context::char_type char_type; @@ -1552,7 +1552,7 @@ class format_arg_store { static const uint64_t TYPES = internal::make_type(); format_arg_store(const Args &... args) - : data_{{internal::MakeValue(args)...}} {} + : data_{{internal::MakeArg(args)...}} {} const value_type *data() const { return data_.data(); } }; diff --git a/test/format-test.cc b/test/format-test.cc index d3d449a3..6829f622 100644 --- a/test/format-test.cc +++ b/test/format-test.cc @@ -1577,10 +1577,11 @@ void print_error(const char *file, int line, const char *format, } #endif -TEST(FormatTest, MaxArgs) { - EXPECT_EQ("0123456789abcde", - fmt::format("{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}", - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 'a', 'b', 'c', 'd', 'e')); +TEST(FormatTest, UnpackedArgs) { + EXPECT_EQ("0123456789abcdefg", + fmt::format("{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}", + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 'a', 'b', 'c', 'd', 'e', + 'f', 'g')); } #if FMT_USE_USER_DEFINED_LITERALS From d86e51e9c15ddb41080bec0519ed169c4ff7c130 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sat, 24 Dec 2016 07:37:33 -0800 Subject: [PATCH 058/340] Don't inherit basic_format_arg from internal::Value --- fmt/format.h | 528 +++++++++++++++++++++++----------------------- test/util-test.cc | 2 +- 2 files changed, 261 insertions(+), 269 deletions(-) diff --git a/fmt/format.h b/fmt/format.h index 6a58f338..91c4cee9 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -989,146 +989,27 @@ FMT_API void format_windows_error(fmt::Writer &out, int error_code, fmt::StringRef message) FMT_NOEXCEPT; #endif -enum Type { - NONE, NAMED_ARG, - // Integer types should go first, - INT, UINT, LONG_LONG, ULONG_LONG, BOOL, CHAR, LAST_INTEGER_TYPE = CHAR, - // followed by floating-point types. - DOUBLE, LONG_DOUBLE, LAST_NUMERIC_TYPE = LONG_DOUBLE, - CSTRING, STRING, TSTRING, POINTER, CUSTOM -}; +template +struct EnableIf {}; -template -struct StringValue { - const Char *value; - std::size_t size; -}; +template +struct EnableIf { typedef T type; }; -typedef void (*FormatFunc)(void *writer, const void *arg, void *ctx); +template +struct Conditional { typedef T type; }; -struct CustomValue { - const void *value; - FormatFunc format; -}; +template +struct Conditional { typedef F type; }; -// A formatting argument value. -template -struct Value { - union { - int int_value; - unsigned uint_value; - LongLong long_long_value; - ULongLong ulong_long_value; - double double_value; - long double long_double_value; - const void *pointer; - StringValue string; - StringValue sstring; - StringValue ustring; - StringValue tstring; - CustomValue custom; - }; -}; +// For bcc32 which doesn't understand ! in template arguments. +template +struct Not { enum { value = 0 }; }; -template -class ArgMap; -} // namespace internal +template <> +struct Not { enum { value = 1 }; }; -template -class basic_format_args; - -// A formatting argument. It is a trivially copyable/constructible type to -// allow storage in internal::MemoryBuffer. -template -class basic_format_arg : public internal::Value { - protected: - internal::Type type_; - - template - friend typename std::result_of::type - visit(Visitor &&vis, basic_format_arg arg); - - template - friend class basic_format_args; - - template - friend class internal::ArgMap; - - void check_type() const { - FMT_ASSERT(type_ > internal::NAMED_ARG, "invalid argument type"); - } - - public: - explicit operator bool() const noexcept { return type_ != internal::NONE; } - - bool is_integral() const { - check_type(); - return type_ <= internal::LAST_INTEGER_TYPE; - } - - bool is_numeric() const { - check_type(); - return type_ <= internal::LAST_NUMERIC_TYPE; - } - - bool is_pointer() const { - check_type(); - return type_ == internal::POINTER; - } -}; - -typedef basic_format_arg format_arg; -typedef basic_format_arg wformat_arg; - -/** - \rst - Visits an argument dispatching to the appropriate visit method based on - the argument type. For example, if the argument type is ``double`` then - ``vis(value)`` will be called with the value of type ``double``. - \endrst - */ -template -typename std::result_of::type - visit(Visitor &&vis, basic_format_arg arg) { - switch (arg.type_) { - case internal::NONE: - case internal::NAMED_ARG: - FMT_ASSERT(false, "invalid argument type"); - break; - case internal::INT: - return vis(arg.int_value); - case internal::UINT: - return vis(arg.uint_value); - case internal::LONG_LONG: - return vis(arg.long_long_value); - case internal::ULONG_LONG: - return vis(arg.ulong_long_value); - case internal::BOOL: - return vis(arg.int_value != 0); - case internal::CHAR: - return vis(static_cast(arg.int_value)); - case internal::DOUBLE: - return vis(arg.double_value); - case internal::LONG_DOUBLE: - return vis(arg.long_double_value); - case internal::CSTRING: - return vis(arg.string.value); - case internal::STRING: - return vis(StringRef(arg.string.value, arg.string.size)); - case internal::TSTRING: - return vis(BasicStringRef(arg.tstring.value, arg.tstring.size)); - case internal::POINTER: - return vis(arg.pointer); - case internal::CUSTOM: - return vis(arg.custom); - } - return typename std::result_of::type(); -} - -namespace internal { - -template -struct NamedArg; +template +struct False { enum { value = 0 }; }; template struct Null {}; @@ -1190,71 +1071,49 @@ FMT_DISABLE_CONVERSION_TO_INT(float); FMT_DISABLE_CONVERSION_TO_INT(double); FMT_DISABLE_CONVERSION_TO_INT(long double); -template -struct EnableIf {}; - -template -struct EnableIf { typedef T type; }; - -template -struct Conditional { typedef T type; }; - -template -struct Conditional { typedef F type; }; - -// For bcc32 which doesn't understand ! in template arguments. -template -struct Not { enum { value = 0 }; }; - -template <> -struct Not { enum { value = 1 }; }; - -template -struct False { enum { value = 0 }; }; - -template struct LConvCheck { - LConvCheck(int) {} +enum Type { + NONE, NAMED_ARG, + // Integer types should go first, + INT, UINT, LONG_LONG, ULONG_LONG, BOOL, CHAR, LAST_INTEGER_TYPE = CHAR, + // followed by floating-point types. + DOUBLE, LONG_DOUBLE, LAST_NUMERIC_TYPE = LONG_DOUBLE, + CSTRING, STRING, TSTRING, POINTER, CUSTOM }; -// Returns the thousands separator for the current locale. -// We check if ``lconv`` contains ``thousands_sep`` because on Android -// ``lconv`` is stubbed as an empty struct. -template -inline StringRef thousands_sep( - LConv *lc, LConvCheck = 0) { - return lc->thousands_sep; -} +template +struct StringValue { + const Char *value; + std::size_t size; +}; -inline fmt::StringRef thousands_sep(...) { return ""; } +typedef void (*FormatFunc)(void *writer, const void *arg, void *ctx); -#define FMT_CONCAT(a, b) a##b +struct CustomValue { + const void *value; + FormatFunc format; +}; -#if FMT_GCC_VERSION >= 407 -# define FMT_UNUSED __attribute__((unused)) -#else -# define FMT_UNUSED -#endif +// A formatting argument value. +template +struct Value { + union { + int int_value; + unsigned uint_value; + LongLong long_long_value; + ULongLong ulong_long_value; + double double_value; + long double long_double_value; + const void *pointer; + StringValue string; + StringValue sstring; + StringValue ustring; + StringValue tstring; + CustomValue custom; + }; +}; -#ifndef FMT_USE_STATIC_ASSERT -# define FMT_USE_STATIC_ASSERT 0 -#endif - -#if FMT_USE_STATIC_ASSERT || FMT_HAS_FEATURE(cxx_static_assert) || \ - (FMT_GCC_VERSION >= 403 && FMT_HAS_GXX_CXX11) || _MSC_VER >= 1600 -# define FMT_STATIC_ASSERT(cond, message) static_assert(cond, message) -#else -# define FMT_CONCAT_(a, b) FMT_CONCAT(a, b) -# define FMT_STATIC_ASSERT(cond, message) \ - typedef int FMT_CONCAT_(Assert, __LINE__)[(cond) ? 1 : -1] FMT_UNUSED -#endif - -template -void format_value(BasicWriter &, const T &, Formatter &, const Char *) { - FMT_STATIC_ASSERT(False::value, - "Cannot format argument. To enable the use of ostream " - "operator<< include fmt/ostream.h. Otherwise provide " - "an overload of format_arg."); -} +template +struct NamedArg; template struct IsNamedArg : std::false_type {}; @@ -1264,81 +1123,57 @@ struct IsNamedArg< NamedArg > : std::true_type {}; template constexpr Type gettype() { - typedef format_arg Arg; return IsNamedArg::value ? - internal::NAMED_ARG : - (ConvertToInt::value ? internal::INT : internal::CUSTOM); + NAMED_ARG : (ConvertToInt::value ? INT : CUSTOM); } -template <> constexpr Type gettype() { return internal::BOOL; } -template <> constexpr Type gettype() { return internal::INT; } -template <> constexpr Type gettype() { - return internal::UINT; -} -template <> constexpr Type gettype() { return internal::INT; } -template <> constexpr Type gettype() { return internal::UINT; } +template <> constexpr Type gettype() { return BOOL; } +template <> constexpr Type gettype() { return INT; } +template <> constexpr Type gettype() { return UINT; } +template <> constexpr Type gettype() { return INT; } +template <> constexpr Type gettype() { return UINT; } template <> constexpr Type gettype() { - return sizeof(long) == sizeof(int) ? internal::INT : internal::LONG_LONG; + return sizeof(long) == sizeof(int) ? INT : LONG_LONG; } template <> constexpr Type gettype() { return sizeof(unsigned long) == sizeof(unsigned) ? - internal::UINT : internal::ULONG_LONG; + UINT : ULONG_LONG; } -template <> constexpr Type gettype() { return internal::LONG_LONG; } -template <> constexpr Type gettype() { - return internal::ULONG_LONG; -} -template <> constexpr Type gettype() { return internal::DOUBLE; } -template <> constexpr Type gettype() { return internal::DOUBLE; } -template <> constexpr Type gettype() { - return internal::LONG_DOUBLE; -} -template <> constexpr Type gettype() { return internal::INT; } -template <> constexpr Type gettype() { return internal::UINT; } -template <> constexpr Type gettype() { return internal::CHAR; } +template <> constexpr Type gettype() { return LONG_LONG; } +template <> constexpr Type gettype() { return ULONG_LONG; } +template <> constexpr Type gettype() { return DOUBLE; } +template <> constexpr Type gettype() { return DOUBLE; } +template <> constexpr Type gettype() { return LONG_DOUBLE; } +template <> constexpr Type gettype() { return INT; } +template <> constexpr Type gettype() { return UINT; } +template <> constexpr Type gettype() { return CHAR; } #if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED) -template <> constexpr Type gettype() { return internal::CHAR; } +template <> constexpr Type gettype() { return CHAR; } #endif -template <> constexpr Type gettype() { return internal::CSTRING; } -template <> constexpr Type gettype() { - return internal::CSTRING; -} -template <> constexpr Type gettype() { - return internal::CSTRING; -} -template <> constexpr Type gettype() { - return internal::CSTRING; -} -template <> constexpr Type gettype() { - return internal::CSTRING; -} -template <> constexpr Type gettype() { - return internal::CSTRING; -} -template <> constexpr Type gettype() { return internal::STRING; } -template <> constexpr Type gettype() { return internal::STRING; } -template <> constexpr Type gettype() { return internal::CSTRING; } -template <> constexpr Type gettype() { return internal::TSTRING; } -template <> constexpr Type gettype() { - return internal::TSTRING; -} -template <> constexpr Type gettype() { - return internal::TSTRING; -} -template <> constexpr Type gettype() { return internal::TSTRING; } -template <> constexpr Type gettype() { return internal::POINTER; } -template <> constexpr Type gettype() { - return internal::POINTER; -} +template <> constexpr Type gettype() { return CSTRING; } +template <> constexpr Type gettype() { return CSTRING; } +template <> constexpr Type gettype() { return CSTRING; } +template <> constexpr Type gettype() { return CSTRING; } +template <> constexpr Type gettype() { return CSTRING; } +template <> constexpr Type gettype() { return CSTRING; } +template <> constexpr Type gettype() { return STRING; } +template <> constexpr Type gettype() { return STRING; } +template <> constexpr Type gettype() { return CSTRING; } +template <> constexpr Type gettype() { return TSTRING; } +template <> constexpr Type gettype() { return TSTRING; } +template <> constexpr Type gettype() { return TSTRING; } +template <> constexpr Type gettype() { return TSTRING; } +template <> constexpr Type gettype() { return POINTER; } +template <> constexpr Type gettype() { return POINTER; } template constexpr Type type() { return gettype::type>(); } // Makes a format_arg object from any type. template -class MakeValue : public basic_format_arg { +class MakeValue : public Value { public: typedef typename Context::char_type Char; @@ -1492,20 +1327,165 @@ class MakeValue : public basic_format_arg { } }; +template +class ArgMap; +} // namespace internal + +template +class basic_format_args; + +// A formatting argument. It is a trivially copyable/constructible type to +// allow storage in internal::MemoryBuffer. +template +class basic_format_arg { + protected: + internal::Value value_; + internal::Type type_; + + template + friend typename std::result_of::type + visit(Visitor &&vis, basic_format_arg arg); + + template + friend class basic_format_args; + + template + friend class internal::ArgMap; + + void check_type() const { + FMT_ASSERT(type_ > internal::NAMED_ARG, "invalid argument type"); + } + + public: + basic_format_arg() : type_(internal::NONE) {} + + explicit operator bool() const noexcept { return type_ != internal::NONE; } + + bool is_integral() const { + check_type(); + return type_ <= internal::LAST_INTEGER_TYPE; + } + + bool is_numeric() const { + check_type(); + return type_ <= internal::LAST_NUMERIC_TYPE; + } + + bool is_pointer() const { + check_type(); + return type_ == internal::POINTER; + } +}; + +typedef basic_format_arg format_arg; +typedef basic_format_arg wformat_arg; + +/** + \rst + Visits an argument dispatching to the appropriate visit method based on + the argument type. For example, if the argument type is ``double`` then + ``vis(value)`` will be called with the value of type ``double``. + \endrst + */ +template +typename std::result_of::type + visit(Visitor &&vis, basic_format_arg arg) { + switch (arg.type_) { + case internal::NONE: + case internal::NAMED_ARG: + FMT_ASSERT(false, "invalid argument type"); + break; + case internal::INT: + return vis(arg.value_.int_value); + case internal::UINT: + return vis(arg.value_.uint_value); + case internal::LONG_LONG: + return vis(arg.value_.long_long_value); + case internal::ULONG_LONG: + return vis(arg.value_.ulong_long_value); + case internal::BOOL: + return vis(arg.value_.int_value != 0); + case internal::CHAR: + return vis(static_cast(arg.value_.int_value)); + case internal::DOUBLE: + return vis(arg.value_.double_value); + case internal::LONG_DOUBLE: + return vis(arg.value_.long_double_value); + case internal::CSTRING: + return vis(arg.value_.string.value); + case internal::STRING: + return vis(StringRef(arg.value_.string.value, arg.value_.string.size)); + case internal::TSTRING: + return vis(BasicStringRef( + arg.value_.tstring.value, arg.value_.tstring.size)); + case internal::POINTER: + return vis(arg.value_.pointer); + case internal::CUSTOM: + return vis(arg.value_.custom); + } + return typename std::result_of::type(); +} + +namespace internal { + template class MakeArg : public basic_format_arg { -public: + public: MakeArg() { this->type_ = internal::NONE; } template - MakeArg(const T &value) - : basic_format_arg(MakeValue(value)) { + MakeArg(const T &value) { + this->value_ = internal::MakeValue(value); this->type_ = internal::type(); } }; +template struct LConvCheck { + LConvCheck(int) {} +}; + +// Returns the thousands separator for the current locale. +// We check if ``lconv`` contains ``thousands_sep`` because on Android +// ``lconv`` is stubbed as an empty struct. +template +inline StringRef thousands_sep( + LConv *lc, LConvCheck = 0) { + return lc->thousands_sep; +} + +inline fmt::StringRef thousands_sep(...) { return ""; } + +#define FMT_CONCAT(a, b) a##b + +#if FMT_GCC_VERSION >= 407 +# define FMT_UNUSED __attribute__((unused)) +#else +# define FMT_UNUSED +#endif + +#ifndef FMT_USE_STATIC_ASSERT +# define FMT_USE_STATIC_ASSERT 0 +#endif + +#if FMT_USE_STATIC_ASSERT || FMT_HAS_FEATURE(cxx_static_assert) || \ + (FMT_GCC_VERSION >= 403 && FMT_HAS_GXX_CXX11) || _MSC_VER >= 1600 +# define FMT_STATIC_ASSERT(cond, message) static_assert(cond, message) +#else +# define FMT_CONCAT_(a, b) FMT_CONCAT(a, b) +# define FMT_STATIC_ASSERT(cond, message) \ + typedef int FMT_CONCAT_(Assert, __LINE__)[(cond) ? 1 : -1] FMT_UNUSED +#endif + +template +void format_value(BasicWriter &, const T &, Formatter &, const Char *) { + FMT_STATIC_ASSERT(False::value, + "Cannot format argument. To enable the use of ostream " + "operator<< include fmt/ostream.h. Otherwise provide " + "an overload of format_arg."); +} + template struct NamedArg : basic_format_arg { BasicStringRef name; @@ -1532,27 +1512,39 @@ constexpr uint64_t make_type() { return 0; } // Maximum number of arguments with packed types. enum { MAX_PACKED_ARGS = 16 }; + +template +inline typename std::enable_if>::type + make_arg(const T& value) { + return MakeValue(value); +} + +template +inline typename std::enable_if::type + make_arg(const T& value) { + return MakeArg(value); +} } // namespace internal template class format_arg_store { private: static const size_t NUM_ARGS = sizeof...(Args); - static const bool IS_PACKED = NUM_ARGS < internal::MAX_PACKED_ARGS; + static const bool PACKED = NUM_ARGS < internal::MAX_PACKED_ARGS; typedef typename Context::char_type char_type; - typedef typename std::conditional, basic_format_arg>::type value_type; // If the arguments are not packed, add one more element to mark the end. - std::array data_; + std::array data_; public: static const uint64_t TYPES = internal::make_type(); format_arg_store(const Args &... args) - : data_{{internal::MakeArg(args)...}} {} + : data_{{internal::make_arg(args)...}} {} const value_type *data() const { return data_.data(); } }; @@ -1607,9 +1599,9 @@ class basic_format_args { bool use_values = type(internal::MAX_PACKED_ARGS - 1) == internal::NONE; if (index < internal::MAX_PACKED_ARGS) { typename internal::Type arg_type = type(index); - internal::Value &val = arg; + internal::Value &val = arg.value_; if (arg_type != internal::NONE) - val = use_values ? values_[index] : args_[index]; + val = use_values ? values_[index] : args_[index].value_; arg.type_ = arg_type; return arg; } @@ -1639,7 +1631,7 @@ class basic_format_args { format_arg operator[](size_type index) const { format_arg arg = get(index); return arg.type_ == internal::NAMED_ARG ? - *static_cast(arg.pointer) : arg; + *static_cast(arg.value_.pointer) : arg; } }; @@ -1922,7 +1914,7 @@ void ArgMap::init(const basic_format_args &args) { for (unsigned i = 0; i != MAX_PACKED_ARGS; ++i) { internal::Type arg_type = args.type(i); if (arg_type == internal::NAMED_ARG) { - named_arg = static_cast(args.args_[i].pointer); + named_arg = static_cast(args.args_[i].value_.pointer); map_.push_back(Pair(named_arg->name, *named_arg)); } } @@ -1931,7 +1923,7 @@ void ArgMap::init(const basic_format_args &args) { case internal::NONE: return; case internal::NAMED_ARG: - named_arg = static_cast(args.args_[i].pointer); + named_arg = static_cast(args.args_[i].value_.pointer); map_.push_back(Pair(named_arg->name, *named_arg)); break; default: @@ -3497,7 +3489,7 @@ void do_format_arg(BasicWriter &writer, const basic_format_arg &arg, spec.fill_ = c; } else ++s; if (spec.align_ == ALIGN_NUMERIC) - require_numeric_argument(arg, '='); + internal::require_numeric_argument(arg, '='); break; } } while (--p >= s); @@ -3506,28 +3498,28 @@ void do_format_arg(BasicWriter &writer, const basic_format_arg &arg, // Parse sign. switch (*s) { case '+': - check_sign(s, arg); + internal::check_sign(s, arg); spec.flags_ |= SIGN_FLAG | PLUS_FLAG; break; case '-': - check_sign(s, arg); + internal::check_sign(s, arg); spec.flags_ |= MINUS_FLAG; break; case ' ': - check_sign(s, arg); + internal::check_sign(s, arg); spec.flags_ |= SIGN_FLAG; break; } if (*s == '#') { - require_numeric_argument(arg, '#'); + internal::require_numeric_argument(arg, '#'); spec.flags_ |= HASH_FLAG; ++s; } // Parse zero flag. if (*s == '0') { - require_numeric_argument(arg, '0'); + internal::require_numeric_argument(arg, '0'); spec.align_ = ALIGN_NUMERIC; spec.fill_ = '0'; ++s; diff --git a/test/util-test.cc b/test/util-test.cc index ec98ef5a..b20fe54f 100644 --- a/test/util-test.cc +++ b/test/util-test.cc @@ -424,7 +424,7 @@ void format_value(fmt::Writer &, const Test &, CustomFormatter &ctx) { TEST(UtilTest, MakeValueWithCustomFormatter) { ::Test t; - format_arg arg = fmt::internal::MakeValue(t); + fmt::internal::Value arg = fmt::internal::MakeValue(t); CustomFormatter ctx = {false}; fmt::MemoryWriter w; arg.custom.format(&w, &t, &ctx); From 63fcfc57985e1e8bd24c675765b979583e821b51 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Mon, 26 Dec 2016 10:55:30 -0800 Subject: [PATCH 059/340] Fix build on older gcc --- fmt/format.h | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/fmt/format.h b/fmt/format.h index 91c4cee9..8911c4d4 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -1520,7 +1520,8 @@ inline typename std::enable_if>::type } template -inline typename std::enable_if::type +inline typename std::enable_if< + !PACKED, basic_format_arg>::type make_arg(const T& value) { return MakeArg(value); } @@ -1538,13 +1539,14 @@ class format_arg_store { internal::Value, basic_format_arg>::type value_type; // If the arguments are not packed, add one more element to mark the end. - std::array data_; + typedef std::array Array; + Array data_; public: static const uint64_t TYPES = internal::make_type(); format_arg_store(const Args &... args) - : data_{{internal::make_arg(args)...}} {} + : data_(Array{internal::make_arg(args)...}) {} const value_type *data() const { return data_.data(); } }; From 3bbc5799b6f1c4fc79d1e4d0e087a3a31da788e3 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Mon, 26 Dec 2016 11:26:41 -0800 Subject: [PATCH 060/340] Fix MinGW build --- fmt/format.h | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/fmt/format.h b/fmt/format.h index 8911c4d4..5bc2911d 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -1513,15 +1513,16 @@ constexpr uint64_t make_type() { return 0; } // Maximum number of arguments with packed types. enum { MAX_PACKED_ARGS = 16 }; -template -inline typename std::enable_if>::type +template +inline typename std::enable_if< + IS_PACKED, Value>::type make_arg(const T& value) { return MakeValue(value); } -template +template inline typename std::enable_if< - !PACKED, basic_format_arg>::type + !IS_PACKED, basic_format_arg>::type make_arg(const T& value) { return MakeArg(value); } @@ -1531,22 +1532,24 @@ template class format_arg_store { private: static const size_t NUM_ARGS = sizeof...(Args); - static const bool PACKED = NUM_ARGS < internal::MAX_PACKED_ARGS; + + // Packed is a macro on MinGW so use IS_PACKED instead. + static const bool IS_PACKED = NUM_ARGS < internal::MAX_PACKED_ARGS; typedef typename Context::char_type char_type; - typedef typename std::conditional, basic_format_arg>::type value_type; // If the arguments are not packed, add one more element to mark the end. - typedef std::array Array; + typedef std::array Array; Array data_; public: static const uint64_t TYPES = internal::make_type(); format_arg_store(const Args &... args) - : data_(Array{internal::make_arg(args)...}) {} + : data_(Array{internal::make_arg(args)...}) {} const value_type *data() const { return data_.data(); } }; From ee1651ce07bba91822672779bdd1add8b9648b6c Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Tue, 27 Dec 2016 07:43:25 -0800 Subject: [PATCH 061/340] Handle empty format_arg state --- fmt/format.h | 20 +++++++++++--------- test/util-test.cc | 7 +++++-- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/fmt/format.h b/fmt/format.h index 5bc2911d..a284468b 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -1331,6 +1331,8 @@ template class ArgMap; } // namespace internal +struct monostate {}; + template class basic_format_args; @@ -1352,27 +1354,22 @@ class basic_format_arg { template friend class internal::ArgMap; - void check_type() const { - FMT_ASSERT(type_ > internal::NAMED_ARG, "invalid argument type"); - } - public: basic_format_arg() : type_(internal::NONE) {} explicit operator bool() const noexcept { return type_ != internal::NONE; } bool is_integral() const { - check_type(); - return type_ <= internal::LAST_INTEGER_TYPE; + FMT_ASSERT(type_ != internal::NAMED_ARG, "invalid argument type"); + return type_ > internal::NONE && type_ <= internal::LAST_INTEGER_TYPE; } bool is_numeric() const { - check_type(); - return type_ <= internal::LAST_NUMERIC_TYPE; + FMT_ASSERT(type_ != internal::NAMED_ARG, "invalid argument type"); + return type_ > internal::NONE && type_ <= internal::LAST_NUMERIC_TYPE; } bool is_pointer() const { - check_type(); return type_ == internal::POINTER; } }; @@ -1392,6 +1389,7 @@ typename std::result_of::type visit(Visitor &&vis, basic_format_arg arg) { switch (arg.type_) { case internal::NONE: + return vis(monostate()); case internal::NAMED_ARG: FMT_ASSERT(false, "invalid argument type"); break; @@ -1986,6 +1984,10 @@ class ArgFormatterBase { ArgFormatterBase(BasicWriter &w, FormatSpec &s) : writer_(w), spec_(s) {} + void operator()(monostate) { + FMT_ASSERT(false, "invalid argument type"); + } + template typename std::enable_if::value>::type operator()(T value) { writer_.write_int(value, spec_); } diff --git a/test/util-test.cc b/test/util-test.cc index b20fe54f..69569e43 100644 --- a/test/util-test.cc +++ b/test/util-test.cc @@ -579,8 +579,11 @@ TEST(UtilTest, CustomArg) { } TEST(ArgVisitorTest, VisitInvalidArg) { - format_arg arg = format_arg(); - EXPECT_ASSERT(visit(MockVisitor(), arg), "invalid argument type"); + typedef MockVisitor Visitor; + testing::StrictMock visitor; + EXPECT_CALL(visitor, visit(_)); + format_arg arg; + visit(visitor, arg); } // Tests fmt::internal::count_digits for integer type Int. From abb6996f36c73b868139cc74ac91dce2a4a7690f Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Tue, 27 Dec 2016 07:55:44 -0800 Subject: [PATCH 062/340] MakeArg -> make_arg --- fmt/format.h | 36 ++++++++++++++++++++---------------- fmt/ostream.h | 4 ++-- fmt/printf.h | 10 +++++----- test/format-impl-test.cc | 2 +- test/ostream-test.cc | 2 +- test/util-test.cc | 3 +-- 6 files changed, 30 insertions(+), 27 deletions(-) diff --git a/fmt/format.h b/fmt/format.h index a284468b..dc8ce0c9 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -371,6 +371,9 @@ class BasicWriter; typedef BasicWriter Writer; typedef BasicWriter WWriter; +template +class basic_format_arg; + template class ArgFormatter; @@ -1329,6 +1332,9 @@ class MakeValue : public Value { template class ArgMap; + +template +basic_format_arg make_arg(const T &value); } // namespace internal struct monostate {}; @@ -1340,10 +1346,14 @@ class basic_format_args; // allow storage in internal::MemoryBuffer. template class basic_format_arg { - protected: + private: internal::Value value_; internal::Type type_; + template + friend basic_format_arg + internal::make_arg(const T &value); + template friend typename std::result_of::type visit(Visitor &&vis, basic_format_arg arg); @@ -1426,19 +1436,13 @@ typename std::result_of::type namespace internal { -template - class MakeArg : public basic_format_arg { - public: - MakeArg() { - this->type_ = internal::NONE; - } - - template - MakeArg(const T &value) { - this->value_ = internal::MakeValue(value); - this->type_ = internal::type(); - } -}; +template +basic_format_arg make_arg(const T &value) { + basic_format_arg arg; + arg.type_ = internal::type(); + arg.value_ = internal::MakeValue(value); + return arg; +} template struct LConvCheck { LConvCheck(int) {} @@ -1490,7 +1494,7 @@ struct NamedArg : basic_format_arg { template NamedArg(BasicStringRef argname, const T &value) - : basic_format_arg(MakeArg< basic_format_context >(value)), + : basic_format_arg(make_arg< basic_format_context >(value)), name(argname) {} }; @@ -1522,7 +1526,7 @@ template inline typename std::enable_if< !IS_PACKED, basic_format_arg>::type make_arg(const T& value) { - return MakeArg(value); + return make_arg(value); } } // namespace internal diff --git a/fmt/ostream.h b/fmt/ostream.h index c623b542..74ccadf4 100644 --- a/fmt/ostream.h +++ b/fmt/ostream.h @@ -87,8 +87,8 @@ void format_value(BasicWriter &w, const T &value, basic_format_context &ctx) { internal::MemoryBuffer buffer; auto str = internal::format_value(buffer, value); - typedef internal::MakeArg< basic_format_context > MakeArg; - do_format_arg< ArgFormatter >(w, MakeArg(str), ctx); + do_format_arg< ArgFormatter >( + w, internal::make_arg< basic_format_context >(str), ctx); } FMT_API void vprint(std::ostream &os, CStringRef format_str, format_args args); diff --git a/fmt/printf.h b/fmt/printf.h index 47d868e6..c0064ae7 100644 --- a/fmt/printf.h +++ b/fmt/printf.h @@ -105,11 +105,11 @@ class ArgConverter { if (sizeof(TargetType) <= sizeof(int)) { // Extra casts are used to silence warnings. if (is_signed) { - arg_ = internal::MakeArg( + arg_ = internal::make_arg( static_cast(static_cast(value))); } else { typedef typename internal::MakeUnsigned::Type Unsigned; - arg_ = internal::MakeArg( + arg_ = internal::make_arg( static_cast(static_cast(value))); } } else { @@ -117,10 +117,10 @@ class ArgConverter { // glibc's printf doesn't sign extend arguments of smaller types: // std::printf("%lld", -42); // prints "4294967254" // but we don't have to do the same because it's a UB. - arg_ = internal::MakeArg( + arg_ = internal::make_arg( static_cast(value)); } else { - arg_ = internal::MakeArg( + arg_ = internal::make_arg( static_cast::Type>(value)); } } @@ -157,7 +157,7 @@ class CharConverter { typename std::enable_if::value>::type operator()(T value) { arg_ = - internal::MakeArg>(static_cast(value)); + internal::make_arg>(static_cast(value)); } template diff --git a/test/format-impl-test.cc b/test/format-impl-test.cc index ff702a53..8a0afb02 100644 --- a/test/format-impl-test.cc +++ b/test/format-impl-test.cc @@ -57,7 +57,7 @@ struct ValueExtractor { TEST(FormatTest, ArgConverter) { using fmt::format_arg; fmt::LongLong value = std::numeric_limits::max(); - format_arg arg = fmt::internal::MakeArg(value); + format_arg arg = fmt::internal::make_arg(value); visit(fmt::internal::ArgConverter(arg, 'd'), arg); EXPECT_EQ(value, visit(ValueExtractor(), arg)); } diff --git a/test/ostream-test.cc b/test/ostream-test.cc index b46418b4..069c8092 100644 --- a/test/ostream-test.cc +++ b/test/ostream-test.cc @@ -69,7 +69,7 @@ TEST(OStreamTest, CustomArg) { fmt::format_context ctx("}", fmt::format_args()); fmt::FormatSpec spec; TestArgFormatter af(writer, ctx, spec); - visit(af, fmt::internal::MakeArg(TestEnum())); + visit(af, fmt::internal::make_arg(TestEnum())); EXPECT_EQ("TestEnum", writer.str()); } diff --git a/test/util-test.cc b/test/util-test.cc index 69569e43..e02b68d8 100644 --- a/test/util-test.cc +++ b/test/util-test.cc @@ -75,8 +75,7 @@ void format_value(fmt::BasicWriter &w, Test, template basic_format_arg make_arg(const T &value) { - typedef fmt::internal::MakeArg< fmt::basic_format_context > MakeArg; - return MakeArg(value); + return fmt::internal::make_arg< fmt::basic_format_context >(value); } } // namespace From 422236af7c07da132d9c487e9f124d53609d5c86 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Wed, 28 Dec 2016 07:55:33 -0800 Subject: [PATCH 063/340] Don't erase writer type --- fmt/format.h | 21 +++++++++++---------- fmt/printf.h | 4 ++-- test/format-test.cc | 2 +- test/util-test.cc | 11 ++++++----- 4 files changed, 20 insertions(+), 18 deletions(-) diff --git a/fmt/format.h b/fmt/format.h index dc8ce0c9..723e5395 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -1089,9 +1089,11 @@ struct StringValue { std::size_t size; }; -typedef void (*FormatFunc)(void *writer, const void *arg, void *ctx); - +template struct CustomValue { + typedef void (*FormatFunc)( + BasicWriter &writer, const void *arg, void *ctx); + const void *value; FormatFunc format; }; @@ -1111,7 +1113,7 @@ struct Value { StringValue sstring; StringValue ustring; StringValue tstring; - CustomValue custom; + CustomValue custom; }; }; @@ -1216,9 +1218,8 @@ class MakeValue : public Value { // Formats an argument of a custom type, such as a user-defined class. template static void format_custom_arg( - void *writer, const void *arg, void *context) { - format_value(*static_cast*>(writer), - *static_cast(arg), + BasicWriter &writer, const void *arg, void *context) { + format_value(writer, *static_cast(arg), *static_cast(context)); } @@ -2140,8 +2141,8 @@ class ArgFormatter : public internal::ArgFormatterBase { using internal::ArgFormatterBase::operator(); /** Formats an argument of a custom (user-defined) type. */ - void operator()(internal::CustomValue c) { - c.format(&this->writer(), c.value, &ctx_); + void operator()(internal::CustomValue c) { + c.format(this->writer(), c.value, &ctx_); } }; @@ -3371,8 +3372,8 @@ class CustomFormatter { CustomFormatter(BasicWriter &writer, Context &ctx) : writer_(writer), ctx_(ctx) {} - bool operator()(internal::CustomValue custom) { - custom.format(&writer_, custom.value, &ctx_); + bool operator()(internal::CustomValue custom) { + custom.format(writer_, custom.value, &ctx_); return true; } diff --git a/fmt/printf.h b/fmt/printf.h index c0064ae7..92d50ef4 100644 --- a/fmt/printf.h +++ b/fmt/printf.h @@ -281,11 +281,11 @@ class PrintfArgFormatter : public internal::ArgFormatterBase { } /** Formats an argument of a custom (user-defined) type. */ - void operator()(internal::CustomValue c) { + void operator()(internal::CustomValue c) { const Char format_str[] = {'}', '\0'}; auto args = basic_format_args, Char>(); basic_format_context ctx(format_str, args); - c.format(&this->writer(), c.value, &ctx); + c.format(this->writer(), c.value, &ctx); } }; diff --git a/test/format-test.cc b/test/format-test.cc index 6829f622..b8693d5e 100644 --- a/test/format-test.cc +++ b/test/format-test.cc @@ -1637,7 +1637,7 @@ class MockArgFormatter : public fmt::internal::ArgFormatterBase { void operator()(int value) { call(value); } - void operator()(fmt::internal::CustomValue) {} + void operator()(fmt::internal::CustomValue) {} }; void custom_vformat(fmt::CStringRef format_str, fmt::format_args args) { diff --git a/test/util-test.cc b/test/util-test.cc index e02b68d8..0e276d52 100644 --- a/test/util-test.cc +++ b/test/util-test.cc @@ -426,14 +426,15 @@ TEST(UtilTest, MakeValueWithCustomFormatter) { fmt::internal::Value arg = fmt::internal::MakeValue(t); CustomFormatter ctx = {false}; fmt::MemoryWriter w; - arg.custom.format(&w, &t, &ctx); + arg.custom.format(w, &t, &ctx); EXPECT_TRUE(ctx.called); } namespace fmt { namespace internal { -bool operator==(CustomValue lhs, CustomValue rhs) { +template +bool operator==(CustomValue lhs, CustomValue rhs) { return lhs.value == rhs.value; } } @@ -563,14 +564,14 @@ TEST(UtilTest, PointerArg) { TEST(UtilTest, CustomArg) { ::Test test; - typedef MockVisitor Visitor; + typedef MockVisitor> Visitor; testing::StrictMock visitor; EXPECT_CALL(visitor, visit(_)).WillOnce( - testing::Invoke([&](fmt::internal::CustomValue custom) { + testing::Invoke([&](fmt::internal::CustomValue custom) { EXPECT_EQ(&test, custom.value); fmt::MemoryWriter w; fmt::format_context ctx("}", fmt::format_args()); - custom.format(&w, &test, &ctx); + custom.format(w, &test, &ctx); EXPECT_EQ("test", w.str()); return Visitor::Result(); })); From d705d51671cd651d841add57688b71d7916a1cb4 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Thu, 29 Dec 2016 09:07:39 -0800 Subject: [PATCH 064/340] Parameterize basic_format_arg on context (#442) --- fmt/format.cc | 6 +- fmt/format.h | 137 ++++++++++++++++++++------------------- fmt/printf.h | 49 +++++++------- test/format-impl-test.cc | 3 +- test/util-test.cc | 10 +-- 5 files changed, 105 insertions(+), 100 deletions(-) diff --git a/fmt/format.cc b/fmt/format.cc index 3e2a6eec..92479615 100644 --- a/fmt/format.cc +++ b/fmt/format.cc @@ -458,7 +458,7 @@ template struct internal::BasicData; template void internal::FixedBuffer::grow(std::size_t); -template void internal::ArgMap::init(const format_args &args); +template void internal::ArgMap::init(const format_args &args); template void printf_context::format(Writer &writer); @@ -472,9 +472,11 @@ template int internal::CharTraits::format_float( // Explicit instantiations for wchar_t. +template class basic_format_context; + template void internal::FixedBuffer::grow(std::size_t); -template void internal::ArgMap::init(const wformat_args &args); +template void internal::ArgMap::init(const wformat_args &args); template void printf_context::format(WWriter &writer); diff --git a/fmt/format.h b/fmt/format.h index 723e5395..3f9de274 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -230,10 +230,9 @@ typedef __int64 intmax_t; # define FMT_BUILTIN_CLZLL(n) __builtin_clzll(n) #endif -// Some compilers masquerade as both MSVC and GCC-likes or -// otherwise support __builtin_clz and __builtin_clzll, so -// only define FMT_BUILTIN_CLZ using the MSVC intrinsics -// if the clz and clzll builtins are not available. +// Some compilers masquerade as both MSVC and GCC-likes or otherwise support +// __builtin_clz and __builtin_clzll, so only define FMT_BUILTIN_CLZ using the +// MSVC intrinsics if the clz and clzll builtins are not available. #if FMT_MSC_VER && !defined(FMT_BUILTIN_CLZLL) # include // _BitScanReverse, _BitScanReverse64 @@ -371,7 +370,7 @@ class BasicWriter; typedef BasicWriter Writer; typedef BasicWriter WWriter; -template +template class basic_format_arg; template @@ -1331,11 +1330,11 @@ class MakeValue : public Value { } }; -template +template class ArgMap; template -basic_format_arg make_arg(const T &value); +basic_format_arg make_arg(const T &value); } // namespace internal struct monostate {}; @@ -1345,25 +1344,25 @@ class basic_format_args; // A formatting argument. It is a trivially copyable/constructible type to // allow storage in internal::MemoryBuffer. -template +template class basic_format_arg { private: + typedef typename Context::char_type Char; + internal::Value value_; internal::Type type_; - template - friend basic_format_arg - internal::make_arg(const T &value); + template + friend basic_format_arg internal::make_arg(const T &value); - template + template friend typename std::result_of::type - visit(Visitor &&vis, basic_format_arg arg); + visit(Visitor &&vis, basic_format_arg arg); - template + template friend class basic_format_args; - template - friend class internal::ArgMap; + friend class internal::ArgMap; public: basic_format_arg() : type_(internal::NONE) {} @@ -1385,8 +1384,8 @@ class basic_format_arg { } }; -typedef basic_format_arg format_arg; -typedef basic_format_arg wformat_arg; +typedef basic_format_arg format_arg; +typedef basic_format_arg wformat_arg; /** \rst @@ -1395,9 +1394,10 @@ typedef basic_format_arg wformat_arg; ``vis(value)`` will be called with the value of type ``double``. \endrst */ -template +template typename std::result_of::type - visit(Visitor &&vis, basic_format_arg arg) { + visit(Visitor &&vis, basic_format_arg arg) { + typedef typename Context::char_type Char; switch (arg.type_) { case internal::NONE: return vis(monostate()); @@ -1438,8 +1438,8 @@ typename std::result_of::type namespace internal { template -basic_format_arg make_arg(const T &value) { - basic_format_arg arg; +basic_format_arg make_arg(const T &value) { + basic_format_arg arg; arg.type_ = internal::type(); arg.value_ = internal::MakeValue(value); return arg; @@ -1489,14 +1489,15 @@ void format_value(BasicWriter &, const T &, Formatter &, const Char *) { "an overload of format_arg."); } -template -struct NamedArg : basic_format_arg { +template +struct NamedArg : basic_format_arg { + typedef typename Context::char_type Char; + BasicStringRef name; template NamedArg(BasicStringRef argname, const T &value) - : basic_format_arg(make_arg< basic_format_context >(value)), - name(argname) {} + : basic_format_arg(make_arg(value)), name(argname) {} }; class RuntimeError : public std::runtime_error { @@ -1524,8 +1525,7 @@ inline typename std::enable_if< } template -inline typename std::enable_if< - !IS_PACKED, basic_format_arg>::type +inline typename std::enable_if>::type make_arg(const T& value) { return make_arg(value); } @@ -1542,7 +1542,7 @@ class format_arg_store { typedef typename Context::char_type char_type; typedef typename std::conditional, basic_format_arg>::type value_type; + internal::Value, basic_format_arg>::type value_type; // If the arguments are not packed, add one more element to mark the end. typedef std::array Array; @@ -1574,7 +1574,7 @@ template class basic_format_args { public: typedef unsigned size_type; - typedef basic_format_arg format_arg; + typedef basic_format_arg format_arg; private: // To reduce compiled code size per formatting function call, types of first @@ -1597,7 +1597,7 @@ class basic_format_args { (types_ & (mask << shift)) >> shift); } - friend class internal::ArgMap; + friend class internal::ArgMap; void set_data(const internal::Value *values) { values_ = values; } void set_data(const format_arg *args) { args_ = args; } @@ -1869,20 +1869,20 @@ inline StrFormatSpec pad( namespace internal { -template +template class ArgMap { private: + typedef typename Context::char_type Char; typedef std::vector< - std::pair, basic_format_arg > > MapType; + std::pair, basic_format_arg > > MapType; typedef typename MapType::value_type Pair; MapType map_; public: - template void init(const basic_format_args &args); - const basic_format_arg + const basic_format_arg *find(const fmt::BasicStringRef &name) const { // The list is unsorted, so just return the first matching name. for (typename MapType::const_iterator it = map_.begin(), end = map_.end(); @@ -1894,12 +1894,11 @@ class ArgMap { } }; -template template -void ArgMap::init(const basic_format_args &args) { +void ArgMap::init(const basic_format_args &args) { if (!map_.empty()) return; - typedef internal::NamedArg NamedArg; + typedef internal::NamedArg NamedArg; const NamedArg *named_arg = 0; bool use_values = args.type(MAX_PACKED_ARGS - 1) == internal::NONE; @@ -2072,7 +2071,7 @@ class format_context_base { int next_arg_index_; protected: - typedef basic_format_arg format_arg; + typedef basic_format_arg format_arg; format_context_base(const Char *format_str, basic_format_args args) @@ -2149,24 +2148,25 @@ class ArgFormatter : public internal::ArgFormatterBase { template class basic_format_context : public internal::format_context_base> { + public: + /** The character type for the output. */ + typedef Char char_type; + private: - internal::ArgMap map_; + internal::ArgMap> map_; FMT_DISALLOW_COPY_AND_ASSIGN(basic_format_context); typedef internal::format_context_base> Base; - using typename Base::format_arg; + typedef typename Base::format_arg format_arg; using Base::get_arg; // Checks if manual indexing is used and returns the argument with // specified name. - basic_format_arg get_arg(BasicStringRef name, const char *&error); + format_arg get_arg(BasicStringRef name, const char *&error); public: - /** The character type for the output. */ - typedef Char char_type; - /** \rst Constructs a ``basic_format_context`` object. References to the arguments are @@ -2178,7 +2178,7 @@ class basic_format_context : : Base(format_str, args) {} // Parses argument id and returns corresponding argument. - basic_format_arg parse_arg_id(); + format_arg parse_arg_id(); using Base::ptr; }; @@ -3274,21 +3274,23 @@ inline void format_decimal(char *&buffer, T value) { \endrst */ template -inline internal::NamedArg arg(StringRef name, const T &arg) { - return internal::NamedArg(name, arg); +inline internal::NamedArg arg(StringRef name, const T &arg) { + return internal::NamedArg(name, arg); } template -inline internal::NamedArg arg(WStringRef name, const T &arg) { - return internal::NamedArg(name, arg); +inline internal::NamedArg arg(WStringRef name, const T &arg) { + return internal::NamedArg(name, arg); } // The following two functions are deleted intentionally to disable // nested named arguments as in ``format("{}", arg("a", arg("b", 42)))``. -template -void arg(StringRef, const internal::NamedArg&) FMT_DELETED_OR_UNDEFINED; -template -void arg(WStringRef, const internal::NamedArg&) FMT_DELETED_OR_UNDEFINED; +template +void arg(StringRef, const internal::NamedArg&) + FMT_DELETED_OR_UNDEFINED; +template +void arg(WStringRef, const internal::NamedArg&) + FMT_DELETED_OR_UNDEFINED; } #if FMT_GCC_VERSION @@ -3351,8 +3353,8 @@ struct IsUnsigned { } }; -template -void check_sign(const Char *&s, const basic_format_arg &arg) { +template +void check_sign(const Char *&s, const basic_format_arg &arg) { char sign = static_cast(*s); require_numeric_argument(arg, sign); if (visit(IsUnsigned(), arg)) { @@ -3425,25 +3427,27 @@ struct PrecisionHandler { } // namespace internal template -inline basic_format_arg basic_format_context::get_arg( +inline typename basic_format_context::format_arg + basic_format_context::get_arg( BasicStringRef name, const char *&error) { if (this->check_no_auto_index(error)) { map_.init(this->args()); - const basic_format_arg *arg = map_.find(name); - if (arg) + if (const format_arg *arg = map_.find(name)) return *arg; error = "argument not found"; } - return basic_format_arg(); + return format_arg(); } template -inline basic_format_arg basic_format_context::parse_arg_id() { +inline typename basic_format_context::format_arg + basic_format_context::parse_arg_id() { const Char *&s = this->ptr(); if (!internal::is_name_start(*s)) { const char *error = 0; - basic_format_arg arg = *s < '0' || *s > '9' ? - this->next_arg(error) : get_arg(internal::parse_nonnegative_int(s), error); + format_arg arg = *s < '0' || *s > '9' ? + this->next_arg(error) : + get_arg(internal::parse_nonnegative_int(s), error); if (error) { FMT_THROW(format_error( *s != '}' && *s != ':' ? "invalid format string" : error)); @@ -3456,8 +3460,7 @@ inline basic_format_arg basic_format_context::parse_arg_id() { c = *++s; } while (internal::is_name_start(c) || ('0' <= c && c <= '9')); const char *error = 0; - basic_format_arg arg = - get_arg(BasicStringRef(start, s - start), error); + format_arg arg = get_arg(BasicStringRef(start, s - start), error); if (error) FMT_THROW(format_error(error)); return arg; @@ -3465,7 +3468,7 @@ inline basic_format_arg basic_format_context::parse_arg_id() { // Formats a single argument. template -void do_format_arg(BasicWriter &writer, const basic_format_arg &arg, +void do_format_arg(BasicWriter &writer, basic_format_arg arg, Context &ctx) { const Char *&s = ctx.ptr(); FormatSpec spec; @@ -3643,7 +3646,7 @@ struct UdlArg { const Char *str; template - NamedArg operator=(T &&value) const { + NamedArg> operator=(T &&value) const { return {str, std::forward(value)}; } }; diff --git a/fmt/printf.h b/fmt/printf.h index 92d50ef4..13b82afd 100644 --- a/fmt/printf.h +++ b/fmt/printf.h @@ -80,14 +80,16 @@ struct is_same { enum { value = 1 }; }; -template +template class ArgConverter { private: - basic_format_arg &arg_; - Char type_; + typedef typename Context::char_type Char; + + basic_format_arg &arg_; + typename Context::char_type type_; public: - ArgConverter(basic_format_arg &arg, Char type) + ArgConverter(basic_format_arg &arg, Char type) : arg_(arg), type_(type) {} void operator()(bool value) { @@ -105,11 +107,11 @@ class ArgConverter { if (sizeof(TargetType) <= sizeof(int)) { // Extra casts are used to silence warnings. if (is_signed) { - arg_ = internal::make_arg( + arg_ = internal::make_arg( static_cast(static_cast(value))); } else { typedef typename internal::MakeUnsigned::Type Unsigned; - arg_ = internal::make_arg( + arg_ = internal::make_arg( static_cast(static_cast(value))); } } else { @@ -117,10 +119,9 @@ class ArgConverter { // glibc's printf doesn't sign extend arguments of smaller types: // std::printf("%lld", -42); // prints "4294967254" // but we don't have to do the same because it's a UB. - arg_ = internal::make_arg( - static_cast(value)); + arg_ = internal::make_arg(static_cast(value)); } else { - arg_ = internal::make_arg( + arg_ = internal::make_arg( static_cast::Type>(value)); } } @@ -137,32 +138,30 @@ class ArgConverter { // If T is void, the argument is converted to corresponding signed or unsigned // type depending on the type specifier: 'd' and 'i' - signed, other - // unsigned). -template -void convert_arg(basic_format_arg &arg, Char type) { - visit(ArgConverter(arg, type), arg); +template +void convert_arg(basic_format_arg &arg, Char type) { + visit(ArgConverter(arg, type), arg); } // Converts an integer argument to char for printf. -template +template class CharConverter { private: - basic_format_arg &arg_; + basic_format_arg &arg_; FMT_DISALLOW_COPY_AND_ASSIGN(CharConverter); public: - explicit CharConverter(basic_format_arg &arg) : arg_(arg) {} + explicit CharConverter(basic_format_arg &arg) : arg_(arg) {} template typename std::enable_if::value>::type operator()(T value) { - arg_ = - internal::make_arg>(static_cast(value)); + arg_ = internal::make_arg(static_cast(value)); } template - typename std::enable_if::value>::type - operator()(T value) { + typename std::enable_if::value>::type operator()(T) { // No coversion needed for non-integral types. } }; @@ -301,12 +300,13 @@ class printf_context : private: typedef internal::format_context_base Base; + typedef typename Base::format_arg format_arg; void parse_flags(FormatSpec &spec, const Char *&s); // Returns the argument with specified index or, if arg_index is equal // to the maximum unsigned value, the next argument. - basic_format_arg get_arg( + format_arg get_arg( const Char *s, unsigned arg_index = (std::numeric_limits::max)()); @@ -356,12 +356,11 @@ void printf_context::parse_flags(FormatSpec &spec, const Char *&s) { } template -basic_format_arg printf_context::get_arg( +typename printf_context::format_arg printf_context::get_arg( const Char *s, unsigned arg_index) { (void)s; const char *error = 0; - basic_format_arg arg = - arg_index == std::numeric_limits::max() ? + format_arg arg = arg_index == std::numeric_limits::max() ? this->next_arg(error) : Base::get_arg(arg_index - 1, error); if (error) FMT_THROW(format_error(!*s ? "invalid format string" : error)); @@ -433,7 +432,7 @@ void printf_context::format(BasicWriter &writer) { } } - basic_format_arg arg = get_arg(s, arg_index); + format_arg arg = get_arg(s, arg_index); if (spec.flag(HASH_FLAG) && visit(internal::IsZeroInt(), arg)) spec.flags_ &= ~internal::to_unsigned(HASH_FLAG); if (spec.fill_ == '0') { @@ -488,7 +487,7 @@ void printf_context::format(BasicWriter &writer) { break; case 'c': // TODO: handle wchar_t - visit(internal::CharConverter(arg), arg); + visit(internal::CharConverter>(arg), arg); break; } } diff --git a/test/format-impl-test.cc b/test/format-impl-test.cc index 8a0afb02..40ee0a8a 100644 --- a/test/format-impl-test.cc +++ b/test/format-impl-test.cc @@ -58,7 +58,8 @@ TEST(FormatTest, ArgConverter) { using fmt::format_arg; fmt::LongLong value = std::numeric_limits::max(); format_arg arg = fmt::internal::make_arg(value); - visit(fmt::internal::ArgConverter(arg, 'd'), arg); + visit(fmt::internal::ArgConverter< + fmt::LongLong, fmt::format_context>(arg, 'd'), arg); EXPECT_EQ(value, visit(ValueExtractor(), arg)); } diff --git a/test/util-test.cc b/test/util-test.cc index 0e276d52..73d3ca8a 100644 --- a/test/util-test.cc +++ b/test/util-test.cc @@ -73,9 +73,9 @@ void format_value(fmt::BasicWriter &w, Test, w << "test"; } -template -basic_format_arg make_arg(const T &value) { - return fmt::internal::make_arg< fmt::basic_format_context >(value); +template +basic_format_arg make_arg(const T &value) { + return fmt::internal::make_arg(value); } } // namespace @@ -487,7 +487,7 @@ VISIT_TYPE(float, double); #define CHECK_ARG_(Char, expected, value) { \ testing::StrictMock> visitor; \ EXPECT_CALL(visitor, visit(expected)); \ - fmt::visit(visitor, make_arg(value)); \ + fmt::visit(visitor, make_arg>(value)); \ } #define CHECK_ARG(value) { \ @@ -575,7 +575,7 @@ TEST(UtilTest, CustomArg) { EXPECT_EQ("test", w.str()); return Visitor::Result(); })); - fmt::visit(visitor, make_arg(test)); + fmt::visit(visitor, make_arg(test)); } TEST(ArgVisitorTest, VisitInvalidArg) { From a4d6cb32d1cec6928db70ddeb7b02edb03aabc5e Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Thu, 29 Dec 2016 17:17:18 -0800 Subject: [PATCH 065/340] Clean up basic_format_arg --- fmt/format.h | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/fmt/format.h b/fmt/format.h index 3f9de274..f102c219 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -1347,21 +1347,17 @@ class basic_format_args; template class basic_format_arg { private: - typedef typename Context::char_type Char; - - internal::Value value_; + internal::Value value_; internal::Type type_; template friend basic_format_arg internal::make_arg(const T &value); - template + template friend typename std::result_of::type - visit(Visitor &&vis, basic_format_arg arg); - - template - friend class basic_format_args; + visit(Visitor &&vis, basic_format_arg arg); + friend class basic_format_args; friend class internal::ArgMap; public: From 42a319074cff953d20605c2ab13638d3231cb92e Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Thu, 29 Dec 2016 18:07:05 -0800 Subject: [PATCH 066/340] Parameterize Value on context --- fmt/format.h | 21 ++++++++++----------- test/util-test.cc | 9 +++++---- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/fmt/format.h b/fmt/format.h index f102c219..ef7a1ab5 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -1098,7 +1098,7 @@ struct CustomValue { }; // A formatting argument value. -template +template struct Value { union { int int_value; @@ -1111,8 +1111,8 @@ struct Value { StringValue string; StringValue sstring; StringValue ustring; - StringValue tstring; - CustomValue custom; + StringValue tstring; + CustomValue custom; }; }; @@ -1177,7 +1177,7 @@ constexpr Type type() { return gettype::type>(); } // Makes a format_arg object from any type. template -class MakeValue : public Value { +class MakeValue : public Value { public: typedef typename Context::char_type Char; @@ -1347,7 +1347,7 @@ class basic_format_args; template class basic_format_arg { private: - internal::Value value_; + internal::Value value_; internal::Type type_; template @@ -1514,8 +1514,7 @@ constexpr uint64_t make_type() { return 0; } enum { MAX_PACKED_ARGS = 16 }; template -inline typename std::enable_if< - IS_PACKED, Value>::type +inline typename std::enable_if>::type make_arg(const T& value) { return MakeValue(value); } @@ -1538,7 +1537,7 @@ class format_arg_store { typedef typename Context::char_type char_type; typedef typename std::conditional, basic_format_arg>::type value_type; + internal::Value, basic_format_arg>::type value_type; // If the arguments are not packed, add one more element to mark the end. typedef std::array Array; @@ -1582,7 +1581,7 @@ class basic_format_args { // This is done to reduce compiled code size as storing larger objects // may require more code (at least on x86-64) even if the same amount of // data is actually copied to stack. It saves ~10% on the bloat test. - const internal::Value *values_; + const internal::Value *values_; const format_arg *args_; }; @@ -1595,7 +1594,7 @@ class basic_format_args { friend class internal::ArgMap; - void set_data(const internal::Value *values) { values_ = values; } + void set_data(const internal::Value *values) { values_ = values; } void set_data(const format_arg *args) { args_ = args; } format_arg get(size_type index) const { @@ -1603,7 +1602,7 @@ class basic_format_args { bool use_values = type(internal::MAX_PACKED_ARGS - 1) == internal::NONE; if (index < internal::MAX_PACKED_ARGS) { typename internal::Type arg_type = type(index); - internal::Value &val = arg.value_; + internal::Value &val = arg.value_; if (arg_type != internal::NONE) val = use_values ? values_[index] : args_[index].value_; arg.type_ = arg_type; diff --git a/test/util-test.cc b/test/util-test.cc index 73d3ca8a..2c0dc448 100644 --- a/test/util-test.cc +++ b/test/util-test.cc @@ -412,19 +412,20 @@ TEST(UtilTest, FormatArgs) { EXPECT_FALSE(args[1]); } -struct CustomFormatter { +struct CustomContext { typedef char char_type; bool called; }; -void format_value(fmt::Writer &, const Test &, CustomFormatter &ctx) { +void format_value(fmt::Writer &, const Test &, CustomContext &ctx) { ctx.called = true; } TEST(UtilTest, MakeValueWithCustomFormatter) { ::Test t; - fmt::internal::Value arg = fmt::internal::MakeValue(t); - CustomFormatter ctx = {false}; + fmt::internal::Value arg = + fmt::internal::MakeValue(t); + CustomContext ctx = {false}; fmt::MemoryWriter w; arg.custom.format(w, &t, &ctx); EXPECT_TRUE(ctx.called); From acd1811c50324658c62834209b8b9db6a4f37a75 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Fri, 30 Dec 2016 08:05:26 -0800 Subject: [PATCH 067/340] Value -> value --- fmt/format.h | 16 ++++++++-------- test/util-test.cc | 4 ++-- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/fmt/format.h b/fmt/format.h index ef7a1ab5..14c5d7d1 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -1099,7 +1099,7 @@ struct CustomValue { // A formatting argument value. template -struct Value { +struct value { union { int int_value; unsigned uint_value; @@ -1177,7 +1177,7 @@ constexpr Type type() { return gettype::type>(); } // Makes a format_arg object from any type. template -class MakeValue : public Value { +class MakeValue : public value { public: typedef typename Context::char_type Char; @@ -1347,7 +1347,7 @@ class basic_format_args; template class basic_format_arg { private: - internal::Value value_; + internal::value value_; internal::Type type_; template @@ -1514,7 +1514,7 @@ constexpr uint64_t make_type() { return 0; } enum { MAX_PACKED_ARGS = 16 }; template -inline typename std::enable_if>::type +inline typename std::enable_if>::type make_arg(const T& value) { return MakeValue(value); } @@ -1537,7 +1537,7 @@ class format_arg_store { typedef typename Context::char_type char_type; typedef typename std::conditional, basic_format_arg>::type value_type; + internal::value, basic_format_arg>::type value_type; // If the arguments are not packed, add one more element to mark the end. typedef std::array Array; @@ -1581,7 +1581,7 @@ class basic_format_args { // This is done to reduce compiled code size as storing larger objects // may require more code (at least on x86-64) even if the same amount of // data is actually copied to stack. It saves ~10% on the bloat test. - const internal::Value *values_; + const internal::value *values_; const format_arg *args_; }; @@ -1594,7 +1594,7 @@ class basic_format_args { friend class internal::ArgMap; - void set_data(const internal::Value *values) { values_ = values; } + void set_data(const internal::value *values) { values_ = values; } void set_data(const format_arg *args) { args_ = args; } format_arg get(size_type index) const { @@ -1602,7 +1602,7 @@ class basic_format_args { bool use_values = type(internal::MAX_PACKED_ARGS - 1) == internal::NONE; if (index < internal::MAX_PACKED_ARGS) { typename internal::Type arg_type = type(index); - internal::Value &val = arg.value_; + internal::value &val = arg.value_; if (arg_type != internal::NONE) val = use_values ? values_[index] : args_[index].value_; arg.type_ = arg_type; diff --git a/test/util-test.cc b/test/util-test.cc index 2c0dc448..f12d0fbb 100644 --- a/test/util-test.cc +++ b/test/util-test.cc @@ -57,7 +57,7 @@ using fmt::format_arg; using fmt::Buffer; using fmt::StringRef; using fmt::internal::MemoryBuffer; -using fmt::internal::Value; +using fmt::internal::value; using testing::_; using testing::Return; @@ -423,7 +423,7 @@ void format_value(fmt::Writer &, const Test &, CustomContext &ctx) { TEST(UtilTest, MakeValueWithCustomFormatter) { ::Test t; - fmt::internal::Value arg = + fmt::internal::value arg = fmt::internal::MakeValue(t); CustomContext ctx = {false}; fmt::MemoryWriter w; From b2a0d8914a05ce97ca21eb35e1e8306393e7c281 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Fri, 30 Dec 2016 09:25:01 -0800 Subject: [PATCH 068/340] Merge value and MakeValue --- fmt/format.h | 85 ++++++++++++++++++++++------------------------- test/util-test.cc | 3 +- 2 files changed, 41 insertions(+), 47 deletions(-) diff --git a/fmt/format.h b/fmt/format.h index 14c5d7d1..f82713f3 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -1017,7 +1017,7 @@ template struct Null {}; // A helper class template to enable or disable overloads taking wide -// characters and strings in MakeValue. +// characters and strings in value's constructor. template struct WCharHelper { typedef Null Supported; @@ -1097,25 +1097,6 @@ struct CustomValue { FormatFunc format; }; -// A formatting argument value. -template -struct value { - union { - int int_value; - unsigned uint_value; - LongLong long_long_value; - ULongLong ulong_long_value; - double double_value; - long double long_double_value; - const void *pointer; - StringValue string; - StringValue sstring; - StringValue ustring; - StringValue tstring; - CustomValue custom; - }; -}; - template struct NamedArg; @@ -1175,10 +1156,25 @@ template <> constexpr Type gettype() { return POINTER; } template constexpr Type type() { return gettype::type>(); } -// Makes a format_arg object from any type. +// A formatting argument value. template -class MakeValue : public value { +class value { public: + union { + int int_value; + unsigned uint_value; + LongLong long_long_value; + ULongLong ulong_long_value; + double double_value; + long double long_double_value; + const void *pointer; + StringValue string; + StringValue sstring; + StringValue ustring; + StringValue tstring; + CustomValue custom; + }; + typedef typename Context::char_type Char; private: @@ -1188,21 +1184,21 @@ class MakeValue : public value { // of "[const] volatile char *" which is printed as bool by iostreams. // Do not implement! template - MakeValue(const T *value); + value(const T *value); template - MakeValue(T *value); + value(T *value); // The following methods are private to disallow formatting of wide // characters and strings into narrow strings as in // fmt::format("{}", L"test"); // To fix this, use a wide format string: fmt::format(L"{}", L"test"). #if !FMT_MSC_VER || defined(_NATIVE_WCHAR_T_DEFINED) - MakeValue(typename WCharHelper::Unsupported); + value(typename WCharHelper::Unsupported); #endif - MakeValue(typename WCharHelper::Unsupported); - MakeValue(typename WCharHelper::Unsupported); - MakeValue(typename WCharHelper::Unsupported); - MakeValue(typename WCharHelper::Unsupported); + value(typename WCharHelper::Unsupported); + value(typename WCharHelper::Unsupported); + value(typename WCharHelper::Unsupported); + value(typename WCharHelper::Unsupported); void set_string(StringRef str) { this->string.value = str.data(); @@ -1223,10 +1219,10 @@ class MakeValue : public value { } public: - MakeValue() {} + value() {} #define FMT_MAKE_VALUE_(Type, field, TYPE, rhs) \ - MakeValue(Type value) { \ + value(Type value) { \ static_assert(internal::type() == internal::TYPE, "invalid type"); \ this->field = rhs; \ } @@ -1240,7 +1236,7 @@ class MakeValue : public value { FMT_MAKE_VALUE(int, int_value, INT) FMT_MAKE_VALUE(unsigned, uint_value, UINT) - MakeValue(long value) { + value(long value) { // To minimize the number of types we need to deal with, long is // translated either to int or to long long depending on its size. if (const_check(sizeof(long) == sizeof(int))) @@ -1249,7 +1245,7 @@ class MakeValue : public value { this->long_long_value = value; } - MakeValue(unsigned long value) { + value(unsigned long value) { if (const_check(sizeof(unsigned long) == sizeof(unsigned))) this->uint_value = static_cast(value); else @@ -1267,14 +1263,14 @@ class MakeValue : public value { #if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED) typedef typename WCharHelper::Supported WChar; - MakeValue(WChar value) { + value(WChar value) { static_assert(internal::type() == internal::CHAR, "invalid type"); this->int_value = value; } #endif #define FMT_MAKE_STR_VALUE(Type, TYPE) \ - MakeValue(Type value) { \ + value(Type value) { \ static_assert(internal::type() == internal::TYPE, "invalid type"); \ set_string(value); \ } @@ -1290,8 +1286,8 @@ class MakeValue : public value { FMT_MAKE_VALUE_(CStringRef, string.value, CSTRING, value.c_str()) #define FMT_MAKE_WSTR_VALUE(Type, TYPE) \ - MakeValue(typename WCharHelper::Supported value) { \ - static_assert(internal::type() == internal::TYPE, "invalid type"); \ + value(typename WCharHelper::Supported value) { \ + static_assert(internal::type() == internal::TYPE, "invalid type"); \ set_string(value); \ } @@ -1304,17 +1300,16 @@ class MakeValue : public value { FMT_MAKE_VALUE(const void *, pointer, POINTER) template - MakeValue(const T &value, - typename EnableIf::value>::value, int>::type = 0) { + value(const T &value, + typename EnableIf::value>::value, int>::type = 0) { static_assert(internal::type() == internal::CUSTOM, "invalid type"); this->custom.value = &value; this->custom.format = &format_custom_arg; } template - MakeValue(const T &value, - typename EnableIf::value, int>::type = 0) { + value(const T &value, + typename EnableIf::value, int>::type = 0) { static_assert(internal::type() == internal::INT, "invalid type"); this->int_value = value; } @@ -1322,7 +1317,7 @@ class MakeValue : public value { // Additional template param `Char_` is needed here because make_type always // uses char. template - MakeValue(const NamedArg &value) { + value(const NamedArg &value) { static_assert( internal::type &>() == internal::NAMED_ARG, "invalid type"); @@ -1437,7 +1432,7 @@ template basic_format_arg make_arg(const T &value) { basic_format_arg arg; arg.type_ = internal::type(); - arg.value_ = internal::MakeValue(value); + arg.value_ = value; return arg; } @@ -1516,7 +1511,7 @@ enum { MAX_PACKED_ARGS = 16 }; template inline typename std::enable_if>::type make_arg(const T& value) { - return MakeValue(value); + return value; } template diff --git a/test/util-test.cc b/test/util-test.cc index f12d0fbb..978a8cc8 100644 --- a/test/util-test.cc +++ b/test/util-test.cc @@ -423,8 +423,7 @@ void format_value(fmt::Writer &, const Test &, CustomContext &ctx) { TEST(UtilTest, MakeValueWithCustomFormatter) { ::Test t; - fmt::internal::value arg = - fmt::internal::MakeValue(t); + fmt::internal::value arg(t); CustomContext ctx = {false}; fmt::MemoryWriter w; arg.custom.format(w, &t, &ctx); From f69786a71566f542036e82eff2af4faa17e1ff7f Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Fri, 30 Dec 2016 09:29:41 -0800 Subject: [PATCH 069/340] Remove Not --- fmt/format.h | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/fmt/format.h b/fmt/format.h index f82713f3..a67aa340 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -1003,13 +1003,6 @@ struct Conditional { typedef T type; }; template struct Conditional { typedef F type; }; -// For bcc32 which doesn't understand ! in template arguments. -template -struct Not { enum { value = 0 }; }; - -template <> -struct Not { enum { value = 1 }; }; - template struct False { enum { value = 0 }; }; @@ -1301,7 +1294,7 @@ class value { template value(const T &value, - typename EnableIf::value>::value, int>::type = 0) { + typename EnableIf::value, int>::type = 0) { static_assert(internal::type() == internal::CUSTOM, "invalid type"); this->custom.value = &value; this->custom.format = &format_custom_arg; From 939aff29361e63ca4858e6a6319471f24d979aa2 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Fri, 30 Dec 2016 10:19:38 -0800 Subject: [PATCH 070/340] Remove unnecessary template arg from basic_format_args --- fmt/format.h | 29 ++++++++++++++--------------- fmt/printf.h | 11 +++++------ test/custom-formatter-test.cc | 2 +- 3 files changed, 20 insertions(+), 22 deletions(-) diff --git a/fmt/format.h b/fmt/format.h index a67aa340..6f9007dd 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -1327,7 +1327,7 @@ basic_format_arg make_arg(const T &value); struct monostate {}; -template +template class basic_format_args; // A formatting argument. It is a trivially copyable/constructible type to @@ -1345,7 +1345,7 @@ class basic_format_arg { friend typename std::result_of::type visit(Visitor &&vis, basic_format_arg arg); - friend class basic_format_args; + friend class basic_format_args; friend class internal::ArgMap; public: @@ -1553,7 +1553,7 @@ inline format_arg_store } /** Formatting arguments. */ -template +template class basic_format_args { public: typedef unsigned size_type; @@ -1626,8 +1626,8 @@ class basic_format_args { } }; -typedef basic_format_args, char> format_args; -typedef basic_format_args, wchar_t> wformat_args; +typedef basic_format_args format_args; +typedef basic_format_args wformat_args; enum Alignment { ALIGN_DEFAULT, ALIGN_LEFT, ALIGN_RIGHT, ALIGN_CENTER, ALIGN_NUMERIC @@ -1863,7 +1863,7 @@ class ArgMap { MapType map_; public: - void init(const basic_format_args &args); + void init(const basic_format_args &args); const basic_format_arg *find(const fmt::BasicStringRef &name) const { @@ -1878,7 +1878,7 @@ class ArgMap { }; template -void ArgMap::init(const basic_format_args &args) { +void ArgMap::init(const basic_format_args &args) { if (!map_.empty()) return; typedef internal::NamedArg NamedArg; @@ -2050,18 +2050,17 @@ template class format_context_base { private: const Char *ptr_; - basic_format_args args_; + basic_format_args args_; int next_arg_index_; protected: typedef basic_format_arg format_arg; - format_context_base(const Char *format_str, - basic_format_args args) + format_context_base(const Char *format_str, basic_format_args args) : ptr_(format_str), args_(args), next_arg_index_(0) {} ~format_context_base() {} - basic_format_args args() const { return args_; } + basic_format_args args() const { return args_; } // Returns the argument with specified index. format_arg do_get_arg(unsigned arg_index, const char *&error) { @@ -2157,7 +2156,7 @@ class basic_format_context : \endrst */ basic_format_context(const Char *format_str, - basic_format_args args) + basic_format_args args) : Base(format_str, args) {} // Parses argument id and returns corresponding argument. @@ -2394,7 +2393,7 @@ class BasicWriter { } void vwrite(BasicCStringRef format, - basic_format_args, Char> args); + basic_format_args> args); /** \rst Writes formatted data. @@ -3578,7 +3577,7 @@ void do_format_arg(BasicWriter &writer, basic_format_arg arg, /** Formats arguments and writes the output to the writer. */ template void vformat(BasicWriter &writer, BasicCStringRef format_str, - basic_format_args args) { + basic_format_args args) { basic_format_context ctx(format_str.c_str(), args); const Char *&s = ctx.ptr(); const Char *start = s; @@ -3604,7 +3603,7 @@ void vformat(BasicWriter &writer, BasicCStringRef format_str, template inline void BasicWriter::vwrite( BasicCStringRef format, - basic_format_args, Char> args) { + basic_format_args> args) { vformat>(*this, format, args); } } // namespace fmt diff --git a/fmt/printf.h b/fmt/printf.h index 13b82afd..beea7c39 100644 --- a/fmt/printf.h +++ b/fmt/printf.h @@ -282,7 +282,7 @@ class PrintfArgFormatter : public internal::ArgFormatterBase { /** Formats an argument of a custom (user-defined) type. */ void operator()(internal::CustomValue c) { const Char format_str[] = {'}', '\0'}; - auto args = basic_format_args, Char>(); + auto args = basic_format_args>(); basic_format_context ctx(format_str, args); c.format(this->writer(), c.value, &ctx); } @@ -322,7 +322,7 @@ class printf_context : \endrst */ explicit printf_context(BasicCStringRef format_str, - basic_format_args args) + basic_format_args args) : Base(format_str.c_str(), args) {} /** Formats stored arguments and writes the output to the writer. */ @@ -510,11 +510,11 @@ void format_value(BasicWriter &w, const T &value, template void printf(BasicWriter &w, BasicCStringRef format, - basic_format_args, Char> args) { + basic_format_args> args) { printf_context(format, args).format(w); } -typedef basic_format_args, char> printf_args; +typedef basic_format_args> printf_args; inline std::string vsprintf(CStringRef format, printf_args args) { MemoryWriter w; @@ -537,8 +537,7 @@ inline std::string sprintf(CStringRef format_str, const Args & ... args) { } inline std::wstring vsprintf( - WCStringRef format, - basic_format_args, wchar_t> args) { + WCStringRef format, basic_format_args> args) { WMemoryWriter w; printf(w, format, args); return w.str(); diff --git a/test/custom-formatter-test.cc b/test/custom-formatter-test.cc index 51bed768..7601aeb5 100644 --- a/test/custom-formatter-test.cc +++ b/test/custom-formatter-test.cc @@ -63,7 +63,7 @@ typedef fmt::printf_context std::string custom_vsprintf( const char* format_str, - fmt::basic_format_args args) { + fmt::basic_format_args args) { fmt::MemoryWriter writer; CustomPrintfFormatter formatter(format_str, args); formatter.format(writer); From 8428621ddc407c0765725af5ad7669dec85fa111 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Fri, 30 Dec 2016 12:11:27 -0800 Subject: [PATCH 071/340] BasicWriter -> basic_writer --- fmt/format.cc | 16 ++--- fmt/format.h | 128 +++++++++++++++++----------------- fmt/ostream.cc | 2 +- fmt/ostream.h | 4 +- fmt/printf.h | 14 ++-- fmt/string.h | 4 +- fmt/time.h | 2 +- test/custom-formatter-test.cc | 4 +- test/format-test.cc | 18 ++--- test/ostream-test.cc | 6 +- test/util-test.cc | 6 +- 11 files changed, 101 insertions(+), 103 deletions(-) diff --git a/fmt/format.cc b/fmt/format.cc index 92479615..cd17ebf1 100644 --- a/fmt/format.cc +++ b/fmt/format.cc @@ -106,7 +106,7 @@ inline int fmt_snprintf(char *buffer, size_t size, const char *format, ...) { const char RESET_COLOR[] = "\x1b[0m"; -typedef void (*FormatFunc)(Writer &, int, StringRef); +typedef void (*FormatFunc)(writer &, int, StringRef); // Portable thread-safe version of strerror. // Sets buffer to point to a string describing the error code. @@ -176,7 +176,7 @@ int safe_strerror( return StrError(error_code, buffer, buffer_size).run(); } -void format_error_code(Writer &out, int error_code, +void format_error_code(writer &out, int error_code, StringRef message) FMT_NOEXCEPT { // Report error code making sure that the output fits into // INLINE_BUFFER_SIZE to avoid dynamic memory allocation and potential @@ -215,7 +215,7 @@ namespace internal { // This method is used to preserve binary compatibility with fmt 3.0. // It can be removed in 4.0. FMT_FUNC void format_system_error( - Writer &out, int error_code, StringRef message) FMT_NOEXCEPT { + writer &out, int error_code, StringRef message) FMT_NOEXCEPT { fmt::format_system_error(out, error_code, message); } } // namespace internal @@ -354,7 +354,7 @@ FMT_FUNC void WindowsError::init( } FMT_FUNC void internal::format_windows_error( - Writer &out, int error_code, StringRef message) FMT_NOEXCEPT { + writer &out, int error_code, StringRef message) FMT_NOEXCEPT { FMT_TRY { MemoryBuffer buffer; buffer.resize(INLINE_BUFFER_SIZE); @@ -383,7 +383,7 @@ FMT_FUNC void internal::format_windows_error( #endif // FMT_USE_WINDOWS_H FMT_FUNC void format_system_error( - Writer &out, int error_code, StringRef message) FMT_NOEXCEPT { + writer &out, int error_code, StringRef message) FMT_NOEXCEPT { FMT_TRY { internal::MemoryBuffer buffer; buffer.resize(internal::INLINE_BUFFER_SIZE); @@ -440,7 +440,7 @@ FMT_FUNC void vprint_colored(Color c, CStringRef format, format_args args) { } template -void printf(BasicWriter &w, BasicCStringRef format, +void printf(basic_writer &w, BasicCStringRef format, format_args args); FMT_FUNC int vfprintf(std::FILE *f, CStringRef format, printf_args args) { @@ -460,7 +460,7 @@ template void internal::FixedBuffer::grow(std::size_t); template void internal::ArgMap::init(const format_args &args); -template void printf_context::format(Writer &writer); +template void printf_context::format(writer &writer); template int internal::CharTraits::format_float( char *buffer, std::size_t size, const char *format, @@ -478,7 +478,7 @@ template void internal::FixedBuffer::grow(std::size_t); template void internal::ArgMap::init(const wformat_args &args); -template void printf_context::format(WWriter &writer); +template void printf_context::format(wwriter &writer); template int internal::CharTraits::format_float( wchar_t *buffer, std::size_t size, const wchar_t *format, diff --git a/fmt/format.h b/fmt/format.h index 6f9007dd..1549f4a5 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -365,10 +365,10 @@ using std::move; #endif template -class BasicWriter; +class basic_writer; -typedef BasicWriter Writer; -typedef BasicWriter WWriter; +typedef basic_writer writer; +typedef basic_writer wwriter; template class basic_format_arg; @@ -987,7 +987,7 @@ class UTF16ToUTF8 { FMT_API int convert(WStringRef s); }; -FMT_API void format_windows_error(fmt::Writer &out, int error_code, +FMT_API void format_windows_error(fmt::writer &out, int error_code, fmt::StringRef message) FMT_NOEXCEPT; #endif @@ -1076,7 +1076,7 @@ enum Type { }; template -struct StringValue { +struct string_value { const Char *value; std::size_t size; }; @@ -1084,7 +1084,7 @@ struct StringValue { template struct CustomValue { typedef void (*FormatFunc)( - BasicWriter &writer, const void *arg, void *ctx); + basic_writer &writer, const void *arg, void *ctx); const void *value; FormatFunc format; @@ -1161,10 +1161,10 @@ class value { double double_value; long double long_double_value; const void *pointer; - StringValue string; - StringValue sstring; - StringValue ustring; - StringValue tstring; + string_value string; + string_value sstring; + string_value ustring; + string_value tstring; CustomValue custom; }; @@ -1206,7 +1206,7 @@ class value { // Formats an argument of a custom type, such as a user-defined class. template static void format_custom_arg( - BasicWriter &writer, const void *arg, void *context) { + basic_writer &writer, const void *arg, void *context) { format_value(writer, *static_cast(arg), *static_cast(context)); } @@ -1466,7 +1466,7 @@ inline fmt::StringRef thousands_sep(...) { return ""; } #endif template -void format_value(BasicWriter &, const T &, Formatter &, const Char *) { +void format_value(basic_writer &, const T &, Formatter &, const Char *) { FMT_STATIC_ASSERT(False::value, "Cannot format argument. To enable the use of ostream " "operator<< include fmt/ostream.h. Otherwise provide " @@ -1925,7 +1925,7 @@ void ArgMap::init(const basic_format_args &args) { template class ArgFormatterBase { private: - BasicWriter &writer_; + basic_writer &writer_; FormatSpec &spec_; FMT_DISALLOW_COPY_AND_ASSIGN(ArgFormatterBase); @@ -1953,7 +1953,7 @@ class ArgFormatterBase { } protected: - BasicWriter &writer() { return writer_; } + basic_writer &writer() { return writer_; } FormatSpec &spec() { return spec_; } void write(bool value) { @@ -1968,7 +1968,7 @@ class ArgFormatterBase { public: typedef Char char_type; - ArgFormatterBase(BasicWriter &w, FormatSpec &s) + ArgFormatterBase(basic_writer &w, FormatSpec &s) : writer_(w), spec_(s) {} void operator()(monostate) { @@ -1997,7 +1997,7 @@ class ArgFormatterBase { } if (spec_.align_ == ALIGN_NUMERIC || spec_.flags_ != 0) FMT_THROW(format_error("invalid format specifier for char")); - typedef typename BasicWriter::CharPtr CharPtr; + typedef typename basic_writer::CharPtr CharPtr; Char fill = internal::CharTraits::cast(spec_.fill()); CharPtr out = CharPtr(); const unsigned CHAR_WIDTH = 1; @@ -2041,7 +2041,7 @@ class ArgFormatterBase { }; template -inline void write(BasicWriter &w, const Char *start, const Char *end) { +inline void write(basic_writer &w, const Char *start, const Char *end) { if (start != end) w << BasicStringRef(start, internal::to_unsigned(end - start)); } @@ -2115,7 +2115,7 @@ class ArgFormatter : public internal::ArgFormatterBase { format specifier information for standard argument types. \endrst */ - ArgFormatter(BasicWriter &writer, basic_format_context &ctx, + ArgFormatter(basic_writer &writer, basic_format_context &ctx, FormatSpec &spec) : internal::ArgFormatterBase(writer, spec), ctx_(ctx) {} @@ -2223,7 +2223,7 @@ class SystemError : public internal::RuntimeError { may look like "Unknown error -1" and is platform-dependent. \endrst */ -FMT_API void format_system_error(fmt::Writer &out, int error_code, +FMT_API void format_system_error(fmt::writer &out, int error_code, fmt::StringRef message) FMT_NOEXCEPT; /** @@ -2234,23 +2234,23 @@ FMT_API void format_system_error(fmt::Writer &out, int error_code, You can use one of the following typedefs for common character types: - +---------+----------------------+ - | Type | Definition | - +=========+======================+ - | Writer | BasicWriter | - +---------+----------------------+ - | WWriter | BasicWriter | - +---------+----------------------+ + +---------+-----------------------+ + | Type | Definition | + +=========+=======================+ + | writer | basic_writer | + +---------+-----------------------+ + | wwriter | basic_writer | + +---------+-----------------------+ \endrst */ template -class BasicWriter { +class basic_writer { private: // Output buffer. Buffer &buffer_; - FMT_DISALLOW_COPY_AND_ASSIGN(BasicWriter); + FMT_DISALLOW_COPY_AND_ASSIGN(basic_writer); typedef typename internal::CharTraits::CharPtr CharPtr; @@ -2349,17 +2349,17 @@ class BasicWriter { protected: /** - Constructs a ``BasicWriter`` object. + Constructs a ``basic_writer`` object. */ - explicit BasicWriter(Buffer &b) : buffer_(b) {} + explicit basic_writer(Buffer &b) : buffer_(b) {} public: /** \rst - Destroys a ``BasicWriter`` object. + Destroys a ``basic_writer`` object. \endrst */ - virtual ~BasicWriter() {} + virtual ~basic_writer() {} /** Returns the total number of characters written. @@ -2424,21 +2424,21 @@ class BasicWriter { vwrite(format, make_xformat_args>(args...)); } - BasicWriter &operator<<(int value) { + basic_writer &operator<<(int value) { write_decimal(value); return *this; } - BasicWriter &operator<<(unsigned value) { + basic_writer &operator<<(unsigned value) { return *this << IntFormatSpec(value); } - BasicWriter &operator<<(long value) { + basic_writer &operator<<(long value) { write_decimal(value); return *this; } - BasicWriter &operator<<(unsigned long value) { + basic_writer &operator<<(unsigned long value) { return *this << IntFormatSpec(value); } - BasicWriter &operator<<(LongLong value) { + basic_writer &operator<<(LongLong value) { write_decimal(value); return *this; } @@ -2448,11 +2448,11 @@ class BasicWriter { Formats *value* and writes it to the stream. \endrst */ - BasicWriter &operator<<(ULongLong value) { + basic_writer &operator<<(ULongLong value) { return *this << IntFormatSpec(value); } - BasicWriter &operator<<(double value) { + basic_writer &operator<<(double value) { write_double(value, FormatSpec()); return *this; } @@ -2463,7 +2463,7 @@ class BasicWriter { (``'g'``) and writes it to the stream. \endrst */ - BasicWriter &operator<<(long double value) { + basic_writer &operator<<(long double value) { write_double(value, FormatSpec()); return *this; } @@ -2471,12 +2471,12 @@ class BasicWriter { /** Writes a character to the stream. */ - BasicWriter &operator<<(char value) { + basic_writer &operator<<(char value) { buffer_.push_back(value); return *this; } - BasicWriter &operator<<( + basic_writer &operator<<( typename internal::WCharHelper::Supported value) { buffer_.push_back(value); return *this; @@ -2487,13 +2487,13 @@ class BasicWriter { Writes *value* to the stream. \endrst */ - BasicWriter &operator<<(fmt::BasicStringRef value) { + basic_writer &operator<<(fmt::BasicStringRef value) { const Char *str = value.data(); buffer_.append(str, str + value.size()); return *this; } - BasicWriter &operator<<( + basic_writer &operator<<( typename internal::WCharHelper::Supported value) { const char *str = value.data(); buffer_.append(str, str + value.size()); @@ -2501,14 +2501,14 @@ class BasicWriter { } template - BasicWriter &operator<<(IntFormatSpec spec) { + basic_writer &operator<<(IntFormatSpec spec) { internal::CharTraits::convert(FillChar()); write_int(spec.value(), spec); return *this; } template - BasicWriter &operator<<(const StrFormatSpec &spec) { + basic_writer &operator<<(const StrFormatSpec &spec) { const StrChar *s = spec.str(); write_str(s, std::char_traits::length(s), spec); return *this; @@ -2521,7 +2521,7 @@ class BasicWriter { template template -typename BasicWriter::CharPtr BasicWriter::write_str( +typename basic_writer::CharPtr basic_writer::write_str( const StrChar *s, std::size_t size, const AlignSpec &spec) { CharPtr out = CharPtr(); if (spec.width() > size) { @@ -2544,7 +2544,7 @@ typename BasicWriter::CharPtr BasicWriter::write_str( template template -void BasicWriter::write_str( +void basic_writer::write_str( BasicStringRef s, const FormatSpec &spec) { // Check if StrChar is convertible to Char. internal::CharTraits::convert(StrChar()); @@ -2564,8 +2564,7 @@ void BasicWriter::write_str( } template -typename BasicWriter::CharPtr - BasicWriter::fill_padding( +typename basic_writer::CharPtr basic_writer::fill_padding( CharPtr buffer, unsigned total_size, std::size_t content_size, wchar_t fill) { std::size_t padding = total_size - content_size; @@ -2581,8 +2580,7 @@ typename BasicWriter::CharPtr template template -typename BasicWriter::CharPtr - BasicWriter::prepare_int_buffer( +typename basic_writer::CharPtr basic_writer::prepare_int_buffer( unsigned num_digits, const Spec &spec, const char *prefix, unsigned prefix_size) { unsigned width = spec.width(); @@ -2645,7 +2643,7 @@ typename BasicWriter::CharPtr template template -void BasicWriter::write_int(T value, Spec spec) { +void basic_writer::write_int(T value, Spec spec) { unsigned prefix_size = 0; typedef typename internal::IntTraits::MainType UnsignedType; UnsignedType abs_value = static_cast(value); @@ -2735,7 +2733,7 @@ void BasicWriter::write_int(T value, Spec spec) { template template -void BasicWriter::write_double(T value, const FormatSpec &spec) { +void basic_writer::write_double(T value, const FormatSpec &spec) { // Check type. char type = spec.type(); bool upper = false; @@ -2923,13 +2921,13 @@ void BasicWriter::write_double(T value, const FormatSpec &spec) { \endrst */ template > -class BasicMemoryWriter : public BasicWriter { +class BasicMemoryWriter : public basic_writer { private: internal::MemoryBuffer buffer_; public: explicit BasicMemoryWriter(const Allocator& alloc = Allocator()) - : BasicWriter(buffer_), buffer_(alloc) {} + : basic_writer(buffer_), buffer_(alloc) {} #if FMT_USE_RVALUE_REFERENCES /** @@ -2939,7 +2937,7 @@ class BasicMemoryWriter : public BasicWriter { \endrst */ BasicMemoryWriter(BasicMemoryWriter &&other) - : BasicWriter(buffer_), buffer_(std::move(other.buffer_)) { + : basic_writer(buffer_), buffer_(std::move(other.buffer_)) { } /** @@ -2978,7 +2976,7 @@ typedef BasicMemoryWriter WMemoryWriter; \endrst */ template -class BasicArrayWriter : public BasicWriter { +class BasicArrayWriter : public basic_writer { private: internal::FixedBuffer buffer_; @@ -2990,7 +2988,7 @@ class BasicArrayWriter : public BasicWriter { \endrst */ BasicArrayWriter(Char *array, std::size_t size) - : BasicWriter(buffer_), buffer_(array, size) {} + : basic_writer(buffer_), buffer_(array, size) {} /** \rst @@ -3000,7 +2998,7 @@ class BasicArrayWriter : public BasicWriter { */ template explicit BasicArrayWriter(Char (&array)[SIZE]) - : BasicWriter(buffer_), buffer_(array, SIZE) {} + : basic_writer(buffer_), buffer_(array, SIZE) {} }; typedef BasicArrayWriter ArrayWriter; @@ -3349,11 +3347,11 @@ void check_sign(const Char *&s, const basic_format_arg &arg) { template class CustomFormatter { private: - BasicWriter &writer_; + basic_writer &writer_; Context &ctx_; public: - CustomFormatter(BasicWriter &writer, Context &ctx) + CustomFormatter(basic_writer &writer, Context &ctx) : writer_(writer), ctx_(ctx) {} bool operator()(internal::CustomValue custom) { @@ -3450,7 +3448,7 @@ inline typename basic_format_context::format_arg // Formats a single argument. template -void do_format_arg(BasicWriter &writer, basic_format_arg arg, +void do_format_arg(basic_writer &writer, basic_format_arg arg, Context &ctx) { const Char *&s = ctx.ptr(); FormatSpec spec; @@ -3576,7 +3574,7 @@ void do_format_arg(BasicWriter &writer, basic_format_arg arg, /** Formats arguments and writes the output to the writer. */ template -void vformat(BasicWriter &writer, BasicCStringRef format_str, +void vformat(basic_writer &writer, BasicCStringRef format_str, basic_format_args args) { basic_format_context ctx(format_str.c_str(), args); const Char *&s = ctx.ptr(); @@ -3601,7 +3599,7 @@ void vformat(BasicWriter &writer, BasicCStringRef format_str, } template -inline void BasicWriter::vwrite( +inline void basic_writer::vwrite( BasicCStringRef format, basic_format_args> args) { vformat>(*this, format, args); diff --git a/fmt/ostream.cc b/fmt/ostream.cc index 8b83b2d1..ebfb50d1 100644 --- a/fmt/ostream.cc +++ b/fmt/ostream.cc @@ -12,7 +12,7 @@ namespace fmt { namespace internal { -FMT_FUNC void write(std::ostream &os, Writer &w) { +FMT_FUNC void write(std::ostream &os, writer &w) { const char *data = w.data(); typedef internal::MakeUnsigned::Type UnsignedStreamSize; UnsignedStreamSize size = w.size(); diff --git a/fmt/ostream.h b/fmt/ostream.h index 74ccadf4..bae83100 100644 --- a/fmt/ostream.h +++ b/fmt/ostream.h @@ -68,7 +68,7 @@ struct ConvertToIntImpl { }; // Write the content of w to os. -void write(std::ostream &os, Writer &w); +void write(std::ostream &os, writer &w); template BasicStringRef format_value( @@ -83,7 +83,7 @@ BasicStringRef format_value( // Formats a value. template -void format_value(BasicWriter &w, const T &value, +void format_value(basic_writer &w, const T &value, basic_format_context &ctx) { internal::MemoryBuffer buffer; auto str = internal::format_value(buffer, value); diff --git a/fmt/printf.h b/fmt/printf.h index beea7c39..8a4a486a 100644 --- a/fmt/printf.h +++ b/fmt/printf.h @@ -224,7 +224,7 @@ class PrintfArgFormatter : public internal::ArgFormatterBase { specifier information for standard argument types. \endrst */ - PrintfArgFormatter(BasicWriter &writer, FormatSpec &spec) + PrintfArgFormatter(basic_writer &writer, FormatSpec &spec) : internal::ArgFormatterBase(writer, spec) {} using Base::operator(); @@ -241,10 +241,10 @@ class PrintfArgFormatter : public internal::ArgFormatterBase { /** Formats a character. */ void operator()(Char value) { const FormatSpec &fmt_spec = this->spec(); - BasicWriter &w = this->writer(); + basic_writer &w = this->writer(); if (fmt_spec.type_ && fmt_spec.type_ != 'c') w.write_int(value, fmt_spec); - typedef typename BasicWriter::CharPtr CharPtr; + typedef typename basic_writer::CharPtr CharPtr; CharPtr out = CharPtr(); if (fmt_spec.width_ > 1) { Char fill = ' '; @@ -326,7 +326,7 @@ class printf_context : : Base(format_str.c_str(), args) {} /** Formats stored arguments and writes the output to the writer. */ - FMT_API void format(BasicWriter &writer); + FMT_API void format(basic_writer &writer); }; template @@ -402,7 +402,7 @@ unsigned printf_context::parse_header( } template -void printf_context::format(BasicWriter &writer) { +void printf_context::format(basic_writer &writer) { const Char *start = this->ptr(); const Char *s = start; while (*s) { @@ -502,14 +502,14 @@ void printf_context::format(BasicWriter &writer) { // Formats a value. template -void format_value(BasicWriter &w, const T &value, +void format_value(basic_writer &w, const T &value, printf_context& ctx) { internal::MemoryBuffer buffer; w << internal::format_value(buffer, value); } template -void printf(BasicWriter &w, BasicCStringRef format, +void printf(basic_writer &w, BasicCStringRef format, basic_format_args> args) { printf_context(format, args).format(w); } diff --git a/fmt/string.h b/fmt/string.h index e7beb039..c1731c75 100644 --- a/fmt/string.h +++ b/fmt/string.h @@ -72,7 +72,7 @@ class StringBuffer : public Buffer { \endrst */ template -class BasicStringWriter : public BasicWriter { +class BasicStringWriter : public basic_writer { private: internal::StringBuffer buffer_; @@ -82,7 +82,7 @@ class BasicStringWriter : public BasicWriter { Constructs a :class:`fmt::BasicStringWriter` object. \endrst */ - BasicStringWriter() : BasicWriter(buffer_) {} + BasicStringWriter() : basic_writer(buffer_) {} /** \rst diff --git a/fmt/time.h b/fmt/time.h index ad7ab9cf..6b970bcb 100644 --- a/fmt/time.h +++ b/fmt/time.h @@ -15,7 +15,7 @@ namespace fmt { -void format_value(Writer &w, const std::tm &tm, format_context &ctx) { +void format_value(writer &w, const std::tm &tm, format_context &ctx) { const char *&s = ctx.ptr(); if (*s == ':') ++s; diff --git a/test/custom-formatter-test.cc b/test/custom-formatter-test.cc index 7601aeb5..9f90b258 100644 --- a/test/custom-formatter-test.cc +++ b/test/custom-formatter-test.cc @@ -16,7 +16,7 @@ using fmt::PrintfArgFormatter; // rounded to 0. class CustomArgFormatter : public fmt::ArgFormatter { public: - CustomArgFormatter(fmt::Writer &w, fmt::basic_format_context &ctx, + CustomArgFormatter(fmt::writer &w, fmt::basic_format_context &ctx, fmt::FormatSpec &s) : fmt::ArgFormatter(w, ctx, s) {} @@ -33,7 +33,7 @@ class CustomArgFormatter : public fmt::ArgFormatter { // rounded to 0. class CustomPrintfArgFormatter : public PrintfArgFormatter { public: - CustomPrintfArgFormatter(fmt::BasicWriter &w, fmt::FormatSpec &spec) + CustomPrintfArgFormatter(fmt::basic_writer &w, fmt::FormatSpec &spec) : PrintfArgFormatter(w, spec) {} using PrintfArgFormatter::operator(); diff --git a/test/format-test.cc b/test/format-test.cc index b8693d5e..6419771b 100644 --- a/test/format-test.cc +++ b/test/format-test.cc @@ -70,7 +70,7 @@ lconv *localeconv() { using std::size_t; -using fmt::BasicWriter; +using fmt::basic_writer; using fmt::format; using fmt::format_error; using fmt::StringRef; @@ -165,11 +165,11 @@ TEST(CStringRefTest, Ctor) { #if FMT_USE_TYPE_TRAITS TEST(WriterTest, NotCopyConstructible) { - EXPECT_FALSE(std::is_copy_constructible >::value); + EXPECT_FALSE(std::is_copy_constructible >::value); } TEST(WriterTest, NotCopyAssignable) { - EXPECT_FALSE(std::is_copy_assignable >::value); + EXPECT_FALSE(std::is_copy_assignable >::value); } #endif @@ -399,7 +399,7 @@ TEST(WriterTest, hexu) { } template -BasicWriter &operator<<(BasicWriter &f, const Date &d) { +basic_writer &operator<<(basic_writer &f, const Date &d) { return f << d.year() << '-' << d.month() << '-' << d.day(); } @@ -410,8 +410,8 @@ public: ISO8601DateFormatter(const Date &d) : date_(&d) {} template - friend BasicWriter &operator<<( - BasicWriter &w, const ISO8601DateFormatter &d) { + friend basic_writer &operator<<( + basic_writer &w, const ISO8601DateFormatter &d) { return w << pad(d.date_->year(), 4, '0') << '-' << pad(d.date_->month(), 2, '0') << '-' << pad(d.date_->day(), 2, '0'); } @@ -1355,7 +1355,7 @@ TEST(FormatterTest, FormatCStringRef) { EXPECT_EQ("test", format("{0}", CStringRef("test"))); } -void format_value(fmt::Writer &w, const Date &d, fmt::format_context &) { +void format_value(fmt::writer &w, const Date &d, fmt::format_context &) { w << d.year() << '-' << d.month() << '-' << d.day(); } @@ -1368,7 +1368,7 @@ TEST(FormatterTest, FormatCustom) { class Answer {}; template -void format_value(BasicWriter &w, Answer, fmt::format_context &) { +void format_value(basic_writer &w, Answer, fmt::format_context &) { w << "42"; } @@ -1627,7 +1627,7 @@ class MockArgFormatter : public fmt::internal::ArgFormatterBase { public: typedef fmt::internal::ArgFormatterBase Base; - MockArgFormatter(fmt::Writer &w, fmt::format_context &ctx, + MockArgFormatter(fmt::writer &w, fmt::format_context &ctx, fmt::FormatSpec &s) : fmt::internal::ArgFormatterBase(w, s) { EXPECT_CALL(*this, call(42)); diff --git a/test/ostream-test.cc b/test/ostream-test.cc index 069c8092..7e9fa282 100644 --- a/test/ostream-test.cc +++ b/test/ostream-test.cc @@ -59,7 +59,7 @@ TEST(OStreamTest, Enum) { } struct TestArgFormatter : fmt::ArgFormatter { - TestArgFormatter(fmt::Writer &w, fmt::format_context &ctx, + TestArgFormatter(fmt::writer &w, fmt::format_context &ctx, fmt::FormatSpec &s) : fmt::ArgFormatter(w, ctx, s) {} }; @@ -134,7 +134,7 @@ TEST(OStreamTest, WriteToOStreamMaxSize) { if (max_size <= fmt::internal::to_unsigned(max_streamsize)) return; - class TestWriter : public fmt::BasicWriter { + class TestWriter : public fmt::basic_writer { private: struct TestBuffer : fmt::Buffer { explicit TestBuffer(std::size_t size) { size_ = size; } @@ -142,7 +142,7 @@ TEST(OStreamTest, WriteToOStreamMaxSize) { } buffer_; public: explicit TestWriter(std::size_t size) - : fmt::BasicWriter(buffer_), buffer_(size) {} + : fmt::basic_writer(buffer_), buffer_(size) {} } w(max_size); struct MockStreamBuf : std::streambuf { diff --git a/test/util-test.cc b/test/util-test.cc index 978a8cc8..8a80f659 100644 --- a/test/util-test.cc +++ b/test/util-test.cc @@ -68,7 +68,7 @@ namespace { struct Test {}; template -void format_value(fmt::BasicWriter &w, Test, +void format_value(fmt::basic_writer &w, Test, fmt::basic_format_context &) { w << "test"; } @@ -417,7 +417,7 @@ struct CustomContext { bool called; }; -void format_value(fmt::Writer &, const Test &, CustomContext &ctx) { +void format_value(fmt::writer &, const Test &, CustomContext &ctx) { ctx.called = true; } @@ -690,7 +690,7 @@ TEST(UtilTest, UTF16ToUTF8Convert) { #endif // _WIN32 typedef void (*FormatErrorMessage)( - fmt::Writer &out, int error_code, StringRef message); + fmt::writer &out, int error_code, StringRef message); template void check_throw_error(int error_code, FormatErrorMessage format) { From b77c8190cad52b3e4f8c84158d9f1bf9f2657597 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Fri, 30 Dec 2016 13:12:27 -0800 Subject: [PATCH 072/340] FPUtil -> fputil --- fmt/format.h | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/fmt/format.h b/fmt/format.h index 1549f4a5..1d9cf966 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -195,7 +195,7 @@ typedef __int64 intmax_t; #if FMT_USE_DELETED_FUNCTIONS || FMT_HAS_FEATURE(cxx_deleted_functions) || \ (FMT_GCC_VERSION >= 404 && FMT_HAS_GXX_CXX11) || FMT_MSC_VER >= 1800 -# define FMT_DELETED_OR_UNDEFINED = delete +# define FMT_DELETED_OR_UNDEFINED = delete # define FMT_DISALLOW_COPY_AND_ASSIGN(TypeName) \ TypeName(const TypeName&) = delete; \ TypeName& operator=(const TypeName&) = delete @@ -283,20 +283,20 @@ inline uint32_t clzll(uint64_t x) { namespace fmt { namespace internal { -struct DummyInt { +struct dummy_int { int data[2]; operator int() const { return 0; } }; -typedef std::numeric_limits FPUtil; +typedef std::numeric_limits fputil; // Dummy implementations of system functions such as signbit and ecvt called // if the latter are not available. -inline DummyInt signbit(...) { return DummyInt(); } -inline DummyInt _ecvt_s(...) { return DummyInt(); } -inline DummyInt isinf(...) { return DummyInt(); } -inline DummyInt _finite(...) { return DummyInt(); } -inline DummyInt isnan(...) { return DummyInt(); } -inline DummyInt _isnan(...) { return DummyInt(); } +inline dummy_int signbit(...) { return dummy_int(); } +inline dummy_int _ecvt_s(...) { return dummy_int(); } +inline dummy_int isinf(...) { return dummy_int(); } +inline dummy_int _finite(...) { return dummy_int(); } +inline dummy_int isnan(...) { return dummy_int(); } +inline dummy_int _isnan(...) { return dummy_int(); } // A helper function to suppress bogus "conditional expression is constant" // warnings. @@ -311,7 +311,7 @@ namespace std { // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=48891 // and the same for isnan and signbit. template <> -class numeric_limits : +class numeric_limits : public std::numeric_limits { public: // Portable version of isinf. @@ -2760,14 +2760,14 @@ void basic_writer::write_double(T value, const FormatSpec &spec) { char sign = 0; // Use isnegative instead of value < 0 because the latter is always // false for NaN. - if (internal::FPUtil::isnegative(static_cast(value))) { + if (internal::fputil::isnegative(static_cast(value))) { sign = '-'; value = -value; } else if (spec.flag(SIGN_FLAG)) { sign = spec.flag(PLUS_FLAG) ? '+' : ' '; } - if (internal::FPUtil::isnotanumber(value)) { + if (internal::fputil::isnotanumber(value)) { // Format NaN ourselves because sprintf's output is not consistent // across platforms. std::size_t nan_size = 4; @@ -2782,7 +2782,7 @@ void basic_writer::write_double(T value, const FormatSpec &spec) { return; } - if (internal::FPUtil::isinfinity(value)) { + if (internal::fputil::isinfinity(value)) { // Format infinity ourselves because sprintf's output is not consistent // across platforms. std::size_t inf_size = 4; From ec15ef7b7b50748a3d8e77ecdb001912c55d0929 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sun, 22 Jan 2017 07:40:21 -0800 Subject: [PATCH 073/340] Replace operator<< with write function --- fmt/format.cc | 19 +++++--- fmt/format.h | 67 ++++++++++++---------------- fmt/ostream.cc | 2 +- fmt/printf.h | 2 +- fmt/string.h | 2 +- test/custom-formatter-test.cc | 2 +- test/format-impl-test.cc | 4 +- test/format-test.cc | 82 +++++++++++++++++++++-------------- test/ostream-test.cc | 2 +- test/string-test.cc | 8 +++- test/util-test.cc | 4 +- 11 files changed, 105 insertions(+), 89 deletions(-) diff --git a/fmt/format.cc b/fmt/format.cc index cd17ebf1..eed7f915 100644 --- a/fmt/format.cc +++ b/fmt/format.cc @@ -193,9 +193,12 @@ void format_error_code(writer &out, int error_code, ++error_code_size; } error_code_size += internal::count_digits(abs_value); - if (message.size() <= internal::INLINE_BUFFER_SIZE - error_code_size) - out << message << SEP; - out << ERROR_STR << error_code; + if (message.size() <= internal::INLINE_BUFFER_SIZE - error_code_size) { + out.write(message); + out.write(SEP); + } + out.write(ERROR_STR); + out.write(error_code); assert(out.size() <= internal::INLINE_BUFFER_SIZE); } @@ -367,7 +370,9 @@ FMT_FUNC void internal::format_windows_error( if (result != 0) { UTF16ToUTF8 utf8_message; if (utf8_message.convert(system_message) == ERROR_SUCCESS) { - out << message << ": " << utf8_message; + out.write(message); + out.write(": "); + out.write(utf8_message); return; } break; @@ -391,7 +396,9 @@ FMT_FUNC void format_system_error( char *system_message = &buffer[0]; int result = safe_strerror(error_code, system_message, buffer.size()); if (result == 0) { - out << message << ": " << system_message; + out.write(message); + out.write(": "); + out.write(system_message); return; } if (result != ERANGE) @@ -423,7 +430,7 @@ FMT_FUNC void report_windows_error( FMT_FUNC void vprint(std::FILE *f, CStringRef format_str, format_args args) { MemoryWriter w; - w.vwrite(format_str, args); + w.vformat(format_str, args); std::fwrite(w.data(), 1, w.size(), f); } diff --git a/fmt/format.h b/fmt/format.h index 1d9cf966..e6ea86d4 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -1535,7 +1535,7 @@ class format_arg_store { static const uint64_t TYPES = internal::make_type(); format_arg_store(const Args &... args) - : data_(Array{internal::make_arg(args)...}) {} + : data_(Array{{internal::make_arg(args)...}}) {} const value_type *data() const { return data_.data(); } }; @@ -2043,7 +2043,7 @@ class ArgFormatterBase { template inline void write(basic_writer &w, const Char *start, const Char *end) { if (start != end) - w << BasicStringRef(start, internal::to_unsigned(end - start)); + w.write(BasicStringRef(start, internal::to_unsigned(end - start))); } template @@ -2392,8 +2392,8 @@ class basic_writer { return std::basic_string(&buffer_[0], buffer_.size()); } - void vwrite(BasicCStringRef format, - basic_format_args> args); + void vformat(BasicCStringRef format, + basic_format_args> args); /** \rst Writes formatted data. @@ -2403,8 +2403,8 @@ class basic_writer { **Example**:: MemoryWriter out; - out.write("Current point:\n"); - out.write("({:+f}, {:+f})", -3.14, 3.14); + out.format("Current point:\n"); + out.format("({:+f}, {:+f})", -3.14, 3.14); This will write the following output to the ``out`` object: @@ -2420,27 +2420,24 @@ class basic_writer { \endrst */ template - void write(BasicCStringRef format, const Args & ... args) { - vwrite(format, make_xformat_args>(args...)); + void format(BasicCStringRef format, const Args & ... args) { + vformat(format, make_xformat_args>(args...)); } - basic_writer &operator<<(int value) { + void write(int value) { write_decimal(value); - return *this; } - basic_writer &operator<<(unsigned value) { - return *this << IntFormatSpec(value); + void write(unsigned value) { + *this << IntFormatSpec(value); } - basic_writer &operator<<(long value) { + void write(long value) { write_decimal(value); - return *this; } - basic_writer &operator<<(unsigned long value) { - return *this << IntFormatSpec(value); + void write(unsigned long value) { + *this << IntFormatSpec(value); } - basic_writer &operator<<(LongLong value) { + void write(LongLong value) { write_decimal(value); - return *this; } /** @@ -2448,13 +2445,12 @@ class basic_writer { Formats *value* and writes it to the stream. \endrst */ - basic_writer &operator<<(ULongLong value) { - return *this << IntFormatSpec(value); + void write(ULongLong value) { + *this << IntFormatSpec(value); } - basic_writer &operator<<(double value) { + void write(double value) { write_double(value, FormatSpec()); - return *this; } /** @@ -2463,23 +2459,19 @@ class basic_writer { (``'g'``) and writes it to the stream. \endrst */ - basic_writer &operator<<(long double value) { + void write(long double value) { write_double(value, FormatSpec()); - return *this; } /** Writes a character to the stream. */ - basic_writer &operator<<(char value) { + void write(char value) { buffer_.push_back(value); - return *this; } - basic_writer &operator<<( - typename internal::WCharHelper::Supported value) { + void write(typename internal::WCharHelper::Supported value) { buffer_.push_back(value); - return *this; } /** @@ -2487,17 +2479,14 @@ class basic_writer { Writes *value* to the stream. \endrst */ - basic_writer &operator<<(fmt::BasicStringRef value) { + void write(fmt::BasicStringRef value) { const Char *str = value.data(); buffer_.append(str, str + value.size()); - return *this; } - basic_writer &operator<<( - typename internal::WCharHelper::Supported value) { + void write(typename internal::WCharHelper::Supported value) { const char *str = value.data(); buffer_.append(str, str + value.size()); - return *this; } template @@ -3076,7 +3065,7 @@ inline void print_colored(Color c, CStringRef format_str, inline std::string vformat(CStringRef format_str, format_args args) { MemoryWriter w; - w.vwrite(format_str, args); + w.vformat(format_str, args); return w.str(); } @@ -3096,7 +3085,7 @@ inline std::string format(CStringRef format_str, const Args & ... args) { inline std::wstring vformat(WCStringRef format_str, wformat_args args) { WMemoryWriter w; - w.vwrite(format_str, args); + w.vformat(format_str, args); return w.str(); } @@ -3574,7 +3563,7 @@ void do_format_arg(basic_writer &writer, basic_format_arg arg, /** Formats arguments and writes the output to the writer. */ template -void vformat(basic_writer &writer, BasicCStringRef format_str, +void vwrite(basic_writer &writer, BasicCStringRef format_str, basic_format_args args) { basic_format_context ctx(format_str.c_str(), args); const Char *&s = ctx.ptr(); @@ -3599,10 +3588,10 @@ void vformat(basic_writer &writer, BasicCStringRef format_str, } template -inline void basic_writer::vwrite( +inline void basic_writer::vformat( BasicCStringRef format, basic_format_args> args) { - vformat>(*this, format, args); + vwrite>(*this, format, args); } } // namespace fmt diff --git a/fmt/ostream.cc b/fmt/ostream.cc index ebfb50d1..0c7c7501 100644 --- a/fmt/ostream.cc +++ b/fmt/ostream.cc @@ -30,7 +30,7 @@ FMT_FUNC void write(std::ostream &os, writer &w) { FMT_FUNC void vprint(std::ostream &os, CStringRef format_str, format_args args) { MemoryWriter w; - w.vwrite(format_str, args); + w.vformat(format_str, args); internal::write(os, w); } } // namespace fmt diff --git a/fmt/printf.h b/fmt/printf.h index 8a4a486a..0219ef8e 100644 --- a/fmt/printf.h +++ b/fmt/printf.h @@ -505,7 +505,7 @@ template void format_value(basic_writer &w, const T &value, printf_context& ctx) { internal::MemoryBuffer buffer; - w << internal::format_value(buffer, value); + w.write(internal::format_value(buffer, value)); } template diff --git a/fmt/string.h b/fmt/string.h index c1731c75..0de41b98 100644 --- a/fmt/string.h +++ b/fmt/string.h @@ -111,7 +111,7 @@ typedef BasicStringWriter WStringWriter; template std::string to_string(const T &value) { fmt::MemoryWriter w; - w << value; + w.write(value); return w.str(); } } diff --git a/test/custom-formatter-test.cc b/test/custom-formatter-test.cc index 9f90b258..e1ece844 100644 --- a/test/custom-formatter-test.cc +++ b/test/custom-formatter-test.cc @@ -48,7 +48,7 @@ class CustomPrintfArgFormatter : public PrintfArgFormatter { std::string custom_vformat(fmt::CStringRef format_str, fmt::format_args args) { fmt::MemoryWriter writer; // Pass custom argument formatter as a template arg to vformat. - fmt::vformat(writer, format_str, args); + fmt::vwrite(writer, format_str, args); return writer.str(); } diff --git a/test/format-impl-test.cc b/test/format-impl-test.cc index 40ee0a8a..0c7c2ea8 100644 --- a/test/format-impl-test.cc +++ b/test/format-impl-test.cc @@ -65,7 +65,7 @@ TEST(FormatTest, ArgConverter) { TEST(FormatTest, FormatNegativeNaN) { double nan = std::numeric_limits::quiet_NaN(); - if (fmt::internal::FPUtil::isnegative(-nan)) + if (fmt::internal::fputil::isnegative(-nan)) EXPECT_EQ("-nan", fmt::format("{}", -nan)); else fmt::print("Warning: compiler doesn't handle negative NaN correctly"); @@ -107,7 +107,7 @@ TEST(FormatTest, FormatErrorCode) { std::string msg = "error 42", sep = ": "; { fmt::MemoryWriter w; - w << "garbage"; + w.write("garbage"); fmt::format_error_code(w, 42, "test"); EXPECT_EQ("test: " + msg, w.str()); } diff --git a/test/format-test.cc b/test/format-test.cc index 6419771b..c7c20e91 100644 --- a/test/format-test.cc +++ b/test/format-test.cc @@ -107,8 +107,9 @@ void std_format(long double value, std::wstring &result) { // as writing it to std::basic_ostringstream. template ::testing::AssertionResult check_write(const T &value, const char *type) { - std::basic_string actual = - (fmt::BasicMemoryWriter() << value).str(); + fmt::BasicMemoryWriter writer; + writer.write(value); + std::basic_string actual = writer.str(); std::basic_string expected; std_format(value, expected); if (expected == actual) @@ -191,19 +192,19 @@ void check_move_writer(const std::string &str, MemoryWriter &w) { TEST(WriterTest, MoveCtor) { MemoryWriter w; - w << "test"; + w.write("test"); check_move_writer("test", w); // This fills the inline buffer, but doesn't cause dynamic allocation. std::string s; for (int i = 0; i < fmt::internal::INLINE_BUFFER_SIZE; ++i) s += '*'; w.clear(); - w << s; + w.write(s); check_move_writer(s, w); const char *inline_buffer_ptr = w.data(); // Adding one more character causes the content to move from the inline to // a dynamically allocated buffer. - w << '*'; + w.write('*'); MemoryWriter w2(std::move(w)); // Move should rip the guts of the first writer. EXPECT_EQ(inline_buffer_ptr, w.data()); @@ -220,19 +221,19 @@ void CheckMoveAssignWriter(const std::string &str, MemoryWriter &w) { TEST(WriterTest, MoveAssignment) { MemoryWriter w; - w << "test"; + w.write("test"); CheckMoveAssignWriter("test", w); // This fills the inline buffer, but doesn't cause dynamic allocation. std::string s; for (int i = 0; i < fmt::internal::INLINE_BUFFER_SIZE; ++i) s += '*'; w.clear(); - w << s; + w.write(s); CheckMoveAssignWriter(s, w); const char *inline_buffer_ptr = w.data(); // Adding one more character causes the content to move from the inline to // a dynamically allocated buffer. - w << '*'; + w.write('*'); MemoryWriter w2; w2 = std::move(w); // Move should rip the guts of the first writer. @@ -252,19 +253,19 @@ TEST(WriterTest, Allocator) { std::vector mem(size); EXPECT_CALL(alloc, allocate(size)).WillOnce(testing::Return(&mem[0])); for (int i = 0; i < fmt::internal::INLINE_BUFFER_SIZE + 1; ++i) - w << '*'; + w.write('*'); EXPECT_CALL(alloc, deallocate(&mem[0], size)); } TEST(WriterTest, Data) { MemoryWriter w; - w << 42; + w.write(42); EXPECT_EQ("42", std::string(w.data(), w.size())); } TEST(WriterTest, WriteWithoutArgs) { MemoryWriter w; - w.write("test"); + w.format("test"); EXPECT_EQ("test", std::string(w.data(), w.size())); } @@ -317,15 +318,15 @@ TEST(WriterTest, WriteLongDouble) { TEST(WriterTest, WriteDoubleAtBufferBoundary) { MemoryWriter writer; for (int i = 0; i < 100; ++i) - writer << 1.23456789; + writer.write(1.23456789); } TEST(WriterTest, WriteDoubleWithFilledBuffer) { MemoryWriter writer; // Fill the buffer. for (int i = 0; i < fmt::internal::INLINE_BUFFER_SIZE; ++i) - writer << ' '; - writer << 1.2; + writer.write(' '); + writer.write(1.2); EXPECT_STREQ("1.2", writer.c_str() + fmt::internal::INLINE_BUFFER_SIZE); } @@ -399,8 +400,13 @@ TEST(WriterTest, hexu) { } template -basic_writer &operator<<(basic_writer &f, const Date &d) { - return f << d.year() << '-' << d.month() << '-' << d.day(); +basic_writer &operator<<(basic_writer &w, const Date &d) { + w.write(d.year()); + w.write('-'); + w.write(d.month()); + w.write('-'); + w.write(d.day()); + return w; } class ISO8601DateFormatter { @@ -412,8 +418,12 @@ public: template friend basic_writer &operator<<( basic_writer &w, const ISO8601DateFormatter &d) { - return w << pad(d.date_->year(), 4, '0') << '-' - << pad(d.date_->month(), 2, '0') << '-' << pad(d.date_->day(), 2, '0'); + w << pad(d.date_->year(), 4, '0'); + w.write('-'); + w << pad(d.date_->month(), 2, '0'); + w.write('-'); + w << pad(d.date_->day(), 2, '0'); + return w; } }; @@ -467,12 +477,12 @@ TEST(WriterTest, NoConflictWithIOManip) { TEST(WriterTest, Format) { MemoryWriter w; - w.write("part{0}", 1); + w.format("part{0}", 1); EXPECT_EQ(strlen("part1"), w.size()); EXPECT_STREQ("part1", w.c_str()); EXPECT_STREQ("part1", w.data()); EXPECT_EQ("part1", w.str()); - w.write("part{0}", 2); + w.format("part{0}", 2); EXPECT_EQ(strlen("part1part2"), w.size()); EXPECT_STREQ("part1part2", w.c_str()); EXPECT_STREQ("part1part2", w.data()); @@ -495,27 +505,27 @@ TEST(ArrayWriterTest, CompileTimeSizeCtor) { fmt::ArrayWriter w(array); EXPECT_EQ(0u, w.size()); EXPECT_STREQ("", w.c_str()); - w.write("{:10}", 1); + w.format("{:10}", 1); } TEST(ArrayWriterTest, Write) { char array[10]; fmt::ArrayWriter w(array, sizeof(array)); - w.write("{}", 42); + w.format("{}", 42); EXPECT_EQ("42", w.str()); } TEST(ArrayWriterTest, BufferOverflow) { char array[10]; fmt::ArrayWriter w(array, sizeof(array)); - w.write("{:10}", 1); - EXPECT_THROW_MSG(w.write("{}", 1), std::runtime_error, "buffer overflow"); + w.format("{:10}", 1); + EXPECT_THROW_MSG(w.format("{}", 1), std::runtime_error, "buffer overflow"); } TEST(ArrayWriterTest, WChar) { wchar_t array[10]; fmt::WArrayWriter w(array); - w.write(L"{}", 42); + w.format(L"{}", 42); EXPECT_EQ(L"42", w.str()); } @@ -1356,7 +1366,11 @@ TEST(FormatterTest, FormatCStringRef) { } void format_value(fmt::writer &w, const Date &d, fmt::format_context &) { - w << d.year() << '-' << d.month() << '-' << d.day(); + w.write(d.year()); + w.write('-'); + w.write(d.month()); + w.write('-'); + w.write(d.day()); } TEST(FormatterTest, FormatCustom) { @@ -1369,7 +1383,7 @@ class Answer {}; template void format_value(basic_writer &w, Answer, fmt::format_context &) { - w << "42"; + w.write("42"); } TEST(FormatterTest, CustomFormat) { @@ -1400,14 +1414,16 @@ TEST(FormatterTest, FormatExamples) { EXPECT_EQ("42", format(std::string("{}"), 42)); MemoryWriter out; - out << "The answer is " << 42 << "\n"; - out.write("({:+f}, {:+f})", -3.14, 3.14); + out.write("The answer is "); + out.write(42); + out.write("\n"); + out.format("({:+f}, {:+f})", -3.14, 3.14); EXPECT_EQ("The answer is 42\n(-3.140000, +3.140000)", out.str()); { MemoryWriter writer; for (int i = 0; i < 10; i++) - writer.write("{}", i); + writer.format("{}", i); std::string s = writer.str(); // s == 0123456789 EXPECT_EQ("0123456789", s); } @@ -1552,8 +1568,8 @@ TEST(StrTest, Convert) { std::string vformat_message(int id, const char *format, fmt::format_args args) { MemoryWriter w; - w.write("[{}] ", id); - w.vwrite(format, args); + w.format("[{}] ", id); + w.vformat(format, args); return w.str(); } @@ -1642,7 +1658,7 @@ class MockArgFormatter : public fmt::internal::ArgFormatterBase { void custom_vformat(fmt::CStringRef format_str, fmt::format_args args) { fmt::MemoryWriter writer; - fmt::vformat(writer, format_str, args); + fmt::vwrite(writer, format_str, args); } template diff --git a/test/ostream-test.cc b/test/ostream-test.cc index 7e9fa282..b5c46a61 100644 --- a/test/ostream-test.cc +++ b/test/ostream-test.cc @@ -123,7 +123,7 @@ TEST(OStreamTest, Print) { TEST(OStreamTest, WriteToOStream) { std::ostringstream os; fmt::MemoryWriter w; - w << "foo"; + w.write("foo"); fmt::internal::write(os, w); EXPECT_EQ("foo", os.str()); } diff --git a/test/string-test.cc b/test/string-test.cc index f74a5b8a..b02867da 100644 --- a/test/string-test.cc +++ b/test/string-test.cc @@ -60,7 +60,9 @@ TEST(StringBufferTest, MoveTo) { TEST(StringWriterTest, MoveTo) { fmt::StringWriter out; - out << "The answer is " << 42 << "\n"; + out.write("The answer is "); + out.write(42); + out.write("\n"); std::string s; out.move_to(s); EXPECT_EQ("The answer is 42\n", s); @@ -69,7 +71,9 @@ TEST(StringWriterTest, MoveTo) { TEST(StringWriterTest, WString) { fmt::WStringWriter out; - out << "The answer is " << 42 << "\n"; + out.write("The answer is "); + out.write(42); + out.write("\n"); std::wstring s; out.move_to(s); EXPECT_EQ(L"The answer is 42\n", s); diff --git a/test/util-test.cc b/test/util-test.cc index 8a80f659..a02bef69 100644 --- a/test/util-test.cc +++ b/test/util-test.cc @@ -70,7 +70,7 @@ struct Test {}; template void format_value(fmt::basic_writer &w, Test, fmt::basic_format_context &) { - w << "test"; + w.write("test"); } template @@ -726,7 +726,7 @@ TEST(UtilTest, SystemError) { TEST(UtilTest, ReportSystemError) { fmt::MemoryWriter out; fmt::format_system_error(out, EDOM, "test error"); - out << '\n'; + out.write('\n'); EXPECT_WRITE(stderr, fmt::report_system_error(EDOM, "test error"), out.str()); } From 848502771060414df34a0a1466b83b43cdaf5ea5 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sun, 22 Jan 2017 11:28:55 -0800 Subject: [PATCH 074/340] Use named argument emulation instead of nested functions --- fmt/format.h | 103 +++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 92 insertions(+), 11 deletions(-) diff --git a/fmt/format.h b/fmt/format.h index e6ea86d4..9a7a99a9 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -1639,6 +1639,52 @@ enum { CHAR_FLAG = 0x10 // Argument has char type - used in error reporting. }; +enum format_spec_tag {fill_tag, align_tag, width_tag, type_tag}; + +// Format specifier. +template +class format_spec { + private: + T value_; + + public: + typedef T value_type; + + explicit format_spec(T value) : value_(value) {} + + T value() const { return value_; } +}; + +template +using fill_spec = format_spec; + +using width_spec = format_spec; +using type_spec = format_spec; + +class fill_spec_factory { + public: + constexpr fill_spec_factory() {} + + template + fill_spec operator=(Char value) const { + return fill_spec(value); + } +}; + +template +class format_spec_factory { + public: + constexpr format_spec_factory() {} + + FormatSpec operator=(typename FormatSpec::value_type value) const { + return FormatSpec(value); + } +}; + +constexpr fill_spec_factory fill; +constexpr format_spec_factory width; +constexpr format_spec_factory type; + // An empty format specifier. struct EmptySpec {}; @@ -1688,15 +1734,40 @@ struct AlignTypeSpec : AlignSpec { }; // A full format specifier. -struct FormatSpec : AlignSpec { +class FormatSpec : public AlignSpec { + private: + void set(fill_spec fill) { + fill_ = fill.value(); + } + + void set(width_spec width) { + width_ = width.value(); + } + + void set(type_spec type) { + type_ = type.value(); + } + + template + void set(Spec spec, Specs... tail) { + set(spec); + set(tail...); + } + + public: unsigned flags_; int precision_; char type_; - FormatSpec( - unsigned width = 0, char type = 0, wchar_t fill = ' ') + FormatSpec(unsigned width = 0, char type = 0, wchar_t fill = ' ') : AlignSpec(width, fill), flags_(0), precision_(-1), type_(type) {} + template + explicit FormatSpec(FormatSpecs... specs) + : AlignSpec(0, ' '), flags_(0), precision_(-1), type_(0){ + set(specs...); + } + bool flag(unsigned f) const { return (flags_ & f) != 0; } int precision() const { return precision_; } char type() const { return type_; } @@ -1811,13 +1882,6 @@ inline IntFormatSpec > pad( \ TYPE value, unsigned width) { \ return IntFormatSpec >( \ value, AlignTypeSpec<0>(width, ' ')); \ -} \ - \ -template \ -inline IntFormatSpec, Char> pad( \ - TYPE value, unsigned width, Char fill) { \ - return IntFormatSpec, Char>( \ - value, AlignTypeSpec<0>(width, fill)); \ } FMT_DEFINE_INT_FORMATTERS(int) @@ -2226,6 +2290,17 @@ class SystemError : public internal::RuntimeError { FMT_API void format_system_error(fmt::writer &out, int error_code, fmt::StringRef message) FMT_NOEXCEPT; +namespace internal { +// Named format specifier. +template +class named_format_spec { + public: + constexpr named_format_spec() {} +}; + +constexpr named_format_spec width; +} + /** \rst This template provides operations for formatting and writing data into @@ -2309,7 +2384,7 @@ class basic_writer { CharPtr prepare_int_buffer(unsigned num_digits, const Spec &spec, const char *prefix, unsigned prefix_size); - // Formats an integer. + // Writes a formatted integer. template void write_int(T value, Spec spec); @@ -2449,6 +2524,12 @@ class basic_writer { *this << IntFormatSpec(value); } + template + typename std::enable_if::value, void>::type + write(T value, FormatSpecs... specs) { + write_int(value, FormatSpec(specs...)); + } + void write(double value) { write_double(value, FormatSpec()); } From aea5d3ab00907edc9f47b6f5288d9a7f7d739750 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sun, 22 Jan 2017 11:48:02 -0800 Subject: [PATCH 075/340] Improve compatibility with older gcc and update tests --- fmt/format.h | 5 ++++- test/format-test.cc | 32 +++++++++++++++++++++----------- 2 files changed, 25 insertions(+), 12 deletions(-) diff --git a/fmt/format.h b/fmt/format.h index 9a7a99a9..13be77c3 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -1656,7 +1656,10 @@ class format_spec { }; template -using fill_spec = format_spec; +class fill_spec : public format_spec { + public: + explicit fill_spec(Char value) : format_spec(value) {} +}; using width_spec = format_spec; using type_spec = format_spec; diff --git a/test/format-test.cc b/test/format-test.cc index c7c20e91..378e8249 100644 --- a/test/format-test.cc +++ b/test/format-test.cc @@ -418,25 +418,34 @@ public: template friend basic_writer &operator<<( basic_writer &w, const ISO8601DateFormatter &d) { - w << pad(d.date_->year(), 4, '0'); + using namespace fmt; + w.write(d.date_->year(), width=4, fill='0'); w.write('-'); - w << pad(d.date_->month(), 2, '0'); + w.write(d.date_->month(), width=2, fill='0'); w.write('-'); - w << pad(d.date_->day(), 2, '0'); + w.write(d.date_->day(), width=2, fill='0'); return w; } }; ISO8601DateFormatter iso8601(const Date &d) { return ISO8601DateFormatter(d); } +template +std::string write_str(T... args) { + MemoryWriter writer; + using namespace fmt; + writer.write(args...); + return writer.str(); +} + TEST(WriterTest, pad) { - using fmt::hex; - EXPECT_EQ(" cafe", (MemoryWriter() << pad(hex(0xcafe), 8)).str()); - EXPECT_EQ(" babe", (MemoryWriter() << pad(hex(0xbabeu), 8)).str()); - EXPECT_EQ(" dead", (MemoryWriter() << pad(hex(0xdeadl), 8)).str()); - EXPECT_EQ(" beef", (MemoryWriter() << pad(hex(0xbeeful), 8)).str()); - EXPECT_EQ(" dead", (MemoryWriter() << pad(hex(0xdeadll), 8)).str()); - EXPECT_EQ(" beef", (MemoryWriter() << pad(hex(0xbeefull), 8)).str()); + using namespace fmt; + EXPECT_EQ(" cafe", write_str(0xcafe, width=8, type='x')); + EXPECT_EQ(" babe", write_str(0xbabeu, width=8, type='x')); + EXPECT_EQ(" dead", write_str(0xdeadl, width=8, type='x')); + EXPECT_EQ(" beef", write_str(0xbeeful, width=8, type='x')); + EXPECT_EQ(" dead", write_str(0xdeadll, width=8, type='x')); + EXPECT_EQ(" beef", write_str(0xbeefull, width=8, type='x')); EXPECT_EQ(" 11", (MemoryWriter() << pad(11, 7)).str()); EXPECT_EQ(" 22", (MemoryWriter() << pad(22u, 7)).str()); @@ -447,7 +456,8 @@ TEST(WriterTest, pad) { MemoryWriter w; w.clear(); - w << pad(42, 5, '0'); + using namespace fmt; + w.write(42, width=5, fill='0'); EXPECT_EQ("00042", w.str()); w.clear(); w << Date(2012, 12, 9); From aaa0fc396b718a034fb1174e1c1920bbd7877c1f Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sun, 22 Jan 2017 12:16:16 -0800 Subject: [PATCH 076/340] Improve compatibility with old compilers and fix test --- fmt/format.h | 6 ++++-- test/util-test.cc | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/fmt/format.h b/fmt/format.h index 13be77c3..2a411d94 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -1655,14 +1655,16 @@ class format_spec { T value() const { return value_; } }; +// template +// using fill_spec = format_spec; template class fill_spec : public format_spec { public: explicit fill_spec(Char value) : format_spec(value) {} }; -using width_spec = format_spec; -using type_spec = format_spec; +typedef format_spec width_spec; +typedef format_spec type_spec; class fill_spec_factory { public: diff --git a/test/util-test.cc b/test/util-test.cc index a02bef69..88bad995 100644 --- a/test/util-test.cc +++ b/test/util-test.cc @@ -781,7 +781,7 @@ TEST(UtilTest, WindowsError) { TEST(UtilTest, ReportWindowsError) { fmt::MemoryWriter out; fmt::internal::format_windows_error(out, ERROR_FILE_EXISTS, "test error"); - out << '\n'; + out.write('\n'); EXPECT_WRITE(stderr, fmt::report_windows_error(ERROR_FILE_EXISTS, "test error"), out.str()); } From 4863730eca8041b4d247cb0c666f55984f39d288 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sun, 22 Jan 2017 19:11:47 -0800 Subject: [PATCH 077/340] Remove pad --- fmt/format.h | 74 +++++---------------------------------------- test/format-test.cc | 42 ++++++++++++++----------- 2 files changed, 31 insertions(+), 85 deletions(-) diff --git a/fmt/format.h b/fmt/format.h index 2a411d94..f26e5cb0 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -1741,7 +1741,8 @@ struct AlignTypeSpec : AlignSpec { // A full format specifier. class FormatSpec : public AlignSpec { private: - void set(fill_spec fill) { + template + void set(fill_spec fill) { fill_ = fill.value(); } @@ -1829,24 +1830,6 @@ IntFormatSpec > hex(int value); */ IntFormatSpec > hexu(int value); -/** - \rst - Returns an integer format specifier to pad the formatted argument with the - fill character to the specified width using the default (right) numeric - alignment. - - **Example**:: - - MemoryWriter out; - out << pad(hex(0xcafe), 8, '0'); - // out.str() == "0000cafe" - - \endrst - */ -template -IntFormatSpec, Char> pad( - int value, unsigned width, Char fill = ' '); - #define FMT_DEFINE_INT_FORMATTERS(TYPE) \ inline IntFormatSpec > bin(TYPE value) { \ return IntFormatSpec >(value, TypeSpec<'b'>()); \ @@ -1862,31 +1845,6 @@ inline IntFormatSpec > hex(TYPE value) { \ \ inline IntFormatSpec > hexu(TYPE value) { \ return IntFormatSpec >(value, TypeSpec<'X'>()); \ -} \ - \ -template \ -inline IntFormatSpec > pad( \ - IntFormatSpec > f, unsigned width) { \ - return IntFormatSpec >( \ - f.value(), AlignTypeSpec(width, ' ')); \ -} \ - \ -/* For compatibility with older compilers we provide two overloads for pad, */ \ -/* one that takes a fill character and one that doesn't. In the future this */ \ -/* can be replaced with one overload making the template argument Char */ \ -/* default to char (C++11). */ \ -template \ -inline IntFormatSpec, Char> pad( \ - IntFormatSpec, Char> f, \ - unsigned width, Char fill) { \ - return IntFormatSpec, Char>( \ - f.value(), AlignTypeSpec(width, fill)); \ -} \ - \ -inline IntFormatSpec > pad( \ - TYPE value, unsigned width) { \ - return IntFormatSpec >( \ - value, AlignTypeSpec<0>(width, ' ')); \ } FMT_DEFINE_INT_FORMATTERS(int) @@ -1896,29 +1854,6 @@ FMT_DEFINE_INT_FORMATTERS(unsigned long) FMT_DEFINE_INT_FORMATTERS(LongLong) FMT_DEFINE_INT_FORMATTERS(ULongLong) -/** - \rst - Returns a string formatter that pads the formatted argument with the fill - character to the specified width using the default (left) string alignment. - - **Example**:: - - std::string s = str(MemoryWriter() << pad("abc", 8)); - // s == "abc " - - \endrst - */ -template -inline StrFormatSpec pad( - const Char *str, unsigned width, Char fill = ' ') { - return StrFormatSpec(str, width, fill); -} - -inline StrFormatSpec pad( - const wchar_t *str, unsigned width, char fill = ' ') { - return StrFormatSpec(str, width, fill); -} - namespace internal { template @@ -2575,6 +2510,11 @@ class basic_writer { buffer_.append(str, str + value.size()); } + template + void write(BasicStringRef str, FormatSpecs... specs) { + write_str(str, FormatSpec(specs...)); + } + template basic_writer &operator<<(IntFormatSpec spec) { internal::CharTraits::convert(FillChar()); diff --git a/test/format-test.cc b/test/format-test.cc index 378e8249..12c9c5b9 100644 --- a/test/format-test.cc +++ b/test/format-test.cc @@ -77,7 +77,9 @@ using fmt::StringRef; using fmt::CStringRef; using fmt::MemoryWriter; using fmt::WMemoryWriter; -using fmt::pad; +using fmt::fill; +using fmt::type; +using fmt::width; namespace { @@ -418,7 +420,6 @@ public: template friend basic_writer &operator<<( basic_writer &w, const ISO8601DateFormatter &d) { - using namespace fmt; w.write(d.date_->year(), width=4, fill='0'); w.write('-'); w.write(d.date_->month(), width=2, fill='0'); @@ -438,8 +439,15 @@ std::string write_str(T... args) { return writer.str(); } -TEST(WriterTest, pad) { +template +std::wstring write_wstr(T... args) { + WMemoryWriter writer; using namespace fmt; + writer.write(args...); + return writer.str(); +} + +TEST(WriterTest, pad) { EXPECT_EQ(" cafe", write_str(0xcafe, width=8, type='x')); EXPECT_EQ(" babe", write_str(0xbabeu, width=8, type='x')); EXPECT_EQ(" dead", write_str(0xdeadl, width=8, type='x')); @@ -447,17 +455,16 @@ TEST(WriterTest, pad) { EXPECT_EQ(" dead", write_str(0xdeadll, width=8, type='x')); EXPECT_EQ(" beef", write_str(0xbeefull, width=8, type='x')); - EXPECT_EQ(" 11", (MemoryWriter() << pad(11, 7)).str()); - EXPECT_EQ(" 22", (MemoryWriter() << pad(22u, 7)).str()); - EXPECT_EQ(" 33", (MemoryWriter() << pad(33l, 7)).str()); - EXPECT_EQ(" 44", (MemoryWriter() << pad(44ul, 7)).str()); - EXPECT_EQ(" 33", (MemoryWriter() << pad(33ll, 7)).str()); - EXPECT_EQ(" 44", (MemoryWriter() << pad(44ull, 7)).str()); + EXPECT_EQ(" 11", write_str(11, width=7)); + EXPECT_EQ(" 22", write_str(22u, width=7)); + EXPECT_EQ(" 33", write_str(33l, width=7)); + EXPECT_EQ(" 44", write_str(44ul, width=7)); + EXPECT_EQ(" 33", write_str(33ll, width=7)); + EXPECT_EQ(" 44", write_str(44ull, width=7)); MemoryWriter w; w.clear(); - using namespace fmt; - w.write(42, width=5, fill='0'); + w.write(42, fmt::width=5, fmt::fill='0'); EXPECT_EQ("00042", w.str()); w.clear(); w << Date(2012, 12, 9); @@ -468,14 +475,14 @@ TEST(WriterTest, pad) { } TEST(WriterTest, PadString) { - EXPECT_EQ("test ", (MemoryWriter() << pad("test", 8)).str()); - EXPECT_EQ("test******", (MemoryWriter() << pad("test", 10, '*')).str()); + EXPECT_EQ("test ", write_str("test", width=8)); + EXPECT_EQ("test******", write_str("test", width=10, fill='*')); } TEST(WriterTest, PadWString) { - EXPECT_EQ(L"test ", (WMemoryWriter() << pad(L"test", 8)).str()); - EXPECT_EQ(L"test******", (WMemoryWriter() << pad(L"test", 10, '*')).str()); - EXPECT_EQ(L"test******", (WMemoryWriter() << pad(L"test", 10, L'*')).str()); + EXPECT_EQ(L"test ", write_wstr(L"test", width=8)); + EXPECT_EQ(L"test******", write_wstr(L"test", width=10, fill='*')); + EXPECT_EQ(L"test******", write_wstr(L"test", width=10, fill=L'*')); } TEST(WriterTest, NoConflictWithIOManip) { @@ -1414,8 +1421,7 @@ TEST(FormatterTest, FormatStringFromSpeedTest) { } TEST(FormatterTest, FormatExamples) { - using fmt::hex; - EXPECT_EQ("0000cafe", (MemoryWriter() << pad(hex(0xcafe), 8, '0')).str()); + EXPECT_EQ("0000cafe", write_str(0xcafe, width=8, fill='0', type='x')); std::string message = format("The answer is {}", 42); EXPECT_EQ("The answer is 42", message); From 984a1029210b912eeac4f77c559f66fb74643ca2 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sat, 28 Jan 2017 04:26:48 -0800 Subject: [PATCH 078/340] Remove IntFormatSpec and StrFormatSpec --- fmt/format.h | 101 +------------------------------------------- test/format-test.cc | 100 ++++++++++++++++++------------------------- 2 files changed, 43 insertions(+), 158 deletions(-) diff --git a/fmt/format.h b/fmt/format.h index f26e5cb0..dcf71c13 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -1779,81 +1779,6 @@ class FormatSpec : public AlignSpec { char type() const { return type_; } }; -// An integer format specifier. -template , typename Char = char> -class IntFormatSpec : public SpecT { - private: - T value_; - - public: - IntFormatSpec(T val, const SpecT &spec = SpecT()) - : SpecT(spec), value_(val) {} - - T value() const { return value_; } -}; - -// A string format specifier. -template -class StrFormatSpec : public AlignSpec { - private: - const Char *str_; - - public: - template - StrFormatSpec(const Char *str, unsigned width, FillChar fill) - : AlignSpec(width, fill), str_(str) { - internal::CharTraits::convert(FillChar()); - } - - const Char *str() const { return str_; } -}; - -/** - Returns an integer format specifier to format the value in base 2. - */ -IntFormatSpec > bin(int value); - -/** - Returns an integer format specifier to format the value in base 8. - */ -IntFormatSpec > oct(int value); - -/** - Returns an integer format specifier to format the value in base 16 using - lower-case letters for the digits above 9. - */ -IntFormatSpec > hex(int value); - -/** - Returns an integer formatter format specifier to format in base 16 using - upper-case letters for the digits above 9. - */ -IntFormatSpec > hexu(int value); - -#define FMT_DEFINE_INT_FORMATTERS(TYPE) \ -inline IntFormatSpec > bin(TYPE value) { \ - return IntFormatSpec >(value, TypeSpec<'b'>()); \ -} \ - \ -inline IntFormatSpec > oct(TYPE value) { \ - return IntFormatSpec >(value, TypeSpec<'o'>()); \ -} \ - \ -inline IntFormatSpec > hex(TYPE value) { \ - return IntFormatSpec >(value, TypeSpec<'x'>()); \ -} \ - \ -inline IntFormatSpec > hexu(TYPE value) { \ - return IntFormatSpec >(value, TypeSpec<'X'>()); \ -} - -FMT_DEFINE_INT_FORMATTERS(int) -FMT_DEFINE_INT_FORMATTERS(long) -FMT_DEFINE_INT_FORMATTERS(unsigned) -FMT_DEFINE_INT_FORMATTERS(unsigned long) -FMT_DEFINE_INT_FORMATTERS(LongLong) -FMT_DEFINE_INT_FORMATTERS(ULongLong) - namespace internal { template @@ -2442,28 +2367,18 @@ class basic_writer { void write(int value) { write_decimal(value); } - void write(unsigned value) { - *this << IntFormatSpec(value); - } void write(long value) { write_decimal(value); } - void write(unsigned long value) { - *this << IntFormatSpec(value); - } void write(LongLong value) { write_decimal(value); } /** \rst - Formats *value* and writes it to the stream. + Formats *value* and writes it to the buffer. \endrst */ - void write(ULongLong value) { - *this << IntFormatSpec(value); - } - template typename std::enable_if::value, void>::type write(T value, FormatSpecs... specs) { @@ -2515,20 +2430,6 @@ class basic_writer { write_str(str, FormatSpec(specs...)); } - template - basic_writer &operator<<(IntFormatSpec spec) { - internal::CharTraits::convert(FillChar()); - write_int(spec.value(), spec); - return *this; - } - - template - basic_writer &operator<<(const StrFormatSpec &spec) { - const StrChar *s = spec.str(); - write_str(s, std::char_traits::length(s), spec); - return *this; - } - void clear() FMT_NOEXCEPT { buffer_.clear(); } Buffer &buffer() FMT_NOEXCEPT { return buffer_; } diff --git a/test/format-test.cc b/test/format-test.cc index 12c9c5b9..656551cb 100644 --- a/test/format-test.cc +++ b/test/format-test.cc @@ -353,52 +353,59 @@ TEST(WriterTest, WriteWideString) { //fmt::WMemoryWriter() << "abc"; } +template +std::string write_str(T... args) { + MemoryWriter writer; + using namespace fmt; + writer.write(args...); + return writer.str(); +} + +template +std::wstring write_wstr(T... args) { + WMemoryWriter writer; + using namespace fmt; + writer.write(args...); + return writer.str(); +} + TEST(WriterTest, bin) { - using fmt::bin; - EXPECT_EQ("1100101011111110", (MemoryWriter() << bin(0xcafe)).str()); - EXPECT_EQ("1011101010111110", (MemoryWriter() << bin(0xbabeu)).str()); - EXPECT_EQ("1101111010101101", (MemoryWriter() << bin(0xdeadl)).str()); - EXPECT_EQ("1011111011101111", (MemoryWriter() << bin(0xbeeful)).str()); + EXPECT_EQ("1100101011111110", write_str(0xcafe, type='b')); + EXPECT_EQ("1011101010111110", write_str(0xbabeu, type='b')); + EXPECT_EQ("1101111010101101", write_str(0xdeadl, type='b')); + EXPECT_EQ("1011111011101111", write_str(0xbeeful, type='b')); EXPECT_EQ("11001010111111101011101010111110", - (MemoryWriter() << bin(0xcafebabell)).str()); + write_str(0xcafebabell, type='b')); EXPECT_EQ("11011110101011011011111011101111", - (MemoryWriter() << bin(0xdeadbeefull)).str()); + write_str(0xdeadbeefull, type='b')); } TEST(WriterTest, oct) { - using fmt::oct; - EXPECT_EQ("12", (MemoryWriter() << oct(static_cast(012))).str()); - EXPECT_EQ("12", (MemoryWriter() << oct(012)).str()); - EXPECT_EQ("34", (MemoryWriter() << oct(034u)).str()); - EXPECT_EQ("56", (MemoryWriter() << oct(056l)).str()); - EXPECT_EQ("70", (MemoryWriter() << oct(070ul)).str()); - EXPECT_EQ("1234", (MemoryWriter() << oct(01234ll)).str()); - EXPECT_EQ("5670", (MemoryWriter() << oct(05670ull)).str()); + EXPECT_EQ("12", write_str(static_cast(012), type='o')); + EXPECT_EQ("12", write_str(012, type='o')); + EXPECT_EQ("34", write_str(034u, type='o')); + EXPECT_EQ("56", write_str(056l, type='o')); + EXPECT_EQ("70", write_str(070ul, type='o')); + EXPECT_EQ("1234", write_str(01234ll, type='o')); + EXPECT_EQ("5670", write_str(05670ull, type='o')); } TEST(WriterTest, hex) { - using fmt::hex; - fmt::IntFormatSpec > (*phex)(int value) = hex; - phex(42); - // This shouldn't compile: - //fmt::IntFormatSpec > (*phex2)(short value) = hex; - - EXPECT_EQ("cafe", (MemoryWriter() << hex(0xcafe)).str()); - EXPECT_EQ("babe", (MemoryWriter() << hex(0xbabeu)).str()); - EXPECT_EQ("dead", (MemoryWriter() << hex(0xdeadl)).str()); - EXPECT_EQ("beef", (MemoryWriter() << hex(0xbeeful)).str()); - EXPECT_EQ("cafebabe", (MemoryWriter() << hex(0xcafebabell)).str()); - EXPECT_EQ("deadbeef", (MemoryWriter() << hex(0xdeadbeefull)).str()); + EXPECT_EQ("cafe", write_str(0xcafe, type='x')); + EXPECT_EQ("babe", write_str(0xbabeu, type='x')); + EXPECT_EQ("dead", write_str(0xdeadl, type='x')); + EXPECT_EQ("beef", write_str(0xbeeful, type='x')); + EXPECT_EQ("cafebabe", write_str(0xcafebabell, type='x')); + EXPECT_EQ("deadbeef", write_str(0xdeadbeefull, type='x')); } TEST(WriterTest, hexu) { - using fmt::hexu; - EXPECT_EQ("CAFE", (MemoryWriter() << hexu(0xcafe)).str()); - EXPECT_EQ("BABE", (MemoryWriter() << hexu(0xbabeu)).str()); - EXPECT_EQ("DEAD", (MemoryWriter() << hexu(0xdeadl)).str()); - EXPECT_EQ("BEEF", (MemoryWriter() << hexu(0xbeeful)).str()); - EXPECT_EQ("CAFEBABE", (MemoryWriter() << hexu(0xcafebabell)).str()); - EXPECT_EQ("DEADBEEF", (MemoryWriter() << hexu(0xdeadbeefull)).str()); + EXPECT_EQ("CAFE", write_str(0xcafe, type='X')); + EXPECT_EQ("BABE", write_str(0xbabeu, type='X')); + EXPECT_EQ("DEAD", write_str(0xdeadl, type='X')); + EXPECT_EQ("BEEF", write_str(0xbeeful, type='X')); + EXPECT_EQ("CAFEBABE", write_str(0xcafebabell, type='X')); + EXPECT_EQ("DEADBEEF", write_str(0xdeadbeefull, type='X')); } template @@ -431,22 +438,6 @@ public: ISO8601DateFormatter iso8601(const Date &d) { return ISO8601DateFormatter(d); } -template -std::string write_str(T... args) { - MemoryWriter writer; - using namespace fmt; - writer.write(args...); - return writer.str(); -} - -template -std::wstring write_wstr(T... args) { - WMemoryWriter writer; - using namespace fmt; - writer.write(args...); - return writer.str(); -} - TEST(WriterTest, pad) { EXPECT_EQ(" cafe", write_str(0xcafe, width=8, type='x')); EXPECT_EQ(" babe", write_str(0xbabeu, width=8, type='x')); @@ -485,13 +476,6 @@ TEST(WriterTest, PadWString) { EXPECT_EQ(L"test******", write_wstr(L"test", width=10, fill=L'*')); } -TEST(WriterTest, NoConflictWithIOManip) { - using namespace std; - using namespace fmt; - EXPECT_EQ("cafe", (MemoryWriter() << hex(0xcafe)).str()); - EXPECT_EQ("12", (MemoryWriter() << oct(012)).str()); -} - TEST(WriterTest, Format) { MemoryWriter w; w.format("part{0}", 1); @@ -507,7 +491,7 @@ TEST(WriterTest, Format) { } TEST(WriterTest, WWriter) { - EXPECT_EQ(L"cafe", (fmt::WMemoryWriter() << fmt::hex(0xcafe)).str()); + EXPECT_EQ(L"cafe", write_wstr(0xcafe, type='x')); } TEST(ArrayWriterTest, Ctor) { From b5fb8dd18b37e48c27c3a9d65a0528993316b042 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sat, 28 Jan 2017 12:44:36 +0000 Subject: [PATCH 079/340] stream -> buffer --- fmt/format.h | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/fmt/format.h b/fmt/format.h index dcf71c13..265c14b2 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -2168,9 +2168,9 @@ constexpr named_format_spec width; /** \rst - This template provides operations for formatting and writing data into - a character stream. The output is stored in a buffer provided by a subclass - such as :class:`fmt::BasicMemoryWriter`. + This template provides operations for formatting and writing data into a + character buffer. The output buffer is specified by a subclass such as + :class:`fmt::BasicMemoryWriter`. You can use one of the following typedefs for common character types: @@ -2265,7 +2265,7 @@ class basic_writer { void write_str(BasicStringRef str, const FormatSpec &spec); // This following methods are private to disallow writing wide characters - // and strings to a char stream. If you want to print a wide string as a + // and strings to a char buffer. If you want to print a wide string as a // pointer as std::ostream does, cast it to const void*. // Do not implement! void operator<<(typename internal::WCharHelper::Unsupported); @@ -2392,7 +2392,7 @@ class basic_writer { /** \rst Formats *value* using the general format for floating-point numbers - (``'g'``) and writes it to the stream. + (``'g'``) and writes it to the buffer. \endrst */ void write(long double value) { @@ -2400,7 +2400,7 @@ class basic_writer { } /** - Writes a character to the stream. + Writes a character to the buffer. */ void write(char value) { buffer_.push_back(value); @@ -2412,7 +2412,7 @@ class basic_writer { /** \rst - Writes *value* to the stream. + Writes *value* to the buffer. \endrst */ void write(fmt::BasicStringRef value) { @@ -2805,8 +2805,7 @@ void basic_writer::write_double(T value, const FormatSpec &spec) { /** \rst This class template provides operations for formatting and writing data - into a character stream. The output is stored in a memory buffer that grows - dynamically. + into a memory buffer that grows dynamically. You can use one of the following typedefs for common character types and the standard allocator: From 296e9cada282fef262e230f29406304297b74ef7 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sat, 28 Jan 2017 12:51:35 +0000 Subject: [PATCH 080/340] FrmatSpec -> format_spec --- fmt/format.h | 34 +++++++++++++++++----------------- fmt/printf.h | 20 ++++++++++---------- test/custom-formatter-test.cc | 4 ++-- test/format-test.cc | 2 +- test/ostream-test.cc | 4 ++-- 5 files changed, 32 insertions(+), 32 deletions(-) diff --git a/fmt/format.h b/fmt/format.h index 265c14b2..d4009910 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -1738,8 +1738,8 @@ struct AlignTypeSpec : AlignSpec { char type() const { return TYPE; } }; -// A full format specifier. -class FormatSpec : public AlignSpec { +// Format specifiers. +class format_specs : public AlignSpec { private: template void set(fill_spec fill) { @@ -1765,11 +1765,11 @@ class FormatSpec : public AlignSpec { int precision_; char type_; - FormatSpec(unsigned width = 0, char type = 0, wchar_t fill = ' ') + format_specs(unsigned width = 0, char type = 0, wchar_t fill = ' ') : AlignSpec(width, fill), flags_(0), precision_(-1), type_(type) {} template - explicit FormatSpec(FormatSpecs... specs) + explicit format_specs(FormatSpecs... specs) : AlignSpec(0, ' '), flags_(0), precision_(-1), type_(0){ set(specs...); } @@ -1855,7 +1855,7 @@ template class ArgFormatterBase { private: basic_writer &writer_; - FormatSpec &spec_; + format_specs &spec_; FMT_DISALLOW_COPY_AND_ASSIGN(ArgFormatterBase); @@ -1883,7 +1883,7 @@ class ArgFormatterBase { protected: basic_writer &writer() { return writer_; } - FormatSpec &spec() { return spec_; } + format_specs &spec() { return spec_; } void write(bool value) { writer_.write_str(StringRef(value ? "true" : "false"), spec_); @@ -1897,7 +1897,7 @@ class ArgFormatterBase { public: typedef Char char_type; - ArgFormatterBase(basic_writer &w, FormatSpec &s) + ArgFormatterBase(basic_writer &w, format_specs &s) : writer_(w), spec_(s) {} void operator()(monostate) { @@ -2045,7 +2045,7 @@ class ArgFormatter : public internal::ArgFormatterBase { \endrst */ ArgFormatter(basic_writer &writer, basic_format_context &ctx, - FormatSpec &spec) + format_specs &spec) : internal::ArgFormatterBase(writer, spec), ctx_(ctx) {} using internal::ArgFormatterBase::operator(); @@ -2255,14 +2255,14 @@ class basic_writer { // Formats a floating-point number (double or long double). template - void write_double(T value, const FormatSpec &spec); + void write_double(T value, const format_specs &spec); // Writes a formatted string. template CharPtr write_str(const StrChar *s, std::size_t size, const AlignSpec &spec); template - void write_str(BasicStringRef str, const FormatSpec &spec); + void write_str(BasicStringRef str, const format_specs &spec); // This following methods are private to disallow writing wide characters // and strings to a char buffer. If you want to print a wide string as a @@ -2382,11 +2382,11 @@ class basic_writer { template typename std::enable_if::value, void>::type write(T value, FormatSpecs... specs) { - write_int(value, FormatSpec(specs...)); + write_int(value, format_specs(specs...)); } void write(double value) { - write_double(value, FormatSpec()); + write_double(value, format_specs()); } /** @@ -2396,7 +2396,7 @@ class basic_writer { \endrst */ void write(long double value) { - write_double(value, FormatSpec()); + write_double(value, format_specs()); } /** @@ -2427,7 +2427,7 @@ class basic_writer { template void write(BasicStringRef str, FormatSpecs... specs) { - write_str(str, FormatSpec(specs...)); + write_str(str, format_specs(specs...)); } void clear() FMT_NOEXCEPT { buffer_.clear(); } @@ -2461,7 +2461,7 @@ typename basic_writer::CharPtr basic_writer::write_str( template template void basic_writer::write_str( - BasicStringRef s, const FormatSpec &spec) { + BasicStringRef s, const format_specs &spec) { // Check if StrChar is convertible to Char. internal::CharTraits::convert(StrChar()); if (spec.type_ && spec.type_ != 's') @@ -2649,7 +2649,7 @@ void basic_writer::write_int(T value, Spec spec) { template template -void basic_writer::write_double(T value, const FormatSpec &spec) { +void basic_writer::write_double(T value, const format_specs &spec) { // Check type. char type = spec.type(); bool upper = false; @@ -3366,7 +3366,7 @@ template void do_format_arg(basic_writer &writer, basic_format_arg arg, Context &ctx) { const Char *&s = ctx.ptr(); - FormatSpec spec; + format_specs spec; if (*s == ':') { if (visit(internal::CustomFormatter(writer, ctx), arg)) return; diff --git a/fmt/printf.h b/fmt/printf.h index 0219ef8e..c2694e43 100644 --- a/fmt/printf.h +++ b/fmt/printf.h @@ -170,12 +170,12 @@ class CharConverter { // left alignment if it is negative. class PrintfWidthHandler { private: - FormatSpec &spec_; + format_specs &spec_; FMT_DISALLOW_COPY_AND_ASSIGN(PrintfWidthHandler); public: - explicit PrintfWidthHandler(FormatSpec &spec) : spec_(spec) {} + explicit PrintfWidthHandler(format_specs &spec) : spec_(spec) {} template typename std::enable_if::value, unsigned>::type @@ -224,14 +224,14 @@ class PrintfArgFormatter : public internal::ArgFormatterBase { specifier information for standard argument types. \endrst */ - PrintfArgFormatter(basic_writer &writer, FormatSpec &spec) + PrintfArgFormatter(basic_writer &writer, format_specs &spec) : internal::ArgFormatterBase(writer, spec) {} using Base::operator(); /** Formats an argument of type ``bool``. */ void operator()(bool value) { - FormatSpec &fmt_spec = this->spec(); + format_specs &fmt_spec = this->spec(); if (fmt_spec.type_ != 's') return (*this)(value ? 1 : 0); fmt_spec.type_ = 0; @@ -240,7 +240,7 @@ class PrintfArgFormatter : public internal::ArgFormatterBase { /** Formats a character. */ void operator()(Char value) { - const FormatSpec &fmt_spec = this->spec(); + const format_specs &fmt_spec = this->spec(); basic_writer &w = this->writer(); if (fmt_spec.type_ && fmt_spec.type_ != 'c') w.write_int(value, fmt_spec); @@ -302,7 +302,7 @@ class printf_context : typedef internal::format_context_base Base; typedef typename Base::format_arg format_arg; - void parse_flags(FormatSpec &spec, const Char *&s); + void parse_flags(format_specs &spec, const Char *&s); // Returns the argument with specified index or, if arg_index is equal // to the maximum unsigned value, the next argument. @@ -311,7 +311,7 @@ class printf_context : unsigned arg_index = (std::numeric_limits::max)()); // Parses argument index, flags and width and returns the argument index. - unsigned parse_header(const Char *&s, FormatSpec &spec); + unsigned parse_header(const Char *&s, format_specs &spec); public: /** @@ -330,7 +330,7 @@ class printf_context : }; template -void printf_context::parse_flags(FormatSpec &spec, const Char *&s) { +void printf_context::parse_flags(format_specs &spec, const Char *&s) { for (;;) { switch (*s++) { case '-': @@ -369,7 +369,7 @@ typename printf_context::format_arg printf_context::get_arg( template unsigned printf_context::parse_header( - const Char *&s, FormatSpec &spec) { + const Char *&s, format_specs &spec) { unsigned arg_index = std::numeric_limits::max(); Char c = *s; if (c >= '0' && c <= '9') { @@ -415,7 +415,7 @@ void printf_context::format(basic_writer &writer) { } internal::write(writer, start, s - 1); - FormatSpec spec; + format_specs spec; spec.align_ = ALIGN_RIGHT; // Parse argument index, flags and width. diff --git a/test/custom-formatter-test.cc b/test/custom-formatter-test.cc index e1ece844..8c646211 100644 --- a/test/custom-formatter-test.cc +++ b/test/custom-formatter-test.cc @@ -17,7 +17,7 @@ using fmt::PrintfArgFormatter; class CustomArgFormatter : public fmt::ArgFormatter { public: CustomArgFormatter(fmt::writer &w, fmt::basic_format_context &ctx, - fmt::FormatSpec &s) + fmt::format_specs &s) : fmt::ArgFormatter(w, ctx, s) {} using fmt::ArgFormatter::operator(); @@ -33,7 +33,7 @@ class CustomArgFormatter : public fmt::ArgFormatter { // rounded to 0. class CustomPrintfArgFormatter : public PrintfArgFormatter { public: - CustomPrintfArgFormatter(fmt::basic_writer &w, fmt::FormatSpec &spec) + CustomPrintfArgFormatter(fmt::basic_writer &w, fmt::format_specs &spec) : PrintfArgFormatter(w, spec) {} using PrintfArgFormatter::operator(); diff --git a/test/format-test.cc b/test/format-test.cc index 656551cb..db9faef0 100644 --- a/test/format-test.cc +++ b/test/format-test.cc @@ -1644,7 +1644,7 @@ class MockArgFormatter : public fmt::internal::ArgFormatterBase { typedef fmt::internal::ArgFormatterBase Base; MockArgFormatter(fmt::writer &w, fmt::format_context &ctx, - fmt::FormatSpec &s) + fmt::format_specs &s) : fmt::internal::ArgFormatterBase(w, s) { EXPECT_CALL(*this, call(42)); } diff --git a/test/ostream-test.cc b/test/ostream-test.cc index b5c46a61..c2498e90 100644 --- a/test/ostream-test.cc +++ b/test/ostream-test.cc @@ -60,14 +60,14 @@ TEST(OStreamTest, Enum) { struct TestArgFormatter : fmt::ArgFormatter { TestArgFormatter(fmt::writer &w, fmt::format_context &ctx, - fmt::FormatSpec &s) + fmt::format_specs &s) : fmt::ArgFormatter(w, ctx, s) {} }; TEST(OStreamTest, CustomArg) { fmt::MemoryWriter writer; fmt::format_context ctx("}", fmt::format_args()); - fmt::FormatSpec spec; + fmt::format_specs spec; TestArgFormatter af(writer, ctx, spec); visit(af, fmt::internal::make_arg(TestEnum())); EXPECT_EQ("TestEnum", writer.str()); From bf0f107564743528215d7ba741ab6e25ac321260 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sat, 28 Jan 2017 13:17:47 +0000 Subject: [PATCH 081/340] Parameterize format_specs on character type --- fmt/format.h | 29 ++++++++++++++++++++++------- fmt/printf.h | 8 +++++++- 2 files changed, 29 insertions(+), 8 deletions(-) diff --git a/fmt/format.h b/fmt/format.h index d4009910..ebf36025 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -1739,10 +1739,13 @@ struct AlignTypeSpec : AlignSpec { }; // Format specifiers. -class format_specs : public AlignSpec { +template +class basic_format_specs : public AlignSpec { private: - template - void set(fill_spec fill) { + template + typename std::enable_if::value || + std::is_same::value, void>::type + set(fill_spec fill) { fill_ = fill.value(); } @@ -1765,11 +1768,11 @@ class format_specs : public AlignSpec { int precision_; char type_; - format_specs(unsigned width = 0, char type = 0, wchar_t fill = ' ') + basic_format_specs(unsigned width = 0, char type = 0, wchar_t fill = ' ') : AlignSpec(width, fill), flags_(0), precision_(-1), type_(type) {} template - explicit format_specs(FormatSpecs... specs) + explicit basic_format_specs(FormatSpecs... specs) : AlignSpec(0, ' '), flags_(0), precision_(-1), type_(0){ set(specs...); } @@ -1779,6 +1782,8 @@ class format_specs : public AlignSpec { char type() const { return type_; } }; +typedef basic_format_specs format_specs; + namespace internal { template @@ -1853,6 +1858,9 @@ void ArgMap::init(const basic_format_args &args) { template class ArgFormatterBase { + public: + typedef basic_format_specs format_specs; + private: basic_writer &writer_; format_specs &spec_; @@ -2035,7 +2043,11 @@ class ArgFormatter : public internal::ArgFormatterBase { private: basic_format_context &ctx_; + typedef internal::ArgFormatterBase Base; + public: + typedef typename Base::format_specs format_specs; + /** \rst Constructs an argument formatter object. @@ -2186,6 +2198,9 @@ constexpr named_format_spec width; */ template class basic_writer { + public: + typedef basic_format_specs format_specs; + private: // Output buffer. Buffer &buffer_; @@ -2461,7 +2476,7 @@ typename basic_writer::CharPtr basic_writer::write_str( template template void basic_writer::write_str( - BasicStringRef s, const format_specs &spec) { + BasicStringRef s, const basic_writer::format_specs &spec) { // Check if StrChar is convertible to Char. internal::CharTraits::convert(StrChar()); if (spec.type_ && spec.type_ != 's') @@ -3366,7 +3381,7 @@ template void do_format_arg(basic_writer &writer, basic_format_arg arg, Context &ctx) { const Char *&s = ctx.ptr(); - format_specs spec; + basic_format_specs spec; if (*s == ':') { if (visit(internal::CustomFormatter(writer, ctx), arg)) return; diff --git a/fmt/printf.h b/fmt/printf.h index c2694e43..3316887a 100644 --- a/fmt/printf.h +++ b/fmt/printf.h @@ -168,8 +168,11 @@ class CharConverter { // Checks if an argument is a valid printf width specifier and sets // left alignment if it is negative. +template class PrintfWidthHandler { private: + typedef basic_format_specs format_specs; + format_specs &spec_; FMT_DISALLOW_COPY_AND_ASSIGN(PrintfWidthHandler); @@ -217,6 +220,8 @@ class PrintfArgFormatter : public internal::ArgFormatterBase { typedef internal::ArgFormatterBase Base; public: + typedef typename Base::format_specs format_specs; + /** \rst Constructs an argument formatter object. @@ -301,6 +306,7 @@ class printf_context : private: typedef internal::format_context_base Base; typedef typename Base::format_arg format_arg; + typedef basic_format_specs format_specs; void parse_flags(format_specs &spec, const Char *&s); @@ -396,7 +402,7 @@ unsigned printf_context::parse_header( spec.width_ = internal::parse_nonnegative_int(s); } else if (*s == '*') { ++s; - spec.width_ = visit(internal::PrintfWidthHandler(spec), get_arg(s)); + spec.width_ = visit(internal::PrintfWidthHandler(spec), get_arg(s)); } return arg_index; } From 7ae8bd7073043568c59524a28611516663a0aaf3 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sun, 5 Feb 2017 06:09:06 -0800 Subject: [PATCH 082/340] basic_format_arg -> basic_arg, Buffer -> buffer --- fmt/format.h | 101 +++++++++++++++++----------------- fmt/ostream.h | 4 +- fmt/printf.h | 20 +++---- fmt/string.h | 2 +- fmt/time.h | 2 +- test/custom-formatter-test.cc | 2 +- test/ostream-test.cc | 2 +- test/util-test.cc | 26 ++++----- 8 files changed, 80 insertions(+), 79 deletions(-) diff --git a/fmt/format.h b/fmt/format.h index ebf36025..93d4e0e8 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -371,7 +371,7 @@ typedef basic_writer writer; typedef basic_writer wwriter; template -class basic_format_arg; +class basic_arg; template class ArgFormatter; @@ -587,16 +587,16 @@ inline T *make_ptr(T *ptr, std::size_t) { return ptr; } \endrst */ template -class Buffer { +class buffer { private: - FMT_DISALLOW_COPY_AND_ASSIGN(Buffer); + FMT_DISALLOW_COPY_AND_ASSIGN(buffer); protected: T *ptr_; std::size_t size_; std::size_t capacity_; - Buffer(T *ptr = 0, std::size_t capacity = 0) + buffer(T *ptr = 0, std::size_t capacity = 0) : ptr_(ptr), size_(0), capacity_(capacity) {} /** @@ -608,7 +608,7 @@ class Buffer { virtual void grow(std::size_t size) = 0; public: - virtual ~Buffer() {} + virtual ~buffer() {} /** Returns the size of this buffer. */ std::size_t size() const { return size_; } @@ -653,7 +653,7 @@ class Buffer { template template -void Buffer::append(const U *begin, const U *end) { +void buffer::append(const U *begin, const U *end) { std::size_t new_size = size_ + internal::to_unsigned(end - begin); if (new_size > capacity_) grow(new_size); @@ -667,7 +667,7 @@ namespace internal { // A memory buffer for trivially copyable/constructible types with the first // SIZE elements stored in the object itself. template > -class MemoryBuffer : private Allocator, public Buffer { +class MemoryBuffer : private Allocator, public buffer { private: T data_[SIZE]; @@ -681,7 +681,7 @@ class MemoryBuffer : private Allocator, public Buffer { public: explicit MemoryBuffer(const Allocator &alloc = Allocator()) - : Allocator(alloc), Buffer(data_, SIZE) {} + : Allocator(alloc), buffer(data_, SIZE) {} ~MemoryBuffer() { deallocate(); } #if FMT_USE_RVALUE_REFERENCES @@ -743,9 +743,10 @@ void MemoryBuffer::grow(std::size_t size) { // A fixed-size buffer. template -class FixedBuffer : public fmt::Buffer { +class FixedBuffer : public fmt::buffer { public: - FixedBuffer(Char *array, std::size_t size) : fmt::Buffer(array, size) {} + FixedBuffer(Char *array, std::size_t size) + : fmt::buffer(array, size) {} protected: FMT_API void grow(std::size_t size); @@ -1322,34 +1323,34 @@ template class ArgMap; template -basic_format_arg make_arg(const T &value); +basic_arg make_arg(const T &value); } // namespace internal struct monostate {}; template -class basic_format_args; +class basic_args; // A formatting argument. It is a trivially copyable/constructible type to // allow storage in internal::MemoryBuffer. template -class basic_format_arg { +class basic_arg { private: internal::value value_; internal::Type type_; template - friend basic_format_arg internal::make_arg(const T &value); + friend basic_arg internal::make_arg(const T &value); template friend typename std::result_of::type - visit(Visitor &&vis, basic_format_arg arg); + visit(Visitor &&vis, basic_arg arg); - friend class basic_format_args; + friend class basic_args; friend class internal::ArgMap; public: - basic_format_arg() : type_(internal::NONE) {} + basic_arg() : type_(internal::NONE) {} explicit operator bool() const noexcept { return type_ != internal::NONE; } @@ -1368,8 +1369,8 @@ class basic_format_arg { } }; -typedef basic_format_arg format_arg; -typedef basic_format_arg wformat_arg; +typedef basic_arg format_arg; +typedef basic_arg wformat_arg; /** \rst @@ -1380,7 +1381,7 @@ typedef basic_format_arg wformat_arg; */ template typename std::result_of::type - visit(Visitor &&vis, basic_format_arg arg) { + visit(Visitor &&vis, basic_arg arg) { typedef typename Context::char_type Char; switch (arg.type_) { case internal::NONE: @@ -1422,8 +1423,8 @@ typename std::result_of::type namespace internal { template -basic_format_arg make_arg(const T &value) { - basic_format_arg arg; +basic_arg make_arg(const T &value) { + basic_arg arg; arg.type_ = internal::type(); arg.value_ = value; return arg; @@ -1474,14 +1475,14 @@ void format_value(basic_writer &, const T &, Formatter &, const Char *) { } template -struct NamedArg : basic_format_arg { +struct NamedArg : basic_arg { typedef typename Context::char_type Char; BasicStringRef name; template NamedArg(BasicStringRef argname, const T &value) - : basic_format_arg(make_arg(value)), name(argname) {} + : basic_arg(make_arg(value)), name(argname) {} }; class RuntimeError : public std::runtime_error { @@ -1508,7 +1509,7 @@ inline typename std::enable_if>::type } template -inline typename std::enable_if>::type +inline typename std::enable_if>::type make_arg(const T& value) { return make_arg(value); } @@ -1525,7 +1526,7 @@ class format_arg_store { typedef typename Context::char_type char_type; typedef typename std::conditional, basic_format_arg>::type value_type; + internal::value, basic_arg>::type value_type; // If the arguments are not packed, add one more element to mark the end. typedef std::array Array; @@ -1554,10 +1555,10 @@ inline format_arg_store /** Formatting arguments. */ template -class basic_format_args { +class basic_args { public: typedef unsigned size_type; - typedef basic_format_arg format_arg; + typedef basic_arg format_arg; private: // To reduce compiled code size per formatting function call, types of first @@ -1610,10 +1611,10 @@ class basic_format_args { } public: - basic_format_args() : types_(0) {} + basic_args() : types_(0) {} template - basic_format_args(const format_arg_store &store) + basic_args(const format_arg_store &store) : types_(store.TYPES) { set_data(store.data()); } @@ -1626,8 +1627,8 @@ class basic_format_args { } }; -typedef basic_format_args format_args; -typedef basic_format_args wformat_args; +typedef basic_args format_args; +typedef basic_args wformat_args; enum Alignment { ALIGN_DEFAULT, ALIGN_LEFT, ALIGN_RIGHT, ALIGN_CENTER, ALIGN_NUMERIC @@ -1791,15 +1792,15 @@ class ArgMap { private: typedef typename Context::char_type Char; typedef std::vector< - std::pair, basic_format_arg > > MapType; + std::pair, basic_arg > > MapType; typedef typename MapType::value_type Pair; MapType map_; public: - void init(const basic_format_args &args); + void init(const basic_args &args); - const basic_format_arg + const basic_arg *find(const fmt::BasicStringRef &name) const { // The list is unsorted, so just return the first matching name. for (typename MapType::const_iterator it = map_.begin(), end = map_.end(); @@ -1812,7 +1813,7 @@ class ArgMap { }; template -void ArgMap::init(const basic_format_args &args) { +void ArgMap::init(const basic_args &args) { if (!map_.empty()) return; typedef internal::NamedArg NamedArg; @@ -1987,17 +1988,17 @@ template class format_context_base { private: const Char *ptr_; - basic_format_args args_; + basic_args args_; int next_arg_index_; protected: - typedef basic_format_arg format_arg; + typedef basic_arg format_arg; - format_context_base(const Char *format_str, basic_format_args args) + format_context_base(const Char *format_str, basic_args args) : ptr_(format_str), args_(args), next_arg_index_(0) {} ~format_context_base() {} - basic_format_args args() const { return args_; } + basic_args args() const { return args_; } // Returns the argument with specified index. format_arg do_get_arg(unsigned arg_index, const char *&error) { @@ -2097,7 +2098,7 @@ class basic_format_context : \endrst */ basic_format_context(const Char *format_str, - basic_format_args args) + basic_args args) : Base(format_str, args) {} // Parses argument id and returns corresponding argument. @@ -2203,7 +2204,7 @@ class basic_writer { private: // Output buffer. - Buffer &buffer_; + buffer &buffer_; FMT_DISALLOW_COPY_AND_ASSIGN(basic_writer); @@ -2306,7 +2307,7 @@ class basic_writer { /** Constructs a ``basic_writer`` object. */ - explicit basic_writer(Buffer &b) : buffer_(b) {} + explicit basic_writer(buffer &b) : buffer_(b) {} public: /** @@ -2348,7 +2349,7 @@ class basic_writer { } void vformat(BasicCStringRef format, - basic_format_args> args); + basic_args> args); /** \rst Writes formatted data. @@ -2447,7 +2448,7 @@ class basic_writer { void clear() FMT_NOEXCEPT { buffer_.clear(); } - Buffer &buffer() FMT_NOEXCEPT { return buffer_; } + buffer &buffer() FMT_NOEXCEPT { return buffer_; } }; template @@ -3242,7 +3243,7 @@ unsigned parse_nonnegative_int(const Char *&s) { template inline void require_numeric_argument( - const basic_format_arg &arg, char spec) { + const basic_arg &arg, char spec) { if (!arg.is_numeric()) { FMT_THROW(fmt::format_error( fmt::format("format specifier '{}' requires numeric argument", spec))); @@ -3264,7 +3265,7 @@ struct IsUnsigned { }; template -void check_sign(const Char *&s, const basic_format_arg &arg) { +void check_sign(const Char *&s, const basic_arg &arg) { char sign = static_cast(*s); require_numeric_argument(arg, sign); if (visit(IsUnsigned(), arg)) { @@ -3378,7 +3379,7 @@ inline typename basic_format_context::format_arg // Formats a single argument. template -void do_format_arg(basic_writer &writer, basic_format_arg arg, +void do_format_arg(basic_writer &writer, basic_arg arg, Context &ctx) { const Char *&s = ctx.ptr(); basic_format_specs spec; @@ -3505,7 +3506,7 @@ void do_format_arg(basic_writer &writer, basic_format_arg arg, /** Formats arguments and writes the output to the writer. */ template void vwrite(basic_writer &writer, BasicCStringRef format_str, - basic_format_args args) { + basic_args args) { basic_format_context ctx(format_str.c_str(), args); const Char *&s = ctx.ptr(); const Char *start = s; @@ -3531,7 +3532,7 @@ void vwrite(basic_writer &writer, BasicCStringRef format_str, template inline void basic_writer::vformat( BasicCStringRef format, - basic_format_args> args) { + basic_args> args) { vwrite>(*this, format, args); } } // namespace fmt diff --git a/fmt/ostream.h b/fmt/ostream.h index bae83100..c6eb17a5 100644 --- a/fmt/ostream.h +++ b/fmt/ostream.h @@ -23,11 +23,11 @@ class FormatBuf : public std::basic_streambuf { typedef typename std::basic_streambuf::int_type int_type; typedef typename std::basic_streambuf::traits_type traits_type; - Buffer &buffer_; + buffer &buffer_; Char *start_; public: - FormatBuf(Buffer &buffer) : buffer_(buffer), start_(&buffer[0]) { + FormatBuf(buffer &buffer) : buffer_(buffer), start_(&buffer[0]) { this->setp(start_, start_ + buffer_.capacity()); } diff --git a/fmt/printf.h b/fmt/printf.h index 3316887a..09ed7762 100644 --- a/fmt/printf.h +++ b/fmt/printf.h @@ -85,11 +85,11 @@ class ArgConverter { private: typedef typename Context::char_type Char; - basic_format_arg &arg_; + basic_arg &arg_; typename Context::char_type type_; public: - ArgConverter(basic_format_arg &arg, Char type) + ArgConverter(basic_arg &arg, Char type) : arg_(arg), type_(type) {} void operator()(bool value) { @@ -139,7 +139,7 @@ class ArgConverter { // type depending on the type specifier: 'd' and 'i' - signed, other - // unsigned). template -void convert_arg(basic_format_arg &arg, Char type) { +void convert_arg(basic_arg &arg, Char type) { visit(ArgConverter(arg, type), arg); } @@ -147,12 +147,12 @@ void convert_arg(basic_format_arg &arg, Char type) { template class CharConverter { private: - basic_format_arg &arg_; + basic_arg &arg_; FMT_DISALLOW_COPY_AND_ASSIGN(CharConverter); public: - explicit CharConverter(basic_format_arg &arg) : arg_(arg) {} + explicit CharConverter(basic_arg &arg) : arg_(arg) {} template typename std::enable_if::value>::type @@ -287,7 +287,7 @@ class PrintfArgFormatter : public internal::ArgFormatterBase { /** Formats an argument of a custom (user-defined) type. */ void operator()(internal::CustomValue c) { const Char format_str[] = {'}', '\0'}; - auto args = basic_format_args>(); + auto args = basic_args>(); basic_format_context ctx(format_str, args); c.format(this->writer(), c.value, &ctx); } @@ -328,7 +328,7 @@ class printf_context : \endrst */ explicit printf_context(BasicCStringRef format_str, - basic_format_args args) + basic_args args) : Base(format_str.c_str(), args) {} /** Formats stored arguments and writes the output to the writer. */ @@ -516,11 +516,11 @@ void format_value(basic_writer &w, const T &value, template void printf(basic_writer &w, BasicCStringRef format, - basic_format_args> args) { + basic_args> args) { printf_context(format, args).format(w); } -typedef basic_format_args> printf_args; +typedef basic_args> printf_args; inline std::string vsprintf(CStringRef format, printf_args args) { MemoryWriter w; @@ -543,7 +543,7 @@ inline std::string sprintf(CStringRef format_str, const Args & ... args) { } inline std::wstring vsprintf( - WCStringRef format, basic_format_args> args) { + WCStringRef format, basic_args> args) { WMemoryWriter w; printf(w, format, args); return w.str(); diff --git a/fmt/string.h b/fmt/string.h index 0de41b98..acb399b6 100644 --- a/fmt/string.h +++ b/fmt/string.h @@ -18,7 +18,7 @@ namespace internal { // A buffer that stores data in ``std::string``. template -class StringBuffer : public Buffer { +class StringBuffer : public buffer { private: std::basic_string data_; diff --git a/fmt/time.h b/fmt/time.h index 6b970bcb..f021a892 100644 --- a/fmt/time.h +++ b/fmt/time.h @@ -27,7 +27,7 @@ void format_value(writer &w, const std::tm &tm, format_context &ctx) { internal::MemoryBuffer format; format.append(s, end + 1); format[format.size() - 1] = '\0'; - Buffer &buffer = w.buffer(); + buffer &buffer = w.buffer(); std::size_t start = buffer.size(); for (;;) { std::size_t size = buffer.capacity() - start; diff --git a/test/custom-formatter-test.cc b/test/custom-formatter-test.cc index 8c646211..95117c7c 100644 --- a/test/custom-formatter-test.cc +++ b/test/custom-formatter-test.cc @@ -63,7 +63,7 @@ typedef fmt::printf_context std::string custom_vsprintf( const char* format_str, - fmt::basic_format_args args) { + fmt::basic_args args) { fmt::MemoryWriter writer; CustomPrintfFormatter formatter(format_str, args); formatter.format(writer); diff --git a/test/ostream-test.cc b/test/ostream-test.cc index c2498e90..73c8c053 100644 --- a/test/ostream-test.cc +++ b/test/ostream-test.cc @@ -136,7 +136,7 @@ TEST(OStreamTest, WriteToOStreamMaxSize) { class TestWriter : public fmt::basic_writer { private: - struct TestBuffer : fmt::Buffer { + struct TestBuffer : fmt::buffer { explicit TestBuffer(std::size_t size) { size_ = size; } void grow(std::size_t) {} } buffer_; diff --git a/test/util-test.cc b/test/util-test.cc index 88bad995..7f931f78 100644 --- a/test/util-test.cc +++ b/test/util-test.cc @@ -52,9 +52,9 @@ #undef min #undef max -using fmt::basic_format_arg; +using fmt::basic_arg; using fmt::format_arg; -using fmt::Buffer; +using fmt::buffer; using fmt::StringRef; using fmt::internal::MemoryBuffer; using fmt::internal::value; @@ -74,7 +74,7 @@ void format_value(fmt::basic_writer &w, Test, } template -basic_format_arg make_arg(const T &value) { +basic_arg make_arg(const T &value) { return fmt::internal::make_arg(value); } } // namespace @@ -107,24 +107,24 @@ TEST(AllocatorTest, AllocatorRef) { #if FMT_USE_TYPE_TRAITS TEST(BufferTest, Noncopyable) { - EXPECT_FALSE(std::is_copy_constructible >::value); - EXPECT_FALSE(std::is_copy_assignable >::value); + EXPECT_FALSE(std::is_copy_constructible >::value); + EXPECT_FALSE(std::is_copy_assignable >::value); } TEST(BufferTest, Nonmoveable) { - EXPECT_FALSE(std::is_move_constructible >::value); - EXPECT_FALSE(std::is_move_assignable >::value); + EXPECT_FALSE(std::is_move_constructible >::value); + EXPECT_FALSE(std::is_move_assignable >::value); } #endif // A test buffer with a dummy grow method. template -struct TestBuffer : Buffer { +struct TestBuffer : buffer { void grow(std::size_t size) { this->capacity_ = size; } }; template -struct MockBuffer : Buffer { +struct MockBuffer : buffer { MOCK_METHOD1(do_grow, void (std::size_t size)); void grow(std::size_t size) { @@ -133,8 +133,8 @@ struct MockBuffer : Buffer { } MockBuffer() {} - MockBuffer(T *ptr) : Buffer(ptr) {} - MockBuffer(T *ptr, std::size_t capacity) : Buffer(ptr, capacity) {} + MockBuffer(T *ptr) : buffer(ptr) {} + MockBuffer(T *ptr, std::size_t capacity) : buffer(ptr, capacity) {} }; TEST(BufferTest, Ctor) { @@ -170,7 +170,7 @@ TEST(BufferTest, VirtualDtor) { typedef StrictMock StictMockBuffer; StictMockBuffer *mock_buffer = new StictMockBuffer(); EXPECT_CALL(*mock_buffer, die()); - Buffer *buffer = mock_buffer; + buffer *buffer = mock_buffer; delete buffer; } @@ -181,7 +181,7 @@ TEST(BufferTest, Access) { EXPECT_EQ(11, buffer[0]); buffer[3] = 42; EXPECT_EQ(42, *(&buffer[0] + 3)); - const Buffer &const_buffer = buffer; + const fmt::buffer &const_buffer = buffer; EXPECT_EQ(42, const_buffer[3]); } From 624c58682d93a969f6372ea37efec7a3ca53d655 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sun, 5 Feb 2017 06:41:39 -0800 Subject: [PATCH 083/340] Simplify API --- fmt/format.cc | 6 +-- fmt/format.h | 96 +++++++++++++++++------------------ fmt/ostream.h | 6 +-- fmt/posix.h | 2 +- fmt/printf.h | 20 ++++---- fmt/time.h | 2 +- test/custom-formatter-test.cc | 6 +-- test/format-impl-test.cc | 4 +- test/format-test.cc | 10 ++-- test/ostream-test.cc | 7 ++- test/util-test.cc | 8 +-- 11 files changed, 82 insertions(+), 85 deletions(-) diff --git a/fmt/format.cc b/fmt/format.cc index eed7f915..3dd42e1a 100644 --- a/fmt/format.cc +++ b/fmt/format.cc @@ -465,7 +465,7 @@ template struct internal::BasicData; template void internal::FixedBuffer::grow(std::size_t); -template void internal::ArgMap::init(const format_args &args); +template void internal::ArgMap::init(const format_args &args); template void printf_context::format(writer &writer); @@ -479,11 +479,11 @@ template int internal::CharTraits::format_float( // Explicit instantiations for wchar_t. -template class basic_format_context; +template class basic_context; template void internal::FixedBuffer::grow(std::size_t); -template void internal::ArgMap::init(const wformat_args &args); +template void internal::ArgMap::init(const wformat_args &args); template void printf_context::format(wwriter &writer); diff --git a/fmt/format.h b/fmt/format.h index 93d4e0e8..742904f2 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -380,10 +380,10 @@ template class PrintfArgFormatter; template -class basic_format_context; +class basic_context; -typedef basic_format_context format_context; -typedef basic_format_context wformat_context; +typedef basic_context context; +typedef basic_context wcontext; /** \rst @@ -1369,8 +1369,8 @@ class basic_arg { } }; -typedef basic_arg format_arg; -typedef basic_arg wformat_arg; +typedef basic_arg format_arg; +typedef basic_arg wformat_arg; /** \rst @@ -1516,7 +1516,7 @@ inline typename std::enable_if>::type } // namespace internal template -class format_arg_store { +class arg_store { private: static const size_t NUM_ARGS = sizeof...(Args); @@ -1535,22 +1535,20 @@ class format_arg_store { public: static const uint64_t TYPES = internal::make_type(); - format_arg_store(const Args &... args) + arg_store(const Args &... args) : data_(Array{{internal::make_arg(args)...}}) {} const value_type *data() const { return data_.data(); } }; template -inline format_arg_store - make_xformat_args(const Args & ... args) { - return format_arg_store(args...); +inline arg_store make_args(const Args & ... args) { + return arg_store(args...); } template -inline format_arg_store - make_format_args(const Args & ... args) { - return format_arg_store(args...); +inline arg_store make_args(const Args & ... args) { + return arg_store(args...); } /** Formatting arguments. */ @@ -1614,7 +1612,7 @@ class basic_args { basic_args() : types_(0) {} template - basic_args(const format_arg_store &store) + basic_args(const arg_store &store) : types_(store.TYPES) { set_data(store.data()); } @@ -1627,8 +1625,8 @@ class basic_args { } }; -typedef basic_args format_args; -typedef basic_args wformat_args; +typedef basic_args format_args; +typedef basic_args wformat_args; enum Alignment { ALIGN_DEFAULT, ALIGN_LEFT, ALIGN_RIGHT, ALIGN_CENTER, ALIGN_NUMERIC @@ -1985,7 +1983,7 @@ inline void write(basic_writer &w, const Char *start, const Char *end) { } template -class format_context_base { +class context_base { private: const Char *ptr_; basic_args args_; @@ -1994,9 +1992,9 @@ class format_context_base { protected: typedef basic_arg format_arg; - format_context_base(const Char *format_str, basic_args args) + context_base(const Char *format_str, basic_args args) : ptr_(format_str), args_(args), next_arg_index_(0) {} - ~format_context_base() {} + ~context_base() {} basic_args args() const { return args_; } @@ -2042,7 +2040,7 @@ class format_context_base { template class ArgFormatter : public internal::ArgFormatterBase { private: - basic_format_context &ctx_; + basic_context &ctx_; typedef internal::ArgFormatterBase Base; @@ -2057,7 +2055,7 @@ class ArgFormatter : public internal::ArgFormatterBase { format specifier information for standard argument types. \endrst */ - ArgFormatter(basic_writer &writer, basic_format_context &ctx, + ArgFormatter(basic_writer &writer, basic_context &ctx, format_specs &spec) : internal::ArgFormatterBase(writer, spec), ctx_(ctx) {} @@ -2070,18 +2068,18 @@ class ArgFormatter : public internal::ArgFormatterBase { }; template -class basic_format_context : - public internal::format_context_base> { +class basic_context : + public internal::context_base> { public: /** The character type for the output. */ typedef Char char_type; private: - internal::ArgMap> map_; + internal::ArgMap> map_; - FMT_DISALLOW_COPY_AND_ASSIGN(basic_format_context); + FMT_DISALLOW_COPY_AND_ASSIGN(basic_context); - typedef internal::format_context_base> Base; + typedef internal::context_base> Base; typedef typename Base::format_arg format_arg; using Base::get_arg; @@ -2093,12 +2091,12 @@ class basic_format_context : public: /** \rst - Constructs a ``basic_format_context`` object. References to the arguments are + Constructs a ``basic_context`` object. References to the arguments are stored in the object so make sure they have appropriate lifetimes. \endrst */ - basic_format_context(const Char *format_str, - basic_args args) + basic_context(const Char *format_str, + basic_args args) : Base(format_str, args) {} // Parses argument id and returns corresponding argument. @@ -2141,7 +2139,7 @@ class SystemError : public internal::RuntimeError { */ template SystemError(int error_code, CStringRef message, const Args & ... args) { - init(error_code, message, make_format_args(args...)); + init(error_code, message, make_args(args...)); } ~SystemError() throw(); @@ -2349,7 +2347,7 @@ class basic_writer { } void vformat(BasicCStringRef format, - basic_args> args); + basic_args> args); /** \rst Writes formatted data. @@ -2377,7 +2375,7 @@ class basic_writer { */ template void format(BasicCStringRef format, const Args & ... args) { - vformat(format, make_xformat_args>(args...)); + vformat(format, make_args>(args...)); } void write(int value) { @@ -2978,7 +2976,7 @@ class WindowsError : public SystemError { */ template WindowsError(int error_code, CStringRef message, const Args & ... args) { - init(error_code, message, make_format_args(args...)); + init(error_code, message, make_args(args...)); } }; @@ -3002,7 +3000,7 @@ FMT_API void vprint_colored(Color c, CStringRef format, format_args args); template inline void print_colored(Color c, CStringRef format_str, const Args & ... args) { - vprint_colored(c, format_str, make_format_args(args...)); + vprint_colored(c, format_str, make_args(args...)); } inline std::string vformat(CStringRef format_str, format_args args) { @@ -3022,7 +3020,7 @@ inline std::string vformat(CStringRef format_str, format_args args) { */ template inline std::string format(CStringRef format_str, const Args & ... args) { - return vformat(format_str, make_format_args(args...)); + return vformat(format_str, make_args(args...)); } inline std::wstring vformat(WCStringRef format_str, wformat_args args) { @@ -3033,7 +3031,7 @@ inline std::wstring vformat(WCStringRef format_str, wformat_args args) { template inline std::wstring format(WCStringRef format_str, const Args & ... args) { - auto vargs = make_xformat_args(args...); + auto vargs = make_args(args...); return vformat(format_str, vargs); } @@ -3050,7 +3048,7 @@ FMT_API void vprint(std::FILE *f, CStringRef format_str, format_args args); */ template inline void print(std::FILE *f, CStringRef format_str, const Args & ... args) { - vprint(f, format_str, make_format_args(args...)); + vprint(f, format_str, make_args(args...)); } FMT_API void vprint(CStringRef format_str, format_args args); @@ -3066,7 +3064,7 @@ FMT_API void vprint(CStringRef format_str, format_args args); */ template inline void print(CStringRef format_str, const Args & ... args) { - vprint(format_str, make_format_args(args...)); + vprint(format_str, make_args(args...)); } /** @@ -3185,13 +3183,13 @@ inline void format_decimal(char *&buffer, T value) { \endrst */ template -inline internal::NamedArg arg(StringRef name, const T &arg) { - return internal::NamedArg(name, arg); +inline internal::NamedArg arg(StringRef name, const T &arg) { + return internal::NamedArg(name, arg); } template -inline internal::NamedArg arg(WStringRef name, const T &arg) { - return internal::NamedArg(name, arg); +inline internal::NamedArg arg(WStringRef name, const T &arg) { + return internal::NamedArg(name, arg); } // The following two functions are deleted intentionally to disable @@ -3338,8 +3336,8 @@ struct PrecisionHandler { } // namespace internal template -inline typename basic_format_context::format_arg - basic_format_context::get_arg( +inline typename basic_context::format_arg + basic_context::get_arg( BasicStringRef name, const char *&error) { if (this->check_no_auto_index(error)) { map_.init(this->args()); @@ -3351,8 +3349,8 @@ inline typename basic_format_context::format_arg } template -inline typename basic_format_context::format_arg - basic_format_context::parse_arg_id() { +inline typename basic_context::format_arg + basic_context::parse_arg_id() { const Char *&s = this->ptr(); if (!internal::is_name_start(*s)) { const char *error = 0; @@ -3507,7 +3505,7 @@ void do_format_arg(basic_writer &writer, basic_arg arg, template void vwrite(basic_writer &writer, BasicCStringRef format_str, basic_args args) { - basic_format_context ctx(format_str.c_str(), args); + basic_context ctx(format_str.c_str(), args); const Char *&s = ctx.ptr(); const Char *start = s; while (*s) { @@ -3532,7 +3530,7 @@ void vwrite(basic_writer &writer, BasicCStringRef format_str, template inline void basic_writer::vformat( BasicCStringRef format, - basic_args> args) { + basic_args> args) { vwrite>(*this, format, args); } } // namespace fmt @@ -3557,7 +3555,7 @@ struct UdlArg { const Char *str; template - NamedArg> operator=(T &&value) const { + NamedArg> operator=(T &&value) const { return {str, std::forward(value)}; } }; diff --git a/fmt/ostream.h b/fmt/ostream.h index c6eb17a5..040a185b 100644 --- a/fmt/ostream.h +++ b/fmt/ostream.h @@ -84,11 +84,11 @@ BasicStringRef format_value( // Formats a value. template void format_value(basic_writer &w, const T &value, - basic_format_context &ctx) { + basic_context &ctx) { internal::MemoryBuffer buffer; auto str = internal::format_value(buffer, value); do_format_arg< ArgFormatter >( - w, internal::make_arg< basic_format_context >(str), ctx); + w, internal::make_arg< basic_context >(str), ctx); } FMT_API void vprint(std::ostream &os, CStringRef format_str, format_args args); @@ -105,7 +105,7 @@ FMT_API void vprint(std::ostream &os, CStringRef format_str, format_args args); template inline void print(std::ostream &os, CStringRef format_str, const Args & ... args) { - vprint(os, format_str, make_format_args(args...)); + vprint(os, format_str, make_args(args...)); } } // namespace fmt diff --git a/fmt/posix.h b/fmt/posix.h index 4758a85b..19e80024 100644 --- a/fmt/posix.h +++ b/fmt/posix.h @@ -172,7 +172,7 @@ public: template inline void print(CStringRef format_str, const Args & ... args) { - vprint(format_str, make_format_args(args...)); + vprint(format_str, make_args(args...)); } }; diff --git a/fmt/printf.h b/fmt/printf.h index 09ed7762..2fa54d2f 100644 --- a/fmt/printf.h +++ b/fmt/printf.h @@ -103,7 +103,7 @@ class ArgConverter { bool is_signed = type_ == 'd' || type_ == 'i'; typedef typename internal::Conditional< is_same::value, U, T>::type TargetType; - typedef basic_format_context format_context; + typedef basic_context context; if (sizeof(TargetType) <= sizeof(int)) { // Extra casts are used to silence warnings. if (is_signed) { @@ -287,8 +287,8 @@ class PrintfArgFormatter : public internal::ArgFormatterBase { /** Formats an argument of a custom (user-defined) type. */ void operator()(internal::CustomValue c) { const Char format_str[] = {'}', '\0'}; - auto args = basic_args>(); - basic_format_context ctx(format_str, args); + auto args = basic_args>(); + basic_context ctx(format_str, args); c.format(this->writer(), c.value, &ctx); } }; @@ -297,14 +297,14 @@ class PrintfArgFormatter : public internal::ArgFormatterBase { template > class printf_context : - private internal::format_context_base< + private internal::context_base< Char, printf_context> { public: /** The character type for the output. */ typedef Char char_type; private: - typedef internal::format_context_base Base; + typedef internal::context_base Base; typedef typename Base::format_arg format_arg; typedef basic_format_specs format_specs; @@ -539,7 +539,7 @@ inline std::string vsprintf(CStringRef format, printf_args args) { */ template inline std::string sprintf(CStringRef format_str, const Args & ... args) { - return vsprintf(format_str, make_xformat_args>(args...)); + return vsprintf(format_str, make_args>(args...)); } inline std::wstring vsprintf( @@ -551,7 +551,7 @@ inline std::wstring vsprintf( template inline std::wstring sprintf(WCStringRef format_str, const Args & ... args) { - auto vargs = make_xformat_args>(args...); + auto vargs = make_args>(args...); return vsprintf(format_str, vargs); } @@ -568,7 +568,7 @@ FMT_API int vfprintf(std::FILE *f, CStringRef format, printf_args args); */ template inline int fprintf(std::FILE *f, CStringRef format_str, const Args & ... args) { - auto vargs = make_xformat_args>(args...); + auto vargs = make_args>(args...); return vfprintf(f, format_str, vargs); } @@ -587,7 +587,7 @@ inline int vprintf(CStringRef format, printf_args args) { */ template inline int printf(CStringRef format_str, const Args & ... args) { - return vprintf(format_str, make_xformat_args>(args...)); + return vprintf(format_str, make_args>(args...)); } inline int vfprintf(std::ostream &os, CStringRef format_str, printf_args args) { @@ -609,7 +609,7 @@ inline int vfprintf(std::ostream &os, CStringRef format_str, printf_args args) { template inline int fprintf(std::ostream &os, CStringRef format_str, const Args & ... args) { - auto vargs = make_xformat_args>(args...); + auto vargs = make_args>(args...); return vfprintf(os, format_str, vargs); } } // namespace fmt diff --git a/fmt/time.h b/fmt/time.h index f021a892..4f07fd00 100644 --- a/fmt/time.h +++ b/fmt/time.h @@ -15,7 +15,7 @@ namespace fmt { -void format_value(writer &w, const std::tm &tm, format_context &ctx) { +void format_value(writer &w, const std::tm &tm, context &ctx) { const char *&s = ctx.ptr(); if (*s == ':') ++s; diff --git a/test/custom-formatter-test.cc b/test/custom-formatter-test.cc index 95117c7c..526a9258 100644 --- a/test/custom-formatter-test.cc +++ b/test/custom-formatter-test.cc @@ -16,7 +16,7 @@ using fmt::PrintfArgFormatter; // rounded to 0. class CustomArgFormatter : public fmt::ArgFormatter { public: - CustomArgFormatter(fmt::writer &w, fmt::basic_format_context &ctx, + CustomArgFormatter(fmt::writer &w, fmt::basic_context &ctx, fmt::format_specs &s) : fmt::ArgFormatter(w, ctx, s) {} @@ -54,7 +54,7 @@ std::string custom_vformat(fmt::CStringRef format_str, fmt::format_args args) { template std::string custom_format(const char *format_str, const Args & ... args) { - auto va = fmt::make_format_args(args...); + auto va = fmt::make_args(args...); return custom_vformat(format_str, va); } @@ -72,7 +72,7 @@ std::string custom_vsprintf( template std::string custom_sprintf(const char *format_str, const Args & ... args) { - auto va = fmt::make_xformat_args(args...); + auto va = fmt::make_args(args...); return custom_vsprintf(format_str, va); } diff --git a/test/format-impl-test.cc b/test/format-impl-test.cc index 0c7c2ea8..c19329f7 100644 --- a/test/format-impl-test.cc +++ b/test/format-impl-test.cc @@ -57,9 +57,9 @@ struct ValueExtractor { TEST(FormatTest, ArgConverter) { using fmt::format_arg; fmt::LongLong value = std::numeric_limits::max(); - format_arg arg = fmt::internal::make_arg(value); + format_arg arg = fmt::internal::make_arg(value); visit(fmt::internal::ArgConverter< - fmt::LongLong, fmt::format_context>(arg, 'd'), arg); + fmt::LongLong, fmt::context>(arg, 'd'), arg); EXPECT_EQ(value, visit(ValueExtractor(), arg)); } diff --git a/test/format-test.cc b/test/format-test.cc index db9faef0..35a9e476 100644 --- a/test/format-test.cc +++ b/test/format-test.cc @@ -1366,7 +1366,7 @@ TEST(FormatterTest, FormatCStringRef) { EXPECT_EQ("test", format("{0}", CStringRef("test"))); } -void format_value(fmt::writer &w, const Date &d, fmt::format_context &) { +void format_value(fmt::writer &w, const Date &d, fmt::context &) { w.write(d.year()); w.write('-'); w.write(d.month()); @@ -1383,7 +1383,7 @@ TEST(FormatterTest, FormatCustom) { class Answer {}; template -void format_value(basic_writer &w, Answer, fmt::format_context &) { +void format_value(basic_writer &w, Answer, fmt::context &) { w.write("42"); } @@ -1575,7 +1575,7 @@ std::string vformat_message(int id, const char *format, fmt::format_args args) { template std::string format_message(int id, const char *format, const Args & ... args) { - auto va = fmt::make_format_args(args...); + auto va = fmt::make_args(args...); return vformat_message(id, format, va); } @@ -1643,7 +1643,7 @@ class MockArgFormatter : public fmt::internal::ArgFormatterBase { public: typedef fmt::internal::ArgFormatterBase Base; - MockArgFormatter(fmt::writer &w, fmt::format_context &ctx, + MockArgFormatter(fmt::writer &w, fmt::context &ctx, fmt::format_specs &s) : fmt::internal::ArgFormatterBase(w, s) { EXPECT_CALL(*this, call(42)); @@ -1663,7 +1663,7 @@ void custom_vformat(fmt::CStringRef format_str, fmt::format_args args) { template void custom_format(const char *format_str, const Args & ... args) { - auto va = fmt::make_format_args(args...); + auto va = fmt::make_args(args...); return custom_vformat(format_str, va); } diff --git a/test/ostream-test.cc b/test/ostream-test.cc index 73c8c053..af279b8f 100644 --- a/test/ostream-test.cc +++ b/test/ostream-test.cc @@ -59,17 +59,16 @@ TEST(OStreamTest, Enum) { } struct TestArgFormatter : fmt::ArgFormatter { - TestArgFormatter(fmt::writer &w, fmt::format_context &ctx, - fmt::format_specs &s) + TestArgFormatter(fmt::writer &w, fmt::context &ctx, fmt::format_specs &s) : fmt::ArgFormatter(w, ctx, s) {} }; TEST(OStreamTest, CustomArg) { fmt::MemoryWriter writer; - fmt::format_context ctx("}", fmt::format_args()); + fmt::context ctx("}", fmt::format_args()); fmt::format_specs spec; TestArgFormatter af(writer, ctx, spec); - visit(af, fmt::internal::make_arg(TestEnum())); + visit(af, fmt::internal::make_arg(TestEnum())); EXPECT_EQ("TestEnum", writer.str()); } diff --git a/test/util-test.cc b/test/util-test.cc index 7f931f78..e84415d8 100644 --- a/test/util-test.cc +++ b/test/util-test.cc @@ -69,7 +69,7 @@ struct Test {}; template void format_value(fmt::basic_writer &w, Test, - fmt::basic_format_context &) { + fmt::basic_context &) { w.write("test"); } @@ -487,7 +487,7 @@ VISIT_TYPE(float, double); #define CHECK_ARG_(Char, expected, value) { \ testing::StrictMock> visitor; \ EXPECT_CALL(visitor, visit(expected)); \ - fmt::visit(visitor, make_arg>(value)); \ + fmt::visit(visitor, make_arg>(value)); \ } #define CHECK_ARG(value) { \ @@ -570,12 +570,12 @@ TEST(UtilTest, CustomArg) { testing::Invoke([&](fmt::internal::CustomValue custom) { EXPECT_EQ(&test, custom.value); fmt::MemoryWriter w; - fmt::format_context ctx("}", fmt::format_args()); + fmt::context ctx("}", fmt::format_args()); custom.format(w, &test, &ctx); EXPECT_EQ("test", w.str()); return Visitor::Result(); })); - fmt::visit(visitor, make_arg(test)); + fmt::visit(visitor, make_arg(test)); } TEST(ArgVisitorTest, VisitInvalidArg) { From a13b96ed88b05830bfee132c20095a342cc4bd08 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sun, 5 Feb 2017 06:54:03 -0800 Subject: [PATCH 084/340] Simplify API --- fmt/format.cc | 16 ++++++++-------- fmt/format.h | 21 +++++++++------------ fmt/ostream.cc | 2 +- fmt/ostream.h | 2 +- fmt/posix.h | 2 +- test/custom-formatter-test.cc | 2 +- test/format-impl-test.cc | 3 +-- test/format-test.cc | 4 ++-- test/ostream-test.cc | 2 +- test/util-test.cc | 7 +++---- 10 files changed, 28 insertions(+), 33 deletions(-) diff --git a/fmt/format.cc b/fmt/format.cc index 3dd42e1a..1e34dabb 100644 --- a/fmt/format.cc +++ b/fmt/format.cc @@ -224,7 +224,7 @@ FMT_FUNC void format_system_error( } // namespace internal FMT_FUNC void SystemError::init( - int err_code, CStringRef format_str, format_args args) { + int err_code, CStringRef format_str, args args) { error_code_ = err_code; MemoryWriter w; format_system_error(w, err_code, vformat(format_str, args)); @@ -348,7 +348,7 @@ FMT_FUNC int internal::UTF16ToUTF8::convert(WStringRef s) { } FMT_FUNC void WindowsError::init( - int err_code, CStringRef format_str, format_args args) { + int err_code, CStringRef format_str, args args) { error_code_ = err_code; MemoryWriter w; internal::format_windows_error(w, err_code, vformat(format_str, args)); @@ -428,17 +428,17 @@ FMT_FUNC void report_windows_error( } #endif -FMT_FUNC void vprint(std::FILE *f, CStringRef format_str, format_args args) { +FMT_FUNC void vprint(std::FILE *f, CStringRef format_str, args args) { MemoryWriter w; w.vformat(format_str, args); std::fwrite(w.data(), 1, w.size(), f); } -FMT_FUNC void vprint(CStringRef format_str, format_args args) { +FMT_FUNC void vprint(CStringRef format_str, args args) { vprint(stdout, format_str, args); } -FMT_FUNC void vprint_colored(Color c, CStringRef format, format_args args) { +FMT_FUNC void vprint_colored(Color c, CStringRef format, args args) { char escape[] = "\x1b[30m"; escape[3] = static_cast('0' + c); std::fputs(escape, stdout); @@ -448,7 +448,7 @@ FMT_FUNC void vprint_colored(Color c, CStringRef format, format_args args) { template void printf(basic_writer &w, BasicCStringRef format, - format_args args); + args args); FMT_FUNC int vfprintf(std::FILE *f, CStringRef format, printf_args args) { MemoryWriter w; @@ -465,7 +465,7 @@ template struct internal::BasicData; template void internal::FixedBuffer::grow(std::size_t); -template void internal::ArgMap::init(const format_args &args); +template void internal::ArgMap::init(const args &args); template void printf_context::format(writer &writer); @@ -483,7 +483,7 @@ template class basic_context; template void internal::FixedBuffer::grow(std::size_t); -template void internal::ArgMap::init(const wformat_args &args); +template void internal::ArgMap::init(const wargs &args); template void printf_context::format(wwriter &writer); diff --git a/fmt/format.h b/fmt/format.h index 742904f2..a6a87fb5 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -1369,9 +1369,6 @@ class basic_arg { } }; -typedef basic_arg format_arg; -typedef basic_arg wformat_arg; - /** \rst Visits an argument dispatching to the appropriate visit method based on @@ -1625,8 +1622,8 @@ class basic_args { } }; -typedef basic_args format_args; -typedef basic_args wformat_args; +typedef basic_args args; +typedef basic_args wargs; enum Alignment { ALIGN_DEFAULT, ALIGN_LEFT, ALIGN_RIGHT, ALIGN_CENTER, ALIGN_NUMERIC @@ -2111,7 +2108,7 @@ class basic_context : */ class SystemError : public internal::RuntimeError { private: - void init(int err_code, CStringRef format_str, format_args args); + void init(int err_code, CStringRef format_str, args args); protected: int error_code_; @@ -2943,7 +2940,7 @@ FMT_API void report_system_error(int error_code, /** A Windows error. */ class WindowsError : public SystemError { private: - FMT_API void init(int error_code, CStringRef format_str, format_args args); + FMT_API void init(int error_code, CStringRef format_str, args args); public: /** @@ -2989,7 +2986,7 @@ FMT_API void report_windows_error(int error_code, enum Color { BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE }; -FMT_API void vprint_colored(Color c, CStringRef format, format_args args); +FMT_API void vprint_colored(Color c, CStringRef format, args args); /** Formats a string and prints it to stdout using ANSI escape sequences @@ -3003,7 +3000,7 @@ inline void print_colored(Color c, CStringRef format_str, vprint_colored(c, format_str, make_args(args...)); } -inline std::string vformat(CStringRef format_str, format_args args) { +inline std::string vformat(CStringRef format_str, args args) { MemoryWriter w; w.vformat(format_str, args); return w.str(); @@ -3023,7 +3020,7 @@ inline std::string format(CStringRef format_str, const Args & ... args) { return vformat(format_str, make_args(args...)); } -inline std::wstring vformat(WCStringRef format_str, wformat_args args) { +inline std::wstring vformat(WCStringRef format_str, wargs args) { WMemoryWriter w; w.vformat(format_str, args); return w.str(); @@ -3035,7 +3032,7 @@ inline std::wstring format(WCStringRef format_str, const Args & ... args) { return vformat(format_str, vargs); } -FMT_API void vprint(std::FILE *f, CStringRef format_str, format_args args); +FMT_API void vprint(std::FILE *f, CStringRef format_str, args args); /** \rst @@ -3051,7 +3048,7 @@ inline void print(std::FILE *f, CStringRef format_str, const Args & ... args) { vprint(f, format_str, make_args(args...)); } -FMT_API void vprint(CStringRef format_str, format_args args); +FMT_API void vprint(CStringRef format_str, args args); /** \rst diff --git a/fmt/ostream.cc b/fmt/ostream.cc index 0c7c7501..d6f26985 100644 --- a/fmt/ostream.cc +++ b/fmt/ostream.cc @@ -28,7 +28,7 @@ FMT_FUNC void write(std::ostream &os, writer &w) { } FMT_FUNC void vprint(std::ostream &os, CStringRef format_str, - format_args args) { + args args) { MemoryWriter w; w.vformat(format_str, args); internal::write(os, w); diff --git a/fmt/ostream.h b/fmt/ostream.h index 040a185b..4db6f9c4 100644 --- a/fmt/ostream.h +++ b/fmt/ostream.h @@ -91,7 +91,7 @@ void format_value(basic_writer &w, const T &value, w, internal::make_arg< basic_context >(str), ctx); } -FMT_API void vprint(std::ostream &os, CStringRef format_str, format_args args); +FMT_API void vprint(std::ostream &os, CStringRef format_str, args args); /** \rst diff --git a/fmt/posix.h b/fmt/posix.h index 19e80024..afc69584 100644 --- a/fmt/posix.h +++ b/fmt/posix.h @@ -166,7 +166,7 @@ public: // of MinGW that define fileno as a macro. int (fileno)() const; - void vprint(CStringRef format_str, const format_args &args) { + void vprint(CStringRef format_str, const args &args) { fmt::vprint(file_, format_str, args); } diff --git a/test/custom-formatter-test.cc b/test/custom-formatter-test.cc index 526a9258..01d8b953 100644 --- a/test/custom-formatter-test.cc +++ b/test/custom-formatter-test.cc @@ -45,7 +45,7 @@ class CustomPrintfArgFormatter : public PrintfArgFormatter { } }; -std::string custom_vformat(fmt::CStringRef format_str, fmt::format_args args) { +std::string custom_vformat(fmt::CStringRef format_str, fmt::args args) { fmt::MemoryWriter writer; // Pass custom argument formatter as a template arg to vformat. fmt::vwrite(writer, format_str, args); diff --git a/test/format-impl-test.cc b/test/format-impl-test.cc index c19329f7..6308273e 100644 --- a/test/format-impl-test.cc +++ b/test/format-impl-test.cc @@ -55,9 +55,8 @@ struct ValueExtractor { }; TEST(FormatTest, ArgConverter) { - using fmt::format_arg; fmt::LongLong value = std::numeric_limits::max(); - format_arg arg = fmt::internal::make_arg(value); + auto arg = fmt::internal::make_arg(value); visit(fmt::internal::ArgConverter< fmt::LongLong, fmt::context>(arg, 'd'), arg); EXPECT_EQ(value, visit(ValueExtractor(), arg)); diff --git a/test/format-test.cc b/test/format-test.cc index 35a9e476..f10e1b1f 100644 --- a/test/format-test.cc +++ b/test/format-test.cc @@ -1566,7 +1566,7 @@ TEST(StrTest, Convert) { EXPECT_EQ("2012-12-9", s); } -std::string vformat_message(int id, const char *format, fmt::format_args args) { +std::string vformat_message(int id, const char *format, fmt::args args) { MemoryWriter w; w.format("[{}] ", id); w.vformat(format, args); @@ -1656,7 +1656,7 @@ class MockArgFormatter : public fmt::internal::ArgFormatterBase { void operator()(fmt::internal::CustomValue) {} }; -void custom_vformat(fmt::CStringRef format_str, fmt::format_args args) { +void custom_vformat(fmt::CStringRef format_str, fmt::args args) { fmt::MemoryWriter writer; fmt::vwrite(writer, format_str, args); } diff --git a/test/ostream-test.cc b/test/ostream-test.cc index af279b8f..6eab45a6 100644 --- a/test/ostream-test.cc +++ b/test/ostream-test.cc @@ -65,7 +65,7 @@ struct TestArgFormatter : fmt::ArgFormatter { TEST(OStreamTest, CustomArg) { fmt::MemoryWriter writer; - fmt::context ctx("}", fmt::format_args()); + fmt::context ctx("}", fmt::args()); fmt::format_specs spec; TestArgFormatter af(writer, ctx, spec); visit(af, fmt::internal::make_arg(TestEnum())); diff --git a/test/util-test.cc b/test/util-test.cc index e84415d8..19cbcb8f 100644 --- a/test/util-test.cc +++ b/test/util-test.cc @@ -53,7 +53,6 @@ #undef max using fmt::basic_arg; -using fmt::format_arg; using fmt::buffer; using fmt::StringRef; using fmt::internal::MemoryBuffer; @@ -408,7 +407,7 @@ TEST(UtilTest, Increment) { } TEST(UtilTest, FormatArgs) { - fmt::format_args args; + fmt::args args; EXPECT_FALSE(args[1]); } @@ -570,7 +569,7 @@ TEST(UtilTest, CustomArg) { testing::Invoke([&](fmt::internal::CustomValue custom) { EXPECT_EQ(&test, custom.value); fmt::MemoryWriter w; - fmt::context ctx("}", fmt::format_args()); + fmt::context ctx("}", fmt::args()); custom.format(w, &test, &ctx); EXPECT_EQ("test", w.str()); return Visitor::Result(); @@ -582,7 +581,7 @@ TEST(ArgVisitorTest, VisitInvalidArg) { typedef MockVisitor Visitor; testing::StrictMock visitor; EXPECT_CALL(visitor, visit(_)); - format_arg arg; + fmt::basic_arg arg; visit(visitor, arg); } From bb1c82ef7d8412fa11c78574c8103283f0ff516c Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sun, 5 Feb 2017 06:59:59 -0800 Subject: [PATCH 085/340] Fix build --- fmt/format.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/fmt/format.h b/fmt/format.h index a6a87fb5..6de92b0c 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -2199,7 +2199,7 @@ class basic_writer { private: // Output buffer. - buffer &buffer_; + fmt::buffer &buffer_; FMT_DISALLOW_COPY_AND_ASSIGN(basic_writer); @@ -2302,7 +2302,7 @@ class basic_writer { /** Constructs a ``basic_writer`` object. */ - explicit basic_writer(buffer &b) : buffer_(b) {} + explicit basic_writer(fmt::buffer &b) : buffer_(b) {} public: /** @@ -2443,7 +2443,7 @@ class basic_writer { void clear() FMT_NOEXCEPT { buffer_.clear(); } - buffer &buffer() FMT_NOEXCEPT { return buffer_; } + fmt::buffer &buffer() FMT_NOEXCEPT { return buffer_; } }; template @@ -2472,7 +2472,7 @@ typename basic_writer::CharPtr basic_writer::write_str( template template void basic_writer::write_str( - BasicStringRef s, const basic_writer::format_specs &spec) { + BasicStringRef s, const format_specs &spec) { // Check if StrChar is convertible to Char. internal::CharTraits::convert(StrChar()); if (spec.type_ && spec.type_ != 's') From 6e568f3a08c9a62edcb61cd39b6656c0de78bede Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Tue, 14 Feb 2017 12:08:37 -0500 Subject: [PATCH 086/340] buffer -> basic_buffer --- fmt/format.h | 24 ++++++++++++------------ fmt/ostream.h | 4 ++-- fmt/string.h | 2 +- fmt/time.h | 2 +- test/ostream-test.cc | 2 +- test/util-test.cc | 22 +++++++++++----------- 6 files changed, 28 insertions(+), 28 deletions(-) diff --git a/fmt/format.h b/fmt/format.h index 6de92b0c..3857a11e 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -587,16 +587,16 @@ inline T *make_ptr(T *ptr, std::size_t) { return ptr; } \endrst */ template -class buffer { +class basic_buffer { private: - FMT_DISALLOW_COPY_AND_ASSIGN(buffer); + FMT_DISALLOW_COPY_AND_ASSIGN(basic_buffer); protected: T *ptr_; std::size_t size_; std::size_t capacity_; - buffer(T *ptr = 0, std::size_t capacity = 0) + basic_buffer(T *ptr = 0, std::size_t capacity = 0) : ptr_(ptr), size_(0), capacity_(capacity) {} /** @@ -608,7 +608,7 @@ class buffer { virtual void grow(std::size_t size) = 0; public: - virtual ~buffer() {} + virtual ~basic_buffer() {} /** Returns the size of this buffer. */ std::size_t size() const { return size_; } @@ -653,7 +653,7 @@ class buffer { template template -void buffer::append(const U *begin, const U *end) { +void basic_buffer::append(const U *begin, const U *end) { std::size_t new_size = size_ + internal::to_unsigned(end - begin); if (new_size > capacity_) grow(new_size); @@ -667,7 +667,7 @@ namespace internal { // A memory buffer for trivially copyable/constructible types with the first // SIZE elements stored in the object itself. template > -class MemoryBuffer : private Allocator, public buffer { +class MemoryBuffer : private Allocator, public basic_buffer { private: T data_[SIZE]; @@ -681,7 +681,7 @@ class MemoryBuffer : private Allocator, public buffer { public: explicit MemoryBuffer(const Allocator &alloc = Allocator()) - : Allocator(alloc), buffer(data_, SIZE) {} + : Allocator(alloc), basic_buffer(data_, SIZE) {} ~MemoryBuffer() { deallocate(); } #if FMT_USE_RVALUE_REFERENCES @@ -743,10 +743,10 @@ void MemoryBuffer::grow(std::size_t size) { // A fixed-size buffer. template -class FixedBuffer : public fmt::buffer { +class FixedBuffer : public fmt::basic_buffer { public: FixedBuffer(Char *array, std::size_t size) - : fmt::buffer(array, size) {} + : fmt::basic_buffer(array, size) {} protected: FMT_API void grow(std::size_t size); @@ -2199,7 +2199,7 @@ class basic_writer { private: // Output buffer. - fmt::buffer &buffer_; + basic_buffer &buffer_; FMT_DISALLOW_COPY_AND_ASSIGN(basic_writer); @@ -2302,7 +2302,7 @@ class basic_writer { /** Constructs a ``basic_writer`` object. */ - explicit basic_writer(fmt::buffer &b) : buffer_(b) {} + explicit basic_writer(basic_buffer &b) : buffer_(b) {} public: /** @@ -2443,7 +2443,7 @@ class basic_writer { void clear() FMT_NOEXCEPT { buffer_.clear(); } - fmt::buffer &buffer() FMT_NOEXCEPT { return buffer_; } + basic_buffer &buffer() FMT_NOEXCEPT { return buffer_; } }; template diff --git a/fmt/ostream.h b/fmt/ostream.h index 4db6f9c4..f3780354 100644 --- a/fmt/ostream.h +++ b/fmt/ostream.h @@ -23,11 +23,11 @@ class FormatBuf : public std::basic_streambuf { typedef typename std::basic_streambuf::int_type int_type; typedef typename std::basic_streambuf::traits_type traits_type; - buffer &buffer_; + basic_buffer &buffer_; Char *start_; public: - FormatBuf(buffer &buffer) : buffer_(buffer), start_(&buffer[0]) { + FormatBuf(basic_buffer &buffer) : buffer_(buffer), start_(&buffer[0]) { this->setp(start_, start_ + buffer_.capacity()); } diff --git a/fmt/string.h b/fmt/string.h index acb399b6..35154f47 100644 --- a/fmt/string.h +++ b/fmt/string.h @@ -18,7 +18,7 @@ namespace internal { // A buffer that stores data in ``std::string``. template -class StringBuffer : public buffer { +class StringBuffer : public basic_buffer { private: std::basic_string data_; diff --git a/fmt/time.h b/fmt/time.h index 4f07fd00..b5482e73 100644 --- a/fmt/time.h +++ b/fmt/time.h @@ -27,7 +27,7 @@ void format_value(writer &w, const std::tm &tm, context &ctx) { internal::MemoryBuffer format; format.append(s, end + 1); format[format.size() - 1] = '\0'; - buffer &buffer = w.buffer(); + basic_buffer &buffer = w.buffer(); std::size_t start = buffer.size(); for (;;) { std::size_t size = buffer.capacity() - start; diff --git a/test/ostream-test.cc b/test/ostream-test.cc index 6eab45a6..eea803df 100644 --- a/test/ostream-test.cc +++ b/test/ostream-test.cc @@ -135,7 +135,7 @@ TEST(OStreamTest, WriteToOStreamMaxSize) { class TestWriter : public fmt::basic_writer { private: - struct TestBuffer : fmt::buffer { + struct TestBuffer : fmt::basic_buffer { explicit TestBuffer(std::size_t size) { size_ = size; } void grow(std::size_t) {} } buffer_; diff --git a/test/util-test.cc b/test/util-test.cc index 19cbcb8f..84ba407f 100644 --- a/test/util-test.cc +++ b/test/util-test.cc @@ -53,7 +53,7 @@ #undef max using fmt::basic_arg; -using fmt::buffer; +using fmt::basic_buffer; using fmt::StringRef; using fmt::internal::MemoryBuffer; using fmt::internal::value; @@ -106,24 +106,24 @@ TEST(AllocatorTest, AllocatorRef) { #if FMT_USE_TYPE_TRAITS TEST(BufferTest, Noncopyable) { - EXPECT_FALSE(std::is_copy_constructible >::value); - EXPECT_FALSE(std::is_copy_assignable >::value); + EXPECT_FALSE(std::is_copy_constructible >::value); + EXPECT_FALSE(std::is_copy_assignable >::value); } TEST(BufferTest, Nonmoveable) { - EXPECT_FALSE(std::is_move_constructible >::value); - EXPECT_FALSE(std::is_move_assignable >::value); + EXPECT_FALSE(std::is_move_constructible >::value); + EXPECT_FALSE(std::is_move_assignable >::value); } #endif // A test buffer with a dummy grow method. template -struct TestBuffer : buffer { +struct TestBuffer : basic_buffer { void grow(std::size_t size) { this->capacity_ = size; } }; template -struct MockBuffer : buffer { +struct MockBuffer : basic_buffer { MOCK_METHOD1(do_grow, void (std::size_t size)); void grow(std::size_t size) { @@ -132,8 +132,8 @@ struct MockBuffer : buffer { } MockBuffer() {} - MockBuffer(T *ptr) : buffer(ptr) {} - MockBuffer(T *ptr, std::size_t capacity) : buffer(ptr, capacity) {} + MockBuffer(T *ptr) : basic_buffer(ptr) {} + MockBuffer(T *ptr, std::size_t capacity) : basic_buffer(ptr, capacity) {} }; TEST(BufferTest, Ctor) { @@ -169,7 +169,7 @@ TEST(BufferTest, VirtualDtor) { typedef StrictMock StictMockBuffer; StictMockBuffer *mock_buffer = new StictMockBuffer(); EXPECT_CALL(*mock_buffer, die()); - buffer *buffer = mock_buffer; + basic_buffer *buffer = mock_buffer; delete buffer; } @@ -180,7 +180,7 @@ TEST(BufferTest, Access) { EXPECT_EQ(11, buffer[0]); buffer[3] = 42; EXPECT_EQ(42, *(&buffer[0] + 3)); - const fmt::buffer &const_buffer = buffer; + const fmt::basic_buffer &const_buffer = buffer; EXPECT_EQ(42, const_buffer[3]); } From fefaf07b6f412520b15b603eba97b2bf91d4d13c Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Tue, 14 Feb 2017 16:29:47 -0500 Subject: [PATCH 087/340] Pass buffer instead of writer to format_value --- fmt/format.cc | 65 +++++------ fmt/format.h | 197 ++++++++++++++++------------------ fmt/ostream.cc | 15 ++- fmt/ostream.h | 17 ++- fmt/printf.h | 51 +++++---- fmt/time.h | 13 ++- test/custom-formatter-test.cc | 22 ++-- test/format-impl-test.cc | 8 +- test/format-test.cc | 85 ++++++--------- test/gtest-extra-test.cc | 2 +- test/gtest-extra.cc | 4 +- test/ostream-test.cc | 39 +++---- test/util-test.cc | 37 ++++--- 13 files changed, 258 insertions(+), 297 deletions(-) diff --git a/fmt/format.cc b/fmt/format.cc index 1e34dabb..cd8a244c 100644 --- a/fmt/format.cc +++ b/fmt/format.cc @@ -106,7 +106,7 @@ inline int fmt_snprintf(char *buffer, size_t size, const char *format, ...) { const char RESET_COLOR[] = "\x1b[0m"; -typedef void (*FormatFunc)(writer &, int, StringRef); +typedef void (*FormatFunc)(buffer &, int, StringRef); // Portable thread-safe version of strerror. // Sets buffer to point to a string describing the error code. @@ -176,7 +176,7 @@ int safe_strerror( return StrError(error_code, buffer, buffer_size).run(); } -void format_error_code(writer &out, int error_code, +void format_error_code(buffer &out, int error_code, StringRef message) FMT_NOEXCEPT { // Report error code making sure that the output fits into // INLINE_BUFFER_SIZE to avoid dynamic memory allocation and potential @@ -193,18 +193,19 @@ void format_error_code(writer &out, int error_code, ++error_code_size; } error_code_size += internal::count_digits(abs_value); + basic_writer w(out); if (message.size() <= internal::INLINE_BUFFER_SIZE - error_code_size) { - out.write(message); - out.write(SEP); + w.write(message); + w.write(SEP); } - out.write(ERROR_STR); - out.write(error_code); + w.write(ERROR_STR); + w.write(error_code); assert(out.size() <= internal::INLINE_BUFFER_SIZE); } void report_error(FormatFunc func, int error_code, StringRef message) FMT_NOEXCEPT { - MemoryWriter full_message; + internal::MemoryBuffer full_message; func(full_message, error_code, message); // Use Writer::data instead of Writer::c_str to avoid potential memory // allocation. @@ -213,23 +214,13 @@ void report_error(FormatFunc func, int error_code, } } // namespace -namespace internal { - -// This method is used to preserve binary compatibility with fmt 3.0. -// It can be removed in 4.0. -FMT_FUNC void format_system_error( - writer &out, int error_code, StringRef message) FMT_NOEXCEPT { - fmt::format_system_error(out, error_code, message); -} -} // namespace internal - FMT_FUNC void SystemError::init( int err_code, CStringRef format_str, args args) { error_code_ = err_code; - MemoryWriter w; - format_system_error(w, err_code, vformat(format_str, args)); + internal::MemoryBuffer buf; + format_system_error(buf, err_code, vformat(format_str, args)); std::runtime_error &base = *this; - base = std::runtime_error(w.str()); + base = std::runtime_error(to_string(buf)); } template @@ -388,7 +379,7 @@ FMT_FUNC void internal::format_windows_error( #endif // FMT_USE_WINDOWS_H FMT_FUNC void format_system_error( - writer &out, int error_code, StringRef message) FMT_NOEXCEPT { + buffer &out, int error_code, StringRef message) FMT_NOEXCEPT { FMT_TRY { internal::MemoryBuffer buffer; buffer.resize(internal::INLINE_BUFFER_SIZE); @@ -396,9 +387,10 @@ FMT_FUNC void format_system_error( char *system_message = &buffer[0]; int result = safe_strerror(error_code, system_message, buffer.size()); if (result == 0) { - out.write(message); - out.write(": "); - out.write(system_message); + basic_writer w(out); + w.write(message); + w.write(": "); + w.write(system_message); return; } if (result != ERANGE) @@ -410,7 +402,7 @@ FMT_FUNC void format_system_error( } template -void internal::FixedBuffer::grow(std::size_t) { +void FixedBuffer::grow(std::size_t) { FMT_THROW(std::runtime_error("buffer overflow")); } @@ -429,9 +421,9 @@ FMT_FUNC void report_windows_error( #endif FMT_FUNC void vprint(std::FILE *f, CStringRef format_str, args args) { - MemoryWriter w; - w.vformat(format_str, args); - std::fwrite(w.data(), 1, w.size(), f); + internal::MemoryBuffer buffer; + vformat_to(buffer, format_str, args); + std::fwrite(buffer.data(), 1, buffer.size(), f); } FMT_FUNC void vprint(CStringRef format_str, args args) { @@ -451,10 +443,11 @@ void printf(basic_writer &w, BasicCStringRef format, args args); FMT_FUNC int vfprintf(std::FILE *f, CStringRef format, printf_args args) { - MemoryWriter w; - printf(w, format, args); - std::size_t size = w.size(); - return std::fwrite(w.data(), 1, size, f) < size ? -1 : static_cast(size); + internal::MemoryBuffer buffer; + printf(buffer, format, args); + std::size_t size = buffer.size(); + return std::fwrite( + buffer.data(), 1, size, f) < size ? -1 : static_cast(size); } #ifndef FMT_HEADER_ONLY @@ -463,11 +456,11 @@ template struct internal::BasicData; // Explicit instantiations for char. -template void internal::FixedBuffer::grow(std::size_t); +template void FixedBuffer::grow(std::size_t); template void internal::ArgMap::init(const args &args); -template void printf_context::format(writer &writer); +template void printf_context::format(buffer &); template int internal::CharTraits::format_float( char *buffer, std::size_t size, const char *format, @@ -481,11 +474,11 @@ template int internal::CharTraits::format_float( template class basic_context; -template void internal::FixedBuffer::grow(std::size_t); +template void FixedBuffer::grow(std::size_t); template void internal::ArgMap::init(const wargs &args); -template void printf_context::format(wwriter &writer); +template void printf_context::format(wbuffer &); template int internal::CharTraits::format_float( wchar_t *buffer, std::size_t size, const wchar_t *format, diff --git a/fmt/format.h b/fmt/format.h index 3857a11e..5b8f5bd0 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -365,10 +365,13 @@ using std::move; #endif template -class basic_writer; +class basic_buffer; -typedef basic_writer writer; -typedef basic_writer wwriter; +typedef basic_buffer buffer; +typedef basic_buffer wbuffer; + +template +class basic_writer; template class basic_arg; @@ -616,6 +619,9 @@ class basic_buffer { /** Returns the capacity of this buffer. */ std::size_t capacity() const { return capacity_; } + /** Returns a pointer to the buffer data. */ + const T *data() const { return ptr_; } + /** Resizes the buffer. If T is a POD type new elements may not be initialized. */ @@ -662,11 +668,17 @@ void basic_buffer::append(const U *begin, const U *end) { size_ = new_size; } +template +inline std::basic_string to_string(const basic_buffer& buffer) { + return std::basic_string(buffer.data(), buffer.size()); +} + namespace internal { // A memory buffer for trivially copyable/constructible types with the first // SIZE elements stored in the object itself. -template > +template > class MemoryBuffer : private Allocator, public basic_buffer { private: T data_[SIZE]; @@ -741,17 +753,6 @@ void MemoryBuffer::grow(std::size_t size) { Allocator::deallocate(old_ptr, old_capacity); } -// A fixed-size buffer. -template -class FixedBuffer : public fmt::basic_buffer { - public: - FixedBuffer(Char *array, std::size_t size) - : fmt::basic_buffer(array, size) {} - - protected: - FMT_API void grow(std::size_t size); -}; - template class BasicCharTraits { public: @@ -988,7 +989,7 @@ class UTF16ToUTF8 { FMT_API int convert(WStringRef s); }; -FMT_API void format_windows_error(fmt::writer &out, int error_code, +FMT_API void format_windows_error(fmt::buffer &out, int error_code, fmt::StringRef message) FMT_NOEXCEPT; #endif @@ -1085,7 +1086,7 @@ struct string_value { template struct CustomValue { typedef void (*FormatFunc)( - basic_writer &writer, const void *arg, void *ctx); + basic_buffer &buffer, const void *arg, void *ctx); const void *value; FormatFunc format; @@ -1207,8 +1208,8 @@ class value { // Formats an argument of a custom type, such as a user-defined class. template static void format_custom_arg( - basic_writer &writer, const void *arg, void *context) { - format_value(writer, *static_cast(arg), + basic_buffer &buffer, const void *arg, void *context) { + format_value(buffer, *static_cast(arg), *static_cast(context)); } @@ -1464,7 +1465,7 @@ inline fmt::StringRef thousands_sep(...) { return ""; } #endif template -void format_value(basic_writer &, const T &, Formatter &, const Char *) { +void format_value(basic_buffer &, const T &, Formatter &, const Char *) { FMT_STATIC_ASSERT(False::value, "Cannot format argument. To enable the use of ostream " "operator<< include fmt/ostream.h. Otherwise provide " @@ -1858,7 +1859,7 @@ class ArgFormatterBase { typedef basic_format_specs format_specs; private: - basic_writer &writer_; + basic_writer writer_; format_specs &spec_; FMT_DISALLOW_COPY_AND_ASSIGN(ArgFormatterBase); @@ -1901,8 +1902,8 @@ class ArgFormatterBase { public: typedef Char char_type; - ArgFormatterBase(basic_writer &w, format_specs &s) - : writer_(w), spec_(s) {} + ArgFormatterBase(basic_buffer &b, format_specs &s) + : writer_(b), spec_(s) {} void operator()(monostate) { FMT_ASSERT(false, "invalid argument type"); @@ -1973,12 +1974,6 @@ class ArgFormatterBase { } }; -template -inline void write(basic_writer &w, const Char *start, const Char *end) { - if (start != end) - w.write(BasicStringRef(start, internal::to_unsigned(end - start))); -} - template class context_base { private: @@ -2047,20 +2042,20 @@ class ArgFormatter : public internal::ArgFormatterBase { /** \rst Constructs an argument formatter object. - *writer* is a reference to the writer to be used for output, + *buffer* is a reference to the buffer to be used for output, *ctx* is a reference to the formatting context, *spec* contains format specifier information for standard argument types. \endrst */ - ArgFormatter(basic_writer &writer, basic_context &ctx, + ArgFormatter(basic_buffer &buffer, basic_context &ctx, format_specs &spec) - : internal::ArgFormatterBase(writer, spec), ctx_(ctx) {} + : internal::ArgFormatterBase(buffer, spec), ctx_(ctx) {} using internal::ArgFormatterBase::operator(); /** Formats an argument of a custom (user-defined) type. */ void operator()(internal::CustomValue c) { - c.format(this->writer(), c.value, &ctx_); + c.format(this->writer().buffer(), c.value, &ctx_); } }; @@ -2160,7 +2155,7 @@ class SystemError : public internal::RuntimeError { may look like "Unknown error -1" and is platform-dependent. \endrst */ -FMT_API void format_system_error(fmt::writer &out, int error_code, +FMT_API void format_system_error(fmt::buffer &out, int error_code, fmt::StringRef message) FMT_NOEXCEPT; namespace internal { @@ -2298,13 +2293,12 @@ class basic_writer { template friend class PrintfArgFormatter; - protected: + public: /** Constructs a ``basic_writer`` object. */ explicit basic_writer(basic_buffer &b) : buffer_(b) {} - public: /** \rst Destroys a ``basic_writer`` object. @@ -2343,38 +2337,6 @@ class basic_writer { return std::basic_string(&buffer_[0], buffer_.size()); } - void vformat(BasicCStringRef format, - basic_args> args); - /** - \rst - Writes formatted data. - - *args* is an argument list representing arbitrary arguments. - - **Example**:: - - MemoryWriter out; - out.format("Current point:\n"); - out.format("({:+f}, {:+f})", -3.14, 3.14); - - This will write the following output to the ``out`` object: - - .. code-block:: none - - Current point: - (-3.140000, +3.140000) - - The output can be accessed using :func:`data()`, :func:`c_str` or - :func:`str` methods. - - See also :ref:`syntax`. - \endrst - */ - template - void format(BasicCStringRef format, const Args & ... args) { - vformat(format, make_args>(args...)); - } - void write(int value) { write_decimal(value); } @@ -2881,6 +2843,23 @@ class BasicMemoryWriter : public basic_writer { typedef BasicMemoryWriter MemoryWriter; typedef BasicMemoryWriter WMemoryWriter; +// A fixed-size buffer. +template +class FixedBuffer : public fmt::basic_buffer { + public: + /** + \rst + Constructs a :class:`fmt::FixedBuffer` object for *array* of the + given size. + \endrst + */ + FixedBuffer(Char *array, std::size_t size) + : fmt::basic_buffer(array, size) {} + + protected: + FMT_API void grow(std::size_t size); +}; + /** \rst This class template provides operations for formatting and writing data @@ -2904,15 +2883,9 @@ typedef BasicMemoryWriter WMemoryWriter; template class BasicArrayWriter : public basic_writer { private: - internal::FixedBuffer buffer_; + FixedBuffer buffer_; public: - /** - \rst - Constructs a :class:`fmt::BasicArrayWriter` object for *array* of the - given size. - \endrst - */ BasicArrayWriter(Char *array, std::size_t size) : basic_writer(buffer_), buffer_(array, size) {} @@ -3000,10 +2973,34 @@ inline void print_colored(Color c, CStringRef format_str, vprint_colored(c, format_str, make_args(args...)); } +template +void vformat_to(basic_buffer &buffer, BasicCStringRef format_str, + basic_args args); + +inline void vformat_to(buffer &buf, CStringRef format_str, args args) { + vformat_to>(buf, format_str, args); +} + +inline void vformat_to(wbuffer &buf, WCStringRef format_str, wargs args) { + vformat_to>(buf, format_str, args); +} + +template +inline void format_to(buffer &buf, CStringRef format_str, + const Args & ... args) { + vformat_to(buf, format_str, make_args(args...)); +} + +template +inline void format_to(wbuffer &buf, WCStringRef format_str, + const Args & ... args) { + vformat_to(buf, format_str, make_args(args...)); +} + inline std::string vformat(CStringRef format_str, args args) { - MemoryWriter w; - w.vformat(format_str, args); - return w.str(); + internal::MemoryBuffer buffer; + vformat_to(buffer, format_str, args); + return to_string(buffer); } /** @@ -3021,15 +3018,14 @@ inline std::string format(CStringRef format_str, const Args & ... args) { } inline std::wstring vformat(WCStringRef format_str, wargs args) { - WMemoryWriter w; - w.vformat(format_str, args); - return w.str(); + internal::MemoryBuffer buffer; + vformat_to(buffer, format_str, args); + return to_string(buffer); } template inline std::wstring format(WCStringRef format_str, const Args & ... args) { - auto vargs = make_args(args...); - return vformat(format_str, vargs); + return vformat(format_str, make_args(args...)); } FMT_API void vprint(std::FILE *f, CStringRef format_str, args args); @@ -3273,15 +3269,15 @@ void check_sign(const Char *&s, const basic_arg &arg) { template class CustomFormatter { private: - basic_writer &writer_; + basic_buffer &buffer_; Context &ctx_; public: - CustomFormatter(basic_writer &writer, Context &ctx) - : writer_(writer), ctx_(ctx) {} + CustomFormatter(basic_buffer &buffer, Context &ctx) + : buffer_(buffer), ctx_(ctx) {} bool operator()(internal::CustomValue custom) { - custom.format(writer_, custom.value, &ctx_); + custom.format(buffer_, custom.value, &ctx_); return true; } @@ -3374,12 +3370,12 @@ inline typename basic_context::format_arg // Formats a single argument. template -void do_format_arg(basic_writer &writer, basic_arg arg, +void do_format_arg(basic_buffer &buffer, basic_arg arg, Context &ctx) { const Char *&s = ctx.ptr(); basic_format_specs spec; if (*s == ':') { - if (visit(internal::CustomFormatter(writer, ctx), arg)) + if (visit(internal::CustomFormatter(buffer, ctx), arg)) return; ++s; // Parse fill and alignment. @@ -3495,13 +3491,13 @@ void do_format_arg(basic_writer &writer, basic_arg arg, FMT_THROW(format_error("missing '}' in format string")); // Format argument. - visit(ArgFormatter(writer, ctx, spec), arg); + visit(ArgFormatter(buffer, ctx, spec), arg); } -/** Formats arguments and writes the output to the writer. */ +/** Formats arguments and writes the output to the buffer. */ template -void vwrite(basic_writer &writer, BasicCStringRef format_str, - basic_args args) { +void vformat_to(basic_buffer &buffer, BasicCStringRef format_str, + basic_args args) { basic_context ctx(format_str.c_str(), args); const Char *&s = ctx.ptr(); const Char *start = s; @@ -3509,26 +3505,19 @@ void vwrite(basic_writer &writer, BasicCStringRef format_str, Char c = *s++; if (c != '{' && c != '}') continue; if (*s == c) { - internal::write(writer, start, s); + buffer.append(start, s); start = ++s; continue; } if (c == '}') FMT_THROW(format_error("unmatched '}' in format string")); - internal::write(writer, start, s - 1); - do_format_arg(writer, ctx.parse_arg_id(), ctx); + buffer.append(start, s - 1); + do_format_arg(buffer, ctx.parse_arg_id(), ctx); if (*s != '}') FMT_THROW(format_error(fmt::format("unknown format specifier"))); start = ++s; } - internal::write(writer, start, s); -} - -template -inline void basic_writer::vformat( - BasicCStringRef format, - basic_args> args) { - vwrite>(*this, format, args); + buffer.append(start, s); } } // namespace fmt diff --git a/fmt/ostream.cc b/fmt/ostream.cc index d6f26985..f900664c 100644 --- a/fmt/ostream.cc +++ b/fmt/ostream.cc @@ -12,10 +12,10 @@ namespace fmt { namespace internal { -FMT_FUNC void write(std::ostream &os, writer &w) { - const char *data = w.data(); +FMT_FUNC void write(std::ostream &os, buffer &buf) { + const char *data = buf.data(); typedef internal::MakeUnsigned::Type UnsignedStreamSize; - UnsignedStreamSize size = w.size(); + UnsignedStreamSize size = buf.size(); UnsignedStreamSize max_size = internal::to_unsigned((std::numeric_limits::max)()); do { @@ -27,10 +27,9 @@ FMT_FUNC void write(std::ostream &os, writer &w) { } } -FMT_FUNC void vprint(std::ostream &os, CStringRef format_str, - args args) { - MemoryWriter w; - w.vformat(format_str, args); - internal::write(os, w); +FMT_FUNC void vprint(std::ostream &os, CStringRef format_str, args args) { + internal::MemoryBuffer buffer; + vformat_to(buffer, format_str, args); + internal::write(os, buffer); } } // namespace fmt diff --git a/fmt/ostream.h b/fmt/ostream.h index f3780354..528ee16a 100644 --- a/fmt/ostream.h +++ b/fmt/ostream.h @@ -67,28 +67,27 @@ struct ConvertToIntImpl { }; }; -// Write the content of w to os. -void write(std::ostream &os, writer &w); +// Write the content of buf to os. +void write(std::ostream &os, buffer &buf); template -BasicStringRef format_value( - internal::MemoryBuffer &buffer, - const T &value) { +void format_value(basic_buffer &buffer, const T &value) { internal::FormatBuf format_buf(buffer); std::basic_ostream output(&format_buf); output << value; - return BasicStringRef(&buffer[0], format_buf.size()); + buffer.resize(format_buf.size()); } } // namespace internal // Formats a value. template -void format_value(basic_writer &w, const T &value, +void format_value(basic_buffer &buf, const T &value, basic_context &ctx) { internal::MemoryBuffer buffer; - auto str = internal::format_value(buffer, value); + internal::format_value(buffer, value); + BasicStringRef str(buffer.data(), buffer.size()); do_format_arg< ArgFormatter >( - w, internal::make_arg< basic_context >(str), ctx); + buf, internal::make_arg< basic_context >(str), ctx); } FMT_API void vprint(std::ostream &os, CStringRef format_str, args args); diff --git a/fmt/printf.h b/fmt/printf.h index 2fa54d2f..0b77ae34 100644 --- a/fmt/printf.h +++ b/fmt/printf.h @@ -225,12 +225,12 @@ class PrintfArgFormatter : public internal::ArgFormatterBase { /** \rst Constructs an argument formatter object. - *writer* is a reference to the output writer and *spec* contains format + *buffer* is a reference to the output buffer and *spec* contains format specifier information for standard argument types. \endrst */ - PrintfArgFormatter(basic_writer &writer, format_specs &spec) - : internal::ArgFormatterBase(writer, spec) {} + PrintfArgFormatter(basic_buffer &buffer, format_specs &spec) + : internal::ArgFormatterBase(buffer, spec) {} using Base::operator(); @@ -289,7 +289,7 @@ class PrintfArgFormatter : public internal::ArgFormatterBase { const Char format_str[] = {'}', '\0'}; auto args = basic_args>(); basic_context ctx(format_str, args); - c.format(this->writer(), c.value, &ctx); + c.format(this->writer().buffer(), c.value, &ctx); } }; @@ -331,8 +331,8 @@ class printf_context : basic_args args) : Base(format_str.c_str(), args) {} - /** Formats stored arguments and writes the output to the writer. */ - FMT_API void format(basic_writer &writer); + /** Formats stored arguments and writes the output to the buffer. */ + FMT_API void format(basic_buffer &buffer); }; template @@ -408,18 +408,18 @@ unsigned printf_context::parse_header( } template -void printf_context::format(basic_writer &writer) { +void printf_context::format(basic_buffer &buffer) { const Char *start = this->ptr(); const Char *s = start; while (*s) { Char c = *s++; if (c != '%') continue; if (*s == c) { - internal::write(writer, start, s); + buffer.append(start, s); start = ++s; continue; } - internal::write(writer, start, s - 1); + buffer.append(start, s - 1); format_specs spec; spec.align_ = ALIGN_RIGHT; @@ -501,31 +501,30 @@ void printf_context::format(basic_writer &writer) { start = s; // Format argument. - visit(AF(writer, spec), arg); + visit(AF(buffer, spec), arg); } - internal::write(writer, start, s); + buffer.append(start, s); } // Formats a value. template -void format_value(basic_writer &w, const T &value, +void format_value(basic_buffer &buf, const T &value, printf_context& ctx) { - internal::MemoryBuffer buffer; - w.write(internal::format_value(buffer, value)); + internal::format_value(buf, value); } template -void printf(basic_writer &w, BasicCStringRef format, +void printf(basic_buffer &buf, BasicCStringRef format, basic_args> args) { - printf_context(format, args).format(w); + printf_context(format, args).format(buf); } typedef basic_args> printf_args; inline std::string vsprintf(CStringRef format, printf_args args) { - MemoryWriter w; - printf(w, format, args); - return w.str(); + internal::MemoryBuffer buffer; + printf(buffer, format, args); + return to_string(buffer); } /** @@ -544,9 +543,9 @@ inline std::string sprintf(CStringRef format_str, const Args & ... args) { inline std::wstring vsprintf( WCStringRef format, basic_args> args) { - WMemoryWriter w; - printf(w, format, args); - return w.str(); + internal::MemoryBuffer buffer; + printf(buffer, format, args); + return to_string(buffer); } template @@ -591,10 +590,10 @@ inline int printf(CStringRef format_str, const Args & ... args) { } inline int vfprintf(std::ostream &os, CStringRef format_str, printf_args args) { - MemoryWriter w; - printf(w, format_str, args); - internal::write(os, w); - return static_cast(w.size()); + internal::MemoryBuffer buffer; + printf(buffer, format_str, args); + internal::write(os, buffer); + return static_cast(buffer.size()); } /** diff --git a/fmt/time.h b/fmt/time.h index b5482e73..f4ec4812 100644 --- a/fmt/time.h +++ b/fmt/time.h @@ -15,7 +15,7 @@ namespace fmt { -void format_value(writer &w, const std::tm &tm, context &ctx) { +void format_value(buffer &buf, const std::tm &tm, context &ctx) { const char *&s = ctx.ptr(); if (*s == ':') ++s; @@ -27,13 +27,12 @@ void format_value(writer &w, const std::tm &tm, context &ctx) { internal::MemoryBuffer format; format.append(s, end + 1); format[format.size() - 1] = '\0'; - basic_buffer &buffer = w.buffer(); - std::size_t start = buffer.size(); + std::size_t start = buf.size(); for (;;) { - std::size_t size = buffer.capacity() - start; - std::size_t count = std::strftime(&buffer[start], size, &format[0], &tm); + std::size_t size = buf.capacity() - start; + std::size_t count = std::strftime(&buf[start], size, &format[0], &tm); if (count != 0) { - buffer.resize(start + count); + buf.resize(start + count); break; } if (size >= format.size() * 256) { @@ -44,7 +43,7 @@ void format_value(writer &w, const std::tm &tm, context &ctx) { break; } const std::size_t MIN_GROWTH = 10; - buffer.reserve(buffer.capacity() + (size > MIN_GROWTH ? size : MIN_GROWTH)); + buf.reserve(buf.capacity() + (size > MIN_GROWTH ? size : MIN_GROWTH)); } s = end; } diff --git a/test/custom-formatter-test.cc b/test/custom-formatter-test.cc index 01d8b953..4a582c1a 100644 --- a/test/custom-formatter-test.cc +++ b/test/custom-formatter-test.cc @@ -16,9 +16,9 @@ using fmt::PrintfArgFormatter; // rounded to 0. class CustomArgFormatter : public fmt::ArgFormatter { public: - CustomArgFormatter(fmt::writer &w, fmt::basic_context &ctx, + CustomArgFormatter(fmt::buffer &buf, fmt::basic_context &ctx, fmt::format_specs &s) - : fmt::ArgFormatter(w, ctx, s) {} + : fmt::ArgFormatter(buf, ctx, s) {} using fmt::ArgFormatter::operator(); @@ -33,8 +33,8 @@ class CustomArgFormatter : public fmt::ArgFormatter { // rounded to 0. class CustomPrintfArgFormatter : public PrintfArgFormatter { public: - CustomPrintfArgFormatter(fmt::basic_writer &w, fmt::format_specs &spec) - : PrintfArgFormatter(w, spec) {} + CustomPrintfArgFormatter(fmt::buffer &buf, fmt::format_specs &spec) + : PrintfArgFormatter(buf, spec) {} using PrintfArgFormatter::operator(); @@ -46,10 +46,10 @@ class CustomPrintfArgFormatter : public PrintfArgFormatter { }; std::string custom_vformat(fmt::CStringRef format_str, fmt::args args) { - fmt::MemoryWriter writer; - // Pass custom argument formatter as a template arg to vformat. - fmt::vwrite(writer, format_str, args); - return writer.str(); + fmt::internal::MemoryBuffer buffer; + // Pass custom argument formatter as a template arg to vwrite. + fmt::vformat_to(buffer, format_str, args); + return std::string(buffer.data(), buffer.size()); } template @@ -64,10 +64,10 @@ typedef fmt::printf_context std::string custom_vsprintf( const char* format_str, fmt::basic_args args) { - fmt::MemoryWriter writer; + fmt::internal::MemoryBuffer buffer; CustomPrintfFormatter formatter(format_str, args); - formatter.format(writer); - return writer.str(); + formatter.format(buffer); + return std::string(buffer.data(), buffer.size()); } template diff --git a/test/format-impl-test.cc b/test/format-impl-test.cc index 6308273e..6c86a484 100644 --- a/test/format-impl-test.cc +++ b/test/format-impl-test.cc @@ -107,14 +107,14 @@ TEST(FormatTest, FormatErrorCode) { { fmt::MemoryWriter w; w.write("garbage"); - fmt::format_error_code(w, 42, "test"); + fmt::format_error_code(w.buffer(), 42, "test"); EXPECT_EQ("test: " + msg, w.str()); } { fmt::MemoryWriter w; std::string prefix( fmt::internal::INLINE_BUFFER_SIZE - msg.size() - sep.size() + 1, 'x'); - fmt::format_error_code(w, 42, prefix); + fmt::format_error_code(w.buffer(), 42, prefix); EXPECT_EQ(msg, w.str()); } int codes[] = {42, -1}; @@ -124,14 +124,14 @@ TEST(FormatTest, FormatErrorCode) { fmt::MemoryWriter w; std::string prefix( fmt::internal::INLINE_BUFFER_SIZE - msg.size() - sep.size(), 'x'); - fmt::format_error_code(w, codes[i], prefix); + fmt::format_error_code(w.buffer(), codes[i], prefix); EXPECT_EQ(prefix + sep + msg, w.str()); std::size_t size = fmt::internal::INLINE_BUFFER_SIZE; EXPECT_EQ(size, w.size()); w.clear(); // Test with a message that doesn't fit into the buffer. prefix += 'x'; - fmt::format_error_code(w, codes[i], prefix); + fmt::format_error_code(w.buffer(), codes[i], prefix); EXPECT_EQ(msg, w.str()); } } diff --git a/test/format-test.cc b/test/format-test.cc index f10e1b1f..02b99fd1 100644 --- a/test/format-test.cc +++ b/test/format-test.cc @@ -265,12 +265,6 @@ TEST(WriterTest, Data) { EXPECT_EQ("42", std::string(w.data(), w.size())); } -TEST(WriterTest, WriteWithoutArgs) { - MemoryWriter w; - w.format("test"); - EXPECT_EQ("test", std::string(w.data(), w.size())); -} - TEST(WriterTest, WriteInt) { CHECK_WRITE(42); CHECK_WRITE(-42); @@ -476,20 +470,6 @@ TEST(WriterTest, PadWString) { EXPECT_EQ(L"test******", write_wstr(L"test", width=10, fill=L'*')); } -TEST(WriterTest, Format) { - MemoryWriter w; - w.format("part{0}", 1); - EXPECT_EQ(strlen("part1"), w.size()); - EXPECT_STREQ("part1", w.c_str()); - EXPECT_STREQ("part1", w.data()); - EXPECT_EQ("part1", w.str()); - w.format("part{0}", 2); - EXPECT_EQ(strlen("part1part2"), w.size()); - EXPECT_STREQ("part1part2", w.c_str()); - EXPECT_STREQ("part1part2", w.data()); - EXPECT_EQ("part1part2", w.str()); -} - TEST(WriterTest, WWriter) { EXPECT_EQ(L"cafe", write_wstr(0xcafe, type='x')); } @@ -501,32 +481,43 @@ TEST(ArrayWriterTest, Ctor) { EXPECT_STREQ("", w.c_str()); } +TEST(FormatToTest, FormatWithoutArgs) { + fmt::internal::MemoryBuffer buffer; + format_to(buffer, "test"); + EXPECT_EQ("test", std::string(buffer.data(), buffer.size())); +} + +TEST(FormatToTest, Format) { + fmt::internal::MemoryBuffer buffer; + format_to(buffer, "part{0}", 1); + EXPECT_EQ(strlen("part1"), buffer.size()); + EXPECT_EQ("part1", std::string(buffer.data(), buffer.size())); + format_to(buffer, "part{0}", 2); + EXPECT_EQ(strlen("part1part2"), buffer.size()); + EXPECT_EQ("part1part2", std::string(buffer.data(), buffer.size())); + EXPECT_EQ("part1part2", to_string(buffer)); +} + TEST(ArrayWriterTest, CompileTimeSizeCtor) { char array[10] = "garbage"; fmt::ArrayWriter w(array); EXPECT_EQ(0u, w.size()); EXPECT_STREQ("", w.c_str()); - w.format("{:10}", 1); -} - -TEST(ArrayWriterTest, Write) { - char array[10]; - fmt::ArrayWriter w(array, sizeof(array)); - w.format("{}", 42); - EXPECT_EQ("42", w.str()); + format_to(w.buffer(), "{:10}", 1); } TEST(ArrayWriterTest, BufferOverflow) { char array[10]; fmt::ArrayWriter w(array, sizeof(array)); - w.format("{:10}", 1); - EXPECT_THROW_MSG(w.format("{}", 1), std::runtime_error, "buffer overflow"); + format_to(w.buffer(), "{:10}", 1); + EXPECT_THROW_MSG(format_to(w.buffer(), "{}", 1), std::runtime_error, + "buffer overflow"); } TEST(ArrayWriterTest, WChar) { wchar_t array[10]; fmt::WArrayWriter w(array); - w.format(L"{}", 42); + format_to(w.buffer(), L"{}", 42); EXPECT_EQ(L"42", w.str()); } @@ -1366,12 +1357,8 @@ TEST(FormatterTest, FormatCStringRef) { EXPECT_EQ("test", format("{0}", CStringRef("test"))); } -void format_value(fmt::writer &w, const Date &d, fmt::context &) { - w.write(d.year()); - w.write('-'); - w.write(d.month()); - w.write('-'); - w.write(d.day()); +void format_value(fmt::buffer &buf, const Date &d, fmt::context &) { + fmt::format_to(buf, "{}-{}-{}", d.year(), d.month(), d.day()); } TEST(FormatterTest, FormatCustom) { @@ -1383,8 +1370,8 @@ TEST(FormatterTest, FormatCustom) { class Answer {}; template -void format_value(basic_writer &w, Answer, fmt::context &) { - w.write("42"); +void format_value(fmt::basic_buffer &buf, Answer, fmt::context &) { + fmt::format_to(buf, "{}", 42); } TEST(FormatterTest, CustomFormat) { @@ -1417,13 +1404,11 @@ TEST(FormatterTest, FormatExamples) { out.write("The answer is "); out.write(42); out.write("\n"); - out.format("({:+f}, {:+f})", -3.14, 3.14); - EXPECT_EQ("The answer is 42\n(-3.140000, +3.140000)", out.str()); { MemoryWriter writer; for (int i = 0; i < 10; i++) - writer.format("{}", i); + format_to(writer.buffer(), "{}", i); std::string s = writer.str(); // s == 0123456789 EXPECT_EQ("0123456789", s); } @@ -1567,10 +1552,10 @@ TEST(StrTest, Convert) { } std::string vformat_message(int id, const char *format, fmt::args args) { - MemoryWriter w; - w.format("[{}] ", id); - w.vformat(format, args); - return w.str(); + fmt::internal::MemoryBuffer buffer; + format_to(buffer, "[{}] ", id); + vformat_to(buffer, format, args); + return to_string(buffer); } template @@ -1643,9 +1628,9 @@ class MockArgFormatter : public fmt::internal::ArgFormatterBase { public: typedef fmt::internal::ArgFormatterBase Base; - MockArgFormatter(fmt::writer &w, fmt::context &ctx, + MockArgFormatter(fmt::buffer &b, fmt::context &ctx, fmt::format_specs &s) - : fmt::internal::ArgFormatterBase(w, s) { + : fmt::internal::ArgFormatterBase(b, s) { EXPECT_CALL(*this, call(42)); } @@ -1657,8 +1642,8 @@ class MockArgFormatter : public fmt::internal::ArgFormatterBase { }; void custom_vformat(fmt::CStringRef format_str, fmt::args args) { - fmt::MemoryWriter writer; - fmt::vwrite(writer, format_str, args); + fmt::internal::MemoryBuffer buffer; + fmt::vformat_to(buffer, format_str, args); } template diff --git a/test/gtest-extra-test.cc b/test/gtest-extra-test.cc index 6a8c5676..4de17ee3 100644 --- a/test/gtest-extra-test.cc +++ b/test/gtest-extra-test.cc @@ -320,7 +320,7 @@ TEST(StreamingAssertionsTest, EXPECT_WRITE) { TEST(UtilTest, FormatSystemError) { fmt::MemoryWriter out; - fmt::format_system_error(out, EDOM, "test message"); + fmt::format_system_error(out.buffer(), EDOM, "test message"); EXPECT_EQ(out.str(), format_system_error(EDOM, "test message")); } diff --git a/test/gtest-extra.cc b/test/gtest-extra.cc index 7640d154..5708eef7 100644 --- a/test/gtest-extra.cc +++ b/test/gtest-extra.cc @@ -104,7 +104,7 @@ std::string read(File &f, std::size_t count) { #endif // FMT_USE_FILE_DESCRIPTORS std::string format_system_error(int error_code, fmt::StringRef message) { - fmt::MemoryWriter out; + fmt::internal::MemoryBuffer out; fmt::format_system_error(out, error_code, message); - return out.str(); + return to_string(out); } diff --git a/test/ostream-test.cc b/test/ostream-test.cc index eea803df..761820b6 100644 --- a/test/ostream-test.cc +++ b/test/ostream-test.cc @@ -59,17 +59,17 @@ TEST(OStreamTest, Enum) { } struct TestArgFormatter : fmt::ArgFormatter { - TestArgFormatter(fmt::writer &w, fmt::context &ctx, fmt::format_specs &s) - : fmt::ArgFormatter(w, ctx, s) {} + TestArgFormatter(fmt::buffer &buf, fmt::context &ctx, fmt::format_specs &s) + : fmt::ArgFormatter(buf, ctx, s) {} }; TEST(OStreamTest, CustomArg) { - fmt::MemoryWriter writer; + fmt::internal::MemoryBuffer buffer; fmt::context ctx("}", fmt::args()); fmt::format_specs spec; - TestArgFormatter af(writer, ctx, spec); + TestArgFormatter af(buffer, ctx, spec); visit(af, fmt::internal::make_arg(TestEnum())); - EXPECT_EQ("TestEnum", writer.str()); + EXPECT_EQ("TestEnum", std::string(buffer.data(), buffer.size())); } TEST(OStreamTest, Format) { @@ -121,9 +121,10 @@ TEST(OStreamTest, Print) { TEST(OStreamTest, WriteToOStream) { std::ostringstream os; - fmt::MemoryWriter w; - w.write("foo"); - fmt::internal::write(os, w); + fmt::internal::MemoryBuffer buffer; + const char *foo = "foo"; + buffer.append(foo, foo + std::strlen(foo)); + fmt::internal::write(os, buffer); EXPECT_EQ("foo", os.str()); } @@ -133,16 +134,10 @@ TEST(OStreamTest, WriteToOStreamMaxSize) { if (max_size <= fmt::internal::to_unsigned(max_streamsize)) return; - class TestWriter : public fmt::basic_writer { - private: - struct TestBuffer : fmt::basic_buffer { - explicit TestBuffer(std::size_t size) { size_ = size; } - void grow(std::size_t) {} - } buffer_; - public: - explicit TestWriter(std::size_t size) - : fmt::basic_writer(buffer_), buffer_(size) {} - } w(max_size); + struct TestBuffer : fmt::basic_buffer { + explicit TestBuffer(std::size_t size) { size_ = size; } + void grow(std::size_t) {} + } buffer(max_size); struct MockStreamBuf : std::streambuf { MOCK_METHOD2(xsputn, std::streamsize (const void *s, std::streamsize n)); @@ -150,11 +145,11 @@ TEST(OStreamTest, WriteToOStreamMaxSize) { const void *v = s; return xsputn(v, n); } - } buffer; + } streambuf; struct TestOStream : std::ostream { explicit TestOStream(MockStreamBuf &buffer) : std::ostream(&buffer) {} - } os(buffer); + } os(streambuf); testing::InSequence sequence; const char *data = 0; @@ -163,10 +158,10 @@ TEST(OStreamTest, WriteToOStreamMaxSize) { typedef fmt::internal::MakeUnsigned::Type UStreamSize; UStreamSize n = std::min( size, fmt::internal::to_unsigned(max_streamsize)); - EXPECT_CALL(buffer, xsputn(data, static_cast(n))) + EXPECT_CALL(streambuf, xsputn(data, static_cast(n))) .WillOnce(testing::Return(max_streamsize)); data += n; size -= static_cast(n); } while (size != 0); - fmt::internal::write(os, w); + fmt::internal::write(os, buffer); } diff --git a/test/util-test.cc b/test/util-test.cc index 84ba407f..9466c372 100644 --- a/test/util-test.cc +++ b/test/util-test.cc @@ -67,9 +67,10 @@ namespace { struct Test {}; template -void format_value(fmt::basic_writer &w, Test, +void format_value(fmt::basic_buffer &b, Test, fmt::basic_context &) { - w.write("test"); + const Char *test = "test"; + b.append(test, test + std::strlen(test)); } template @@ -416,7 +417,7 @@ struct CustomContext { bool called; }; -void format_value(fmt::writer &, const Test &, CustomContext &ctx) { +void format_value(fmt::buffer &, const Test &, CustomContext &ctx) { ctx.called = true; } @@ -424,8 +425,8 @@ TEST(UtilTest, MakeValueWithCustomFormatter) { ::Test t; fmt::internal::value arg(t); CustomContext ctx = {false}; - fmt::MemoryWriter w; - arg.custom.format(w, &t, &ctx); + fmt::internal::MemoryBuffer buffer; + arg.custom.format(buffer, &t, &ctx); EXPECT_TRUE(ctx.called); } @@ -568,10 +569,10 @@ TEST(UtilTest, CustomArg) { EXPECT_CALL(visitor, visit(_)).WillOnce( testing::Invoke([&](fmt::internal::CustomValue custom) { EXPECT_EQ(&test, custom.value); - fmt::MemoryWriter w; + fmt::internal::MemoryBuffer buffer; fmt::context ctx("}", fmt::args()); - custom.format(w, &test, &ctx); - EXPECT_EQ("test", w.str()); + custom.format(buffer, &test, &ctx); + EXPECT_EQ("test", std::string(buffer.data(), buffer.size())); return Visitor::Result(); })); fmt::visit(visitor, make_arg(test)); @@ -689,7 +690,7 @@ TEST(UtilTest, UTF16ToUTF8Convert) { #endif // _WIN32 typedef void (*FormatErrorMessage)( - fmt::writer &out, int error_code, StringRef message); + fmt::buffer &out, int error_code, StringRef message); template void check_throw_error(int error_code, FormatErrorMessage format) { @@ -699,20 +700,21 @@ void check_throw_error(int error_code, FormatErrorMessage format) { } catch (const fmt::SystemError &e) { error = e; } - fmt::MemoryWriter message; + fmt::internal::MemoryBuffer message; format(message, error_code, "test error"); - EXPECT_EQ(message.str(), error.what()); + EXPECT_EQ(to_string(message), error.what()); EXPECT_EQ(error_code, error.error_code()); } TEST(UtilTest, FormatSystemError) { - fmt::MemoryWriter message; + fmt::internal::MemoryBuffer message; fmt::format_system_error(message, EDOM, "test"); - EXPECT_EQ(fmt::format("test: {}", get_system_error(EDOM)), message.str()); + EXPECT_EQ(fmt::format("test: {}", get_system_error(EDOM)), + to_string(message)); message.clear(); fmt::format_system_error( message, EDOM, fmt::StringRef(0, std::numeric_limits::max())); - EXPECT_EQ(fmt::format("error {}", EDOM), message.str()); + EXPECT_EQ(fmt::format("error {}", EDOM), to_string(message)); } TEST(UtilTest, SystemError) { @@ -723,10 +725,11 @@ TEST(UtilTest, SystemError) { } TEST(UtilTest, ReportSystemError) { - fmt::MemoryWriter out; + fmt::internal::MemoryBuffer out; fmt::format_system_error(out, EDOM, "test error"); - out.write('\n'); - EXPECT_WRITE(stderr, fmt::report_system_error(EDOM, "test error"), out.str()); + out.push_back('\n'); + EXPECT_WRITE(stderr, fmt::report_system_error(EDOM, "test error"), + to_string(out)); } #ifdef _WIN32 From c2f021692f6fa3ddd4c9fe71526158139e8108e9 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Tue, 14 Feb 2017 20:12:39 -0500 Subject: [PATCH 088/340] Merge ArrayWriter into FixedBuffer --- fmt/format.h | 60 +++++++++++++-------------------------------- test/format-test.cc | 30 ----------------------- test/util-test.cc | 36 +++++++++++++++++---------- 3 files changed, 40 insertions(+), 86 deletions(-) diff --git a/fmt/format.h b/fmt/format.h index 5b8f5bd0..fff6adfa 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -586,7 +586,7 @@ inline T *make_ptr(T *ptr, std::size_t) { return ptr; } /** \rst - A buffer supporting a subset of ``std::vector``'s operations. + A contiguous memory buffer with an optional growing ability. \endrst */ template @@ -2843,9 +2843,17 @@ class BasicMemoryWriter : public basic_writer { typedef BasicMemoryWriter MemoryWriter; typedef BasicMemoryWriter WMemoryWriter; -// A fixed-size buffer. +/** + \rst + A fixed-size memory buffer. For a dynamically growing buffer use + :class:`fmt::internal::MemoryBuffer`. + + Trying to increase the buffer size past the initial capacity will throw + ``std::runtime_error``. + \endrst + */ template -class FixedBuffer : public fmt::basic_buffer { +class FixedBuffer : public basic_buffer { public: /** \rst @@ -2854,54 +2862,20 @@ class FixedBuffer : public fmt::basic_buffer { \endrst */ FixedBuffer(Char *array, std::size_t size) - : fmt::basic_buffer(array, size) {} - - protected: - FMT_API void grow(std::size_t size); -}; - -/** - \rst - This class template provides operations for formatting and writing data - into a fixed-size array. For writing into a dynamically growing buffer - use :class:`fmt::BasicMemoryWriter`. - - Any write method will throw ``std::runtime_error`` if the output doesn't fit - into the array. - - You can use one of the following typedefs for common character types: - - +--------------+---------------------------+ - | Type | Definition | - +==============+===========================+ - | ArrayWriter | BasicArrayWriter | - +--------------+---------------------------+ - | WArrayWriter | BasicArrayWriter | - +--------------+---------------------------+ - \endrst - */ -template -class BasicArrayWriter : public basic_writer { - private: - FixedBuffer buffer_; - - public: - BasicArrayWriter(Char *array, std::size_t size) - : basic_writer(buffer_), buffer_(array, size) {} + : basic_buffer(array, size) {} /** \rst - Constructs a :class:`fmt::BasicArrayWriter` object for *array* of the + Constructs a :class:`fmt::FixedBuffer` object for *array* of the size known at compile time. \endrst */ template - explicit BasicArrayWriter(Char (&array)[SIZE]) - : basic_writer(buffer_), buffer_(array, SIZE) {} -}; + explicit FixedBuffer(Char (&array)[SIZE]) : basic_buffer(array, SIZE) {} -typedef BasicArrayWriter ArrayWriter; -typedef BasicArrayWriter WArrayWriter; + protected: + FMT_API void grow(std::size_t size); +}; // Reports a system error without throwing an exception. // Can be used to report errors from destructors. diff --git a/test/format-test.cc b/test/format-test.cc index 02b99fd1..56ea7136 100644 --- a/test/format-test.cc +++ b/test/format-test.cc @@ -474,13 +474,6 @@ TEST(WriterTest, WWriter) { EXPECT_EQ(L"cafe", write_wstr(0xcafe, type='x')); } -TEST(ArrayWriterTest, Ctor) { - char array[10] = "garbage"; - fmt::ArrayWriter w(array, sizeof(array)); - EXPECT_EQ(0u, w.size()); - EXPECT_STREQ("", w.c_str()); -} - TEST(FormatToTest, FormatWithoutArgs) { fmt::internal::MemoryBuffer buffer; format_to(buffer, "test"); @@ -498,29 +491,6 @@ TEST(FormatToTest, Format) { EXPECT_EQ("part1part2", to_string(buffer)); } -TEST(ArrayWriterTest, CompileTimeSizeCtor) { - char array[10] = "garbage"; - fmt::ArrayWriter w(array); - EXPECT_EQ(0u, w.size()); - EXPECT_STREQ("", w.c_str()); - format_to(w.buffer(), "{:10}", 1); -} - -TEST(ArrayWriterTest, BufferOverflow) { - char array[10]; - fmt::ArrayWriter w(array, sizeof(array)); - format_to(w.buffer(), "{:10}", 1); - EXPECT_THROW_MSG(format_to(w.buffer(), "{}", 1), std::runtime_error, - "buffer overflow"); -} - -TEST(ArrayWriterTest, WChar) { - wchar_t array[10]; - fmt::WArrayWriter w(array); - format_to(w.buffer(), L"{}", 42); - EXPECT_EQ(L"42", w.str()); -} - TEST(FormatterTest, Escape) { EXPECT_EQ("{", format("{{")); EXPECT_EQ("before {", format("before {{")); diff --git a/test/util-test.cc b/test/util-test.cc index 9466c372..ab149555 100644 --- a/test/util-test.cc +++ b/test/util-test.cc @@ -213,19 +213,6 @@ TEST(BufferTest, Clear) { EXPECT_EQ(20u, buffer.capacity()); } -TEST(BufferTest, PushBack) { - int data[15]; - MockBuffer buffer(data, 10); - buffer.push_back(11); - EXPECT_EQ(11, buffer[0]); - EXPECT_EQ(1u, buffer.size()); - buffer.resize(10); - EXPECT_CALL(buffer, do_grow(11)); - buffer.push_back(22); - EXPECT_EQ(22, buffer[10]); - EXPECT_EQ(11u, buffer.size()); -} - TEST(BufferTest, Append) { char data[15]; MockBuffer buffer(data, 10); @@ -393,6 +380,29 @@ TEST(MemoryBufferTest, ExceptionInDeallocate) { EXPECT_CALL(alloc, deallocate(&mem2[0], 2 * size)); } +TEST(FixedBufferTest, Ctor) { + char array[10] = "garbage"; + fmt::FixedBuffer buffer(array, sizeof(array)); + EXPECT_EQ(0u, buffer.size()); + EXPECT_EQ(10u, buffer.capacity()); + EXPECT_EQ(array, buffer.data()); +} + +TEST(FixedBufferTest, CompileTimeSizeCtor) { + char array[10] = "garbage"; + fmt::FixedBuffer buffer(array); + EXPECT_EQ(0u, buffer.size()); + EXPECT_EQ(10u, buffer.capacity()); + EXPECT_EQ(array, buffer.data()); +} + +TEST(FixedBufferTest, BufferOverflow) { + char array[10]; + fmt::FixedBuffer buffer(array); + buffer.resize(10); + EXPECT_THROW_MSG(buffer.resize(11), std::runtime_error, "buffer overflow"); +} + TEST(UtilTest, Increment) { char s[10] = "123"; increment(s); From 87b691d80c46770d2159aa3100ba441336366228 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Fri, 17 Feb 2017 06:23:16 -0800 Subject: [PATCH 089/340] Merge StringWriter into StringBuffer --- fmt/string.h | 106 +++++++++++++++++--------------------------- test/string-test.cc | 31 ++++--------- 2 files changed, 50 insertions(+), 87 deletions(-) diff --git a/fmt/string.h b/fmt/string.h index 35154f47..eae6d8ab 100644 --- a/fmt/string.h +++ b/fmt/string.h @@ -14,11 +14,36 @@ namespace fmt { -namespace internal { +/** + \rst + This class template represents a character buffer backed by std::string. -// A buffer that stores data in ``std::string``. -template -class StringBuffer : public basic_buffer { + You can use one of the following typedefs for common character types + and the standard allocator: + + +----------------+------------------------------+ + | Type | Definition | + +================+==============================+ + | string_buffer | basic_string_buffer | + +----------------+------------------------------+ + | wstring_buffer | basic_string_buffer | + +----------------+------------------------------+ + + **Example**:: + + string_buffer out; + format_to(out, "The answer is {}", 42); + + This will write the following output to the ``out`` object: + + .. code-block:: none + + The answer is 42 + + The output can be moved to an ``std::string`` with ``out.move_to()``. + \endrst + */template +class basic_string_buffer : public basic_buffer { private: std::basic_string data_; @@ -30,7 +55,11 @@ class StringBuffer : public basic_buffer { } public: - // Moves the data to ``str`` clearing the buffer. + /** + \rst + Moves the buffer content to *str* clearing the buffer. + \endrst + */ void move_to(std::basic_string &str) { data_.resize(this->size_); str.swap(data_); @@ -38,64 +67,9 @@ class StringBuffer : public basic_buffer { this->ptr_ = 0; } }; -} // namespace internal -/** - \rst - This class template provides operations for formatting and writing data - into a character stream. The output is stored in ``std::string`` that grows - dynamically. - - You can use one of the following typedefs for common character types - and the standard allocator: - - +---------------+----------------------------+ - | Type | Definition | - +===============+============================+ - | StringWriter | BasicStringWriter | - +---------------+----------------------------+ - | WStringWriter | BasicStringWriter | - +---------------+----------------------------+ - - **Example**:: - - StringWriter out; - out << "The answer is " << 42 << "\n"; - - This will write the following output to the ``out`` object: - - .. code-block:: none - - The answer is 42 - - The output can be moved to an ``std::string`` with ``out.move_to()``. - \endrst - */ -template -class BasicStringWriter : public basic_writer { - private: - internal::StringBuffer buffer_; - - public: - /** - \rst - Constructs a :class:`fmt::BasicStringWriter` object. - \endrst - */ - BasicStringWriter() : basic_writer(buffer_) {} - - /** - \rst - Moves the buffer content to *str* clearing the buffer. - \endrst - */ - void move_to(std::basic_string &str) { - buffer_.move_to(str); - } -}; - -typedef BasicStringWriter StringWriter; -typedef BasicStringWriter WStringWriter; +typedef basic_string_buffer string_buffer; +typedef basic_string_buffer wstring_buffer; /** \rst @@ -110,9 +84,11 @@ typedef BasicStringWriter WStringWriter; */ template std::string to_string(const T &value) { - fmt::MemoryWriter w; - w.write(value); - return w.str(); + string_buffer buf; + basic_writer(buf).write(value); + std::string str; + buf.move_to(str); + return str; } } diff --git a/test/string-test.cc b/test/string-test.cc index b02867da..6d9dd12d 100644 --- a/test/string-test.cc +++ b/test/string-test.cc @@ -10,10 +10,10 @@ #include "fmt/string.h" #include "gtest/gtest.h" -using fmt::internal::StringBuffer; +using fmt::string_buffer; TEST(StringBufferTest, Empty) { - StringBuffer buffer; + string_buffer buffer; EXPECT_EQ(0, buffer.size()); EXPECT_EQ(0, buffer.capacity()); std::string data; @@ -25,7 +25,7 @@ TEST(StringBufferTest, Empty) { } TEST(StringBufferTest, Reserve) { - StringBuffer buffer; + string_buffer buffer; std::size_t capacity = std::string().capacity() + 10; buffer.reserve(capacity); EXPECT_EQ(0, buffer.size()); @@ -36,7 +36,7 @@ TEST(StringBufferTest, Reserve) { } TEST(StringBufferTest, Resize) { - StringBuffer buffer; + string_buffer buffer; std::size_t size = std::string().capacity() + 10; buffer.resize(size); EXPECT_EQ(size, buffer.size()); @@ -47,7 +47,7 @@ TEST(StringBufferTest, Resize) { } TEST(StringBufferTest, MoveTo) { - StringBuffer buffer; + string_buffer buffer; std::size_t size = std::string().capacity() + 10; buffer.resize(size); const char *p = &buffer[0]; @@ -58,25 +58,12 @@ TEST(StringBufferTest, MoveTo) { EXPECT_EQ(0, buffer.capacity()); } -TEST(StringWriterTest, MoveTo) { - fmt::StringWriter out; - out.write("The answer is "); - out.write(42); - out.write("\n"); - std::string s; - out.move_to(s); - EXPECT_EQ("The answer is 42\n", s); - EXPECT_EQ(0, out.size()); -} - -TEST(StringWriterTest, WString) { - fmt::WStringWriter out; - out.write("The answer is "); - out.write(42); - out.write("\n"); +TEST(StringBufferTest, WString) { + fmt::wstring_buffer out; + out.push_back(L'x'); std::wstring s; out.move_to(s); - EXPECT_EQ(L"The answer is 42\n", s); + EXPECT_EQ(L"x", s); } TEST(StringTest, ToString) { From e022c21ddc40fd3da840540f7c56f409f08465a8 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Fri, 17 Feb 2017 06:38:53 -0800 Subject: [PATCH 090/340] Fix windows build --- fmt/format.cc | 17 +++++++++-------- test/posix-mock-test.cc | 4 ++-- test/util-test.cc | 22 ++++++++++++---------- 3 files changed, 23 insertions(+), 20 deletions(-) diff --git a/fmt/format.cc b/fmt/format.cc index cd8a244c..222cc71f 100644 --- a/fmt/format.cc +++ b/fmt/format.cc @@ -341,16 +341,16 @@ FMT_FUNC int internal::UTF16ToUTF8::convert(WStringRef s) { FMT_FUNC void WindowsError::init( int err_code, CStringRef format_str, args args) { error_code_ = err_code; - MemoryWriter w; - internal::format_windows_error(w, err_code, vformat(format_str, args)); + internal::MemoryBuffer buffer; + internal::format_windows_error(buffer, err_code, vformat(format_str, args)); std::runtime_error &base = *this; - base = std::runtime_error(w.str()); + base = std::runtime_error(to_string(buffer)); } FMT_FUNC void internal::format_windows_error( - writer &out, int error_code, StringRef message) FMT_NOEXCEPT { + buffer &out, int error_code, StringRef message) FMT_NOEXCEPT { FMT_TRY { - MemoryBuffer buffer; + MemoryBuffer buffer; buffer.resize(INLINE_BUFFER_SIZE); for (;;) { wchar_t *system_message = &buffer[0]; @@ -361,9 +361,10 @@ FMT_FUNC void internal::format_windows_error( if (result != 0) { UTF16ToUTF8 utf8_message; if (utf8_message.convert(system_message) == ERROR_SUCCESS) { - out.write(message); - out.write(": "); - out.write(utf8_message); + basic_writer w(out); + w.write(message); + w.write(": "); + w.write(utf8_message); return; } break; diff --git a/test/posix-mock-test.cc b/test/posix-mock-test.cc index 3eaca21c..a87f8633 100644 --- a/test/posix-mock-test.cc +++ b/test/posix-mock-test.cc @@ -279,11 +279,11 @@ TEST(FileTest, Size) { EXPECT_GE(f.size(), 0); EXPECT_EQ(content.size(), static_cast(f.size())); #ifdef _WIN32 - fmt::MemoryWriter message; + fmt::internal::MemoryBuffer message; fmt::internal::format_windows_error( message, ERROR_ACCESS_DENIED, "cannot get file size"); fstat_sim = ERROR; - EXPECT_THROW_MSG(f.size(), fmt::WindowsError, message.str()); + EXPECT_THROW_MSG(f.size(), fmt::WindowsError, fmt::to_string(message)); fstat_sim = NONE; #else f.close(); diff --git a/test/util-test.cc b/test/util-test.cc index ab149555..370a704f 100644 --- a/test/util-test.cc +++ b/test/util-test.cc @@ -667,7 +667,7 @@ template void check_utf_conversion_error( const char *message, fmt::BasicStringRef str = fmt::BasicStringRef(0, 0)) { - fmt::MemoryWriter out; + fmt::internal::MemoryBuffer out; fmt::internal::format_windows_error(out, ERROR_INVALID_PARAMETER, message); fmt::SystemError error(0, ""); try { @@ -676,7 +676,7 @@ void check_utf_conversion_error( error = e; } EXPECT_EQ(ERROR_INVALID_PARAMETER, error.error_code()); - EXPECT_EQ(out.str(), error.what()); + EXPECT_EQ(fmt::to_string(out), error.what()); } TEST(UtilTest, UTF16ToUTF8Error) { @@ -752,16 +752,17 @@ TEST(UtilTest, FormatWindowsError) { reinterpret_cast(&message), 0, 0); fmt::internal::UTF16ToUTF8 utf8_message(message); LocalFree(message); - fmt::MemoryWriter actual_message; + fmt::internal::MemoryBuffer actual_message; fmt::internal::format_windows_error( actual_message, ERROR_FILE_EXISTS, "test"); EXPECT_EQ(fmt::format("test: {}", utf8_message.str()), - actual_message.str()); + fmt::to_string(actual_message)); actual_message.clear(); fmt::internal::format_windows_error( actual_message, ERROR_FILE_EXISTS, fmt::StringRef(0, std::numeric_limits::max())); - EXPECT_EQ(fmt::format("error {}", ERROR_FILE_EXISTS), actual_message.str()); + EXPECT_EQ(fmt::format("error {}", ERROR_FILE_EXISTS), + fmt::to_string(actual_message)); } TEST(UtilTest, FormatLongWindowsError) { @@ -778,11 +779,11 @@ TEST(UtilTest, FormatLongWindowsError) { } fmt::internal::UTF16ToUTF8 utf8_message(message); LocalFree(message); - fmt::MemoryWriter actual_message; + fmt::internal::MemoryBuffer actual_message; fmt::internal::format_windows_error( actual_message, provisioning_not_allowed, "test"); EXPECT_EQ(fmt::format("test: {}", utf8_message.str()), - actual_message.str()); + fmt::to_string(actual_message)); } TEST(UtilTest, WindowsError) { @@ -791,11 +792,12 @@ TEST(UtilTest, WindowsError) { } TEST(UtilTest, ReportWindowsError) { - fmt::MemoryWriter out; + fmt::internal::MemoryBuffer out; fmt::internal::format_windows_error(out, ERROR_FILE_EXISTS, "test error"); - out.write('\n'); + out.push_back('\n'); EXPECT_WRITE(stderr, - fmt::report_windows_error(ERROR_FILE_EXISTS, "test error"), out.str()); + fmt::report_windows_error(ERROR_FILE_EXISTS, "test error"), + fmt::to_string(out)); } #endif // _WIN32 From 50e716737d2dded9d89ba98b31469a074c1badfc Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sat, 18 Feb 2017 06:52:52 -0800 Subject: [PATCH 091/340] StringRef -> string_view, LongLong -> long_long --- fmt/format.cc | 24 ++--- fmt/format.h | 191 ++++++++++++++++++--------------------- fmt/ostream.h | 2 +- fmt/posix.cc | 6 +- fmt/posix.h | 2 +- fmt/printf.h | 4 +- test/format-impl-test.cc | 6 +- test/format-test.cc | 18 ++-- test/gtest-extra.cc | 2 +- test/gtest-extra.h | 2 +- test/posix-mock-test.cc | 4 +- test/posix-test.cc | 2 +- test/printf-test.cc | 40 ++++---- test/util-test.cc | 44 ++++----- 14 files changed, 167 insertions(+), 180 deletions(-) diff --git a/fmt/format.cc b/fmt/format.cc index 222cc71f..563a8f7d 100644 --- a/fmt/format.cc +++ b/fmt/format.cc @@ -106,7 +106,7 @@ inline int fmt_snprintf(char *buffer, size_t size, const char *format, ...) { const char RESET_COLOR[] = "\x1b[0m"; -typedef void (*FormatFunc)(buffer &, int, StringRef); +typedef void (*FormatFunc)(buffer &, int, string_view); // Portable thread-safe version of strerror. // Sets buffer to point to a string describing the error code. @@ -177,7 +177,7 @@ int safe_strerror( } void format_error_code(buffer &out, int error_code, - StringRef message) FMT_NOEXCEPT { + string_view message) FMT_NOEXCEPT { // Report error code making sure that the output fits into // INLINE_BUFFER_SIZE to avoid dynamic memory allocation and potential // bad_alloc. @@ -204,7 +204,7 @@ void format_error_code(buffer &out, int error_code, } void report_error(FormatFunc func, int error_code, - StringRef message) FMT_NOEXCEPT { + string_view message) FMT_NOEXCEPT { internal::MemoryBuffer full_message; func(full_message, error_code, message); // Use Writer::data instead of Writer::c_str to avoid potential memory @@ -279,10 +279,10 @@ template const uint64_t internal::BasicData::POWERS_OF_10_64[] = { 0, FMT_POWERS_OF_10(1), - FMT_POWERS_OF_10(ULongLong(1000000000)), + FMT_POWERS_OF_10(ulong_long(1000000000)), // Multiply several constants instead of using a single long long constant // to avoid warnings about C++98 not supporting long long. - ULongLong(1000000000) * ULongLong(1000000000) * 10 + ulong_long(1000000000) * ulong_long(1000000000) * 10 }; FMT_FUNC void internal::report_unknown_type(char code, const char *type) { @@ -298,7 +298,7 @@ FMT_FUNC void internal::report_unknown_type(char code, const char *type) { #if FMT_USE_WINDOWS_H -FMT_FUNC internal::UTF8ToUTF16::UTF8ToUTF16(StringRef s) { +FMT_FUNC internal::UTF8ToUTF16::UTF8ToUTF16(string_view s) { static const char ERROR_MSG[] = "cannot convert string from UTF-8 to UTF-16"; if (s.size() > INT_MAX) FMT_THROW(WindowsError(ERROR_INVALID_PARAMETER, ERROR_MSG)); @@ -315,14 +315,14 @@ FMT_FUNC internal::UTF8ToUTF16::UTF8ToUTF16(StringRef s) { buffer_[length] = 0; } -FMT_FUNC internal::UTF16ToUTF8::UTF16ToUTF8(WStringRef s) { +FMT_FUNC internal::UTF16ToUTF8::UTF16ToUTF8(wstring_view s) { if (int error_code = convert(s)) { FMT_THROW(WindowsError(error_code, "cannot convert string from UTF-16 to UTF-8")); } } -FMT_FUNC int internal::UTF16ToUTF8::convert(WStringRef s) { +FMT_FUNC int internal::UTF16ToUTF8::convert(wstring_view s) { if (s.size() > INT_MAX) return ERROR_INVALID_PARAMETER; int s_size = static_cast(s.size()); @@ -348,7 +348,7 @@ FMT_FUNC void WindowsError::init( } FMT_FUNC void internal::format_windows_error( - buffer &out, int error_code, StringRef message) FMT_NOEXCEPT { + buffer &out, int error_code, string_view message) FMT_NOEXCEPT { FMT_TRY { MemoryBuffer buffer; buffer.resize(INLINE_BUFFER_SIZE); @@ -380,7 +380,7 @@ FMT_FUNC void internal::format_windows_error( #endif // FMT_USE_WINDOWS_H FMT_FUNC void format_system_error( - buffer &out, int error_code, StringRef message) FMT_NOEXCEPT { + buffer &out, int error_code, string_view message) FMT_NOEXCEPT { FMT_TRY { internal::MemoryBuffer buffer; buffer.resize(internal::INLINE_BUFFER_SIZE); @@ -408,14 +408,14 @@ void FixedBuffer::grow(std::size_t) { } FMT_FUNC void report_system_error( - int error_code, fmt::StringRef message) FMT_NOEXCEPT { + int error_code, fmt::string_view message) FMT_NOEXCEPT { // 'fmt::' is for bcc32. report_error(format_system_error, error_code, message); } #if FMT_USE_WINDOWS_H FMT_FUNC void report_windows_error( - int error_code, fmt::StringRef message) FMT_NOEXCEPT { + int error_code, fmt::string_view message) FMT_NOEXCEPT { // 'fmt::' is for bcc32. report_error(internal::format_windows_error, error_code, message); } diff --git a/fmt/format.h b/fmt/format.h index fff6adfa..3eb8b1fe 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -82,15 +82,19 @@ typedef __int64 intmax_t; # define FMT_GCC_EXTENSION __extension__ # if FMT_GCC_VERSION >= 406 # pragma GCC diagnostic push + // Disable the warning about "long long" which is sometimes reported even // when using __extension__. # pragma GCC diagnostic ignored "-Wlong-long" + // Disable the warning about declaration shadowing because it affects too // many valid cases. # pragma GCC diagnostic ignored "-Wshadow" + // Disable the warning about implicit conversions that may change the sign of // an integer; silencing it otherwise would require many explicit casts. # pragma GCC diagnostic ignored "-Wsign-conversion" + # endif # if __cplusplus >= 201103L || defined __GXX_EXPERIMENTAL_CXX0X__ # define FMT_HAS_GXX_CXX11 1 @@ -357,8 +361,8 @@ namespace fmt { // Fix the warning about long long on older versions of GCC // that don't support the diagnostic pragma. -FMT_GCC_EXTENSION typedef long long LongLong; -FMT_GCC_EXTENSION typedef unsigned long long ULongLong; +FMT_GCC_EXTENSION typedef long long long_long; +FMT_GCC_EXTENSION typedef unsigned long long ulong_long; #if FMT_USE_RVALUE_REFERENCES using std::move; @@ -390,39 +394,21 @@ typedef basic_context wcontext; /** \rst - A string reference. It can be constructed from a C string or ``std::string``. - - You can use one of the following typedefs for common character types: - - +------------+-------------------------+ - | Type | Definition | - +============+=========================+ - | StringRef | BasicStringRef | - +------------+-------------------------+ - | WStringRef | BasicStringRef | - +------------+-------------------------+ - - This class is most useful as a parameter type to allow passing - different types of strings to a function, for example:: - - template - std::string format(StringRef format_str, const Args & ... args); - - format("{}", 42); - format(std::string("{}"), 42); + An implementation of ``std::basic_string_view`` for pre-C++17. It provides a + subset of the API. \endrst */ template -class BasicStringRef { +class basic_string_view { private: const Char *data_; std::size_t size_; public: - BasicStringRef() : data_(0), size_(0) {} + basic_string_view() : data_(0), size_(0) {} /** Constructs a string reference object from a C string and a size. */ - BasicStringRef(const Char *s, std::size_t size) : data_(s), size_(size) {} + basic_string_view(const Char *s, std::size_t size) : data_(s), size_(size) {} /** \rst @@ -430,7 +416,7 @@ class BasicStringRef { the size with ``std::char_traits::length``. \endrst */ - BasicStringRef(const Char *s) + basic_string_view(const Char *s) : data_(s), size_(std::char_traits::length(s)) {} /** @@ -438,7 +424,7 @@ class BasicStringRef { Constructs a string reference from an ``std::string`` object. \endrst */ - BasicStringRef(const std::basic_string &s) + basic_string_view(const std::basic_string &s) : data_(s.c_str()), size_(s.size()) {} /** @@ -457,7 +443,7 @@ class BasicStringRef { std::size_t size() const { return size_; } // Lexicographically compare this string reference to other. - int compare(BasicStringRef other) const { + int compare(basic_string_view other) const { std::size_t size = size_ < other.size_ ? size_ : other.size_; int result = std::char_traits::compare(data_, other.data_, size); if (result == 0) @@ -465,28 +451,28 @@ class BasicStringRef { return result; } - friend bool operator==(BasicStringRef lhs, BasicStringRef rhs) { + friend bool operator==(basic_string_view lhs, basic_string_view rhs) { return lhs.compare(rhs) == 0; } - friend bool operator!=(BasicStringRef lhs, BasicStringRef rhs) { + friend bool operator!=(basic_string_view lhs, basic_string_view rhs) { return lhs.compare(rhs) != 0; } - friend bool operator<(BasicStringRef lhs, BasicStringRef rhs) { + friend bool operator<(basic_string_view lhs, basic_string_view rhs) { return lhs.compare(rhs) < 0; } - friend bool operator<=(BasicStringRef lhs, BasicStringRef rhs) { + friend bool operator<=(basic_string_view lhs, basic_string_view rhs) { return lhs.compare(rhs) <= 0; } - friend bool operator>(BasicStringRef lhs, BasicStringRef rhs) { + friend bool operator>(basic_string_view lhs, basic_string_view rhs) { return lhs.compare(rhs) > 0; } - friend bool operator>=(BasicStringRef lhs, BasicStringRef rhs) { + friend bool operator>=(basic_string_view lhs, basic_string_view rhs) { return lhs.compare(rhs) >= 0; } }; -typedef BasicStringRef StringRef; -typedef BasicStringRef WStringRef; +typedef basic_string_view string_view; +typedef basic_string_view wstring_view; /** \rst @@ -559,7 +545,7 @@ FMT_SPECIALIZE_MAKE_UNSIGNED(signed char, unsigned char); FMT_SPECIALIZE_MAKE_UNSIGNED(short, unsigned short); FMT_SPECIALIZE_MAKE_UNSIGNED(int, unsigned); FMT_SPECIALIZE_MAKE_UNSIGNED(long, unsigned long); -FMT_SPECIALIZE_MAKE_UNSIGNED(LongLong, ULongLong); +FMT_SPECIALIZE_MAKE_UNSIGNED(long_long, ulong_long); // Casts nonnegative integer to unsigned. template @@ -895,13 +881,13 @@ struct NoThousandsSep { // A functor that adds a thousands separator. class ThousandsSep { private: - fmt::StringRef sep_; + fmt::string_view sep_; // Index of a decimal digit with the least significant digit having index 0. unsigned digit_index_; public: - explicit ThousandsSep(fmt::StringRef sep) : sep_(sep), digit_index_(0) {} + explicit ThousandsSep(fmt::string_view sep) : sep_(sep), digit_index_(0) {} template void operator()(Char *&buffer) { @@ -962,8 +948,8 @@ class UTF8ToUTF16 { MemoryBuffer buffer_; public: - FMT_API explicit UTF8ToUTF16(StringRef s); - operator WStringRef() const { return WStringRef(&buffer_[0], size()); } + FMT_API explicit UTF8ToUTF16(string_view s); + operator wstring_view() const { return wstring_view(&buffer_[0], size()); } size_t size() const { return buffer_.size() - 1; } const wchar_t *c_str() const { return &buffer_[0]; } std::wstring str() const { return std::wstring(&buffer_[0], size()); } @@ -977,8 +963,8 @@ class UTF16ToUTF8 { public: UTF16ToUTF8() {} - FMT_API explicit UTF16ToUTF8(WStringRef s); - operator StringRef() const { return StringRef(&buffer_[0], size()); } + FMT_API explicit UTF16ToUTF8(wstring_view s); + operator string_view() const { return string_view(&buffer_[0], size()); } size_t size() const { return buffer_.size() - 1; } const char *c_str() const { return &buffer_[0]; } std::string str() const { return std::string(&buffer_[0], size()); } @@ -986,11 +972,11 @@ class UTF16ToUTF8 { // Performs conversion returning a system error code instead of // throwing exception on conversion error. This method may still throw // in case of memory allocation error. - FMT_API int convert(WStringRef s); + FMT_API int convert(wstring_view s); }; FMT_API void format_windows_error(fmt::buffer &out, int error_code, - fmt::StringRef message) FMT_NOEXCEPT; + fmt::string_view message) FMT_NOEXCEPT; #endif template @@ -1032,7 +1018,7 @@ template T &get(); // These are non-members to workaround an overload resolution bug in bcc32. -Yes &convert(fmt::ULongLong); +Yes &convert(fmt::ulong_long); No &convert(...); template @@ -1119,8 +1105,8 @@ template <> constexpr Type gettype() { return sizeof(unsigned long) == sizeof(unsigned) ? UINT : ULONG_LONG; } -template <> constexpr Type gettype() { return LONG_LONG; } -template <> constexpr Type gettype() { return ULONG_LONG; } +template <> constexpr Type gettype() { return LONG_LONG; } +template <> constexpr Type gettype() { return ULONG_LONG; } template <> constexpr Type gettype() { return DOUBLE; } template <> constexpr Type gettype() { return DOUBLE; } template <> constexpr Type gettype() { return LONG_DOUBLE; } @@ -1139,12 +1125,12 @@ template <> constexpr Type gettype() { return CSTRING; } template <> constexpr Type gettype() { return CSTRING; } template <> constexpr Type gettype() { return CSTRING; } template <> constexpr Type gettype() { return STRING; } -template <> constexpr Type gettype() { return STRING; } +template <> constexpr Type gettype() { return STRING; } template <> constexpr Type gettype() { return CSTRING; } template <> constexpr Type gettype() { return TSTRING; } template <> constexpr Type gettype() { return TSTRING; } template <> constexpr Type gettype() { return TSTRING; } -template <> constexpr Type gettype() { return TSTRING; } +template <> constexpr Type gettype() { return TSTRING; } template <> constexpr Type gettype() { return POINTER; } template <> constexpr Type gettype() { return POINTER; } @@ -1158,8 +1144,8 @@ class value { union { int int_value; unsigned uint_value; - LongLong long_long_value; - ULongLong ulong_long_value; + long_long long_long_value; + ulong_long ulong_long_value; double double_value; long double long_double_value; const void *pointer; @@ -1193,14 +1179,14 @@ class value { value(typename WCharHelper::Unsupported); value(typename WCharHelper::Unsupported); value(typename WCharHelper::Unsupported); - value(typename WCharHelper::Unsupported); + value(typename WCharHelper::Unsupported); - void set_string(StringRef str) { + void set_string(string_view str) { this->string.value = str.data(); this->string.size = str.size(); } - void set_string(WStringRef str) { + void set_string(wstring_view str) { this->tstring.value = str.data(); this->tstring.size = str.size(); } @@ -1247,8 +1233,8 @@ class value { this->ulong_long_value = value; } - FMT_MAKE_VALUE(LongLong, long_long_value, LONG_LONG) - FMT_MAKE_VALUE(ULongLong, ulong_long_value, ULONG_LONG) + FMT_MAKE_VALUE(long_long, long_long_value, LONG_LONG) + FMT_MAKE_VALUE(ulong_long, ulong_long_value, ULONG_LONG) FMT_MAKE_VALUE(float, double_value, DOUBLE) FMT_MAKE_VALUE(double, double_value, DOUBLE) FMT_MAKE_VALUE(long double, long_double_value, LONG_DOUBLE) @@ -1277,7 +1263,7 @@ class value { FMT_MAKE_VALUE(unsigned char *, ustring.value, CSTRING) FMT_MAKE_VALUE(const unsigned char *, ustring.value, CSTRING) FMT_MAKE_STR_VALUE(const std::string &, STRING) - FMT_MAKE_STR_VALUE(StringRef, STRING) + FMT_MAKE_STR_VALUE(string_view, STRING) FMT_MAKE_VALUE_(CStringRef, string.value, CSTRING, value.c_str()) #define FMT_MAKE_WSTR_VALUE(Type, TYPE) \ @@ -1289,7 +1275,7 @@ class value { FMT_MAKE_WSTR_VALUE(wchar_t *, TSTRING) FMT_MAKE_WSTR_VALUE(const wchar_t *, TSTRING) FMT_MAKE_WSTR_VALUE(const std::wstring &, TSTRING) - FMT_MAKE_WSTR_VALUE(WStringRef, TSTRING) + FMT_MAKE_WSTR_VALUE(wstring_view, TSTRING) FMT_MAKE_VALUE(void *, pointer, POINTER) FMT_MAKE_VALUE(const void *, pointer, POINTER) @@ -1406,9 +1392,9 @@ typename std::result_of::type case internal::CSTRING: return vis(arg.value_.string.value); case internal::STRING: - return vis(StringRef(arg.value_.string.value, arg.value_.string.size)); + return vis(string_view(arg.value_.string.value, arg.value_.string.size)); case internal::TSTRING: - return vis(BasicStringRef( + return vis(basic_string_view( arg.value_.tstring.value, arg.value_.tstring.size)); case internal::POINTER: return vis(arg.value_.pointer); @@ -1436,12 +1422,12 @@ template struct LConvCheck { // We check if ``lconv`` contains ``thousands_sep`` because on Android // ``lconv`` is stubbed as an empty struct. template -inline StringRef thousands_sep( +inline string_view thousands_sep( LConv *lc, LConvCheck = 0) { return lc->thousands_sep; } -inline fmt::StringRef thousands_sep(...) { return ""; } +inline fmt::string_view thousands_sep(...) { return ""; } #define FMT_CONCAT(a, b) a##b @@ -1476,10 +1462,10 @@ template struct NamedArg : basic_arg { typedef typename Context::char_type Char; - BasicStringRef name; + basic_string_view name; template - NamedArg(BasicStringRef argname, const T &value) + NamedArg(basic_string_view argname, const T &value) : basic_arg(make_arg(value)), name(argname) {} }; @@ -1788,7 +1774,7 @@ class ArgMap { private: typedef typename Context::char_type Char; typedef std::vector< - std::pair, basic_arg > > MapType; + std::pair, basic_arg > > MapType; typedef typename MapType::value_type Pair; MapType map_; @@ -1797,7 +1783,7 @@ class ArgMap { void init(const basic_args &args); const basic_arg - *find(const fmt::BasicStringRef &name) const { + *find(const fmt::basic_string_view &name) const { // The list is unsorted, so just return the first matching name. for (typename MapType::const_iterator it = map_.begin(), end = map_.end(); it != end; ++it) { @@ -1871,7 +1857,7 @@ class ArgFormatterBase { } template - void write_str(BasicStringRef value, + void write_str(basic_string_view value, typename EnableIf< std::is_same::value && std::is_same::value, int>::type = 0) { @@ -1879,7 +1865,7 @@ class ArgFormatterBase { } template - void write_str(BasicStringRef value, + void write_str(basic_string_view value, typename EnableIf< !std::is_same::value || !std::is_same::value, int>::type = 0) { @@ -1891,12 +1877,12 @@ class ArgFormatterBase { format_specs &spec() { return spec_; } void write(bool value) { - writer_.write_str(StringRef(value ? "true" : "false"), spec_); + writer_.write_str(string_view(value ? "true" : "false"), spec_); } void write(const char *value) { writer_.write_str( - StringRef(value, value != 0 ? std::strlen(value) : 0), spec_); + string_view(value, value != 0 ? std::strlen(value) : 0), spec_); } public: @@ -1959,11 +1945,11 @@ class ArgFormatterBase { write(value); } - void operator()(StringRef value) { + void operator()(string_view value) { writer_.write_str(value, spec_); } - void operator()(BasicStringRef value) { + void operator()(basic_string_view value) { write_str(value); } @@ -2078,7 +2064,7 @@ class basic_context : // Checks if manual indexing is used and returns the argument with // specified name. - format_arg get_arg(BasicStringRef name, const char *&error); + format_arg get_arg(basic_string_view name, const char *&error); public: /** @@ -2156,7 +2142,7 @@ class SystemError : public internal::RuntimeError { \endrst */ FMT_API void format_system_error(fmt::buffer &out, int error_code, - fmt::StringRef message) FMT_NOEXCEPT; + fmt::string_view message) FMT_NOEXCEPT; namespace internal { // Named format specifier. @@ -2268,7 +2254,7 @@ class basic_writer { CharPtr write_str(const StrChar *s, std::size_t size, const AlignSpec &spec); template - void write_str(BasicStringRef str, const format_specs &spec); + void write_str(basic_string_view str, const format_specs &spec); // This following methods are private to disallow writing wide characters // and strings to a char buffer. If you want to print a wide string as a @@ -2343,7 +2329,7 @@ class basic_writer { void write(long value) { write_decimal(value); } - void write(LongLong value) { + void write(long_long value) { write_decimal(value); } @@ -2388,18 +2374,19 @@ class basic_writer { Writes *value* to the buffer. \endrst */ - void write(fmt::BasicStringRef value) { + void write(fmt::basic_string_view value) { const Char *str = value.data(); buffer_.append(str, str + value.size()); } - void write(typename internal::WCharHelper::Supported value) { + void write( + typename internal::WCharHelper::Supported value) { const char *str = value.data(); buffer_.append(str, str + value.size()); } template - void write(BasicStringRef str, FormatSpecs... specs) { + void write(basic_string_view str, FormatSpecs... specs) { write_str(str, format_specs(specs...)); } @@ -2434,7 +2421,7 @@ typename basic_writer::CharPtr basic_writer::write_str( template template void basic_writer::write_str( - BasicStringRef s, const format_specs &spec) { + basic_string_view s, const format_specs &spec) { // Check if StrChar is convertible to Char. internal::CharTraits::convert(StrChar()); if (spec.type_ && spec.type_ != 's') @@ -2606,7 +2593,7 @@ void basic_writer::write_int(T value, Spec spec) { } case 'n': { unsigned num_digits = internal::count_digits(abs_value); - fmt::StringRef sep = internal::thousands_sep(std::localeconv()); + fmt::string_view sep = internal::thousands_sep(std::localeconv()); unsigned size = static_cast( num_digits + sep.size() * ((num_digits - 1) / 3)); CharPtr p = prepare_int_buffer(size, spec, prefix, prefix_size) + 1; @@ -2880,7 +2867,7 @@ class FixedBuffer : public basic_buffer { // Reports a system error without throwing an exception. // Can be used to report errors from destructors. FMT_API void report_system_error(int error_code, - StringRef message) FMT_NOEXCEPT; + string_view message) FMT_NOEXCEPT; #if FMT_USE_WINDOWS_H @@ -2927,7 +2914,7 @@ class WindowsError : public SystemError { // Reports a Windows error without throwing an exception. // Can be used to report errors from destructors. FMT_API void report_windows_error(int error_code, - StringRef message) FMT_NOEXCEPT; + string_view message) FMT_NOEXCEPT; #endif @@ -3041,12 +3028,12 @@ class FormatInt { private: // Buffer should be large enough to hold all digits (digits10 + 1), // a sign and a null character. - enum {BUFFER_SIZE = std::numeric_limits::digits10 + 3}; + enum {BUFFER_SIZE = std::numeric_limits::digits10 + 3}; mutable char buffer_[BUFFER_SIZE]; char *str_; // Formats value in reverse and returns the number of digits. - char *format_decimal(ULongLong value) { + char *format_decimal(ulong_long value) { char *buffer_end = buffer_ + BUFFER_SIZE - 1; while (value >= 100) { // Integer division is slow so do it for a group of two digits instead @@ -3067,8 +3054,8 @@ class FormatInt { return buffer_end; } - void FormatSigned(LongLong value) { - ULongLong abs_value = static_cast(value); + void FormatSigned(long_long value) { + ulong_long abs_value = static_cast(value); bool negative = value < 0; if (negative) abs_value = 0 - abs_value; @@ -3080,10 +3067,10 @@ class FormatInt { public: explicit FormatInt(int value) { FormatSigned(value); } explicit FormatInt(long value) { FormatSigned(value); } - explicit FormatInt(LongLong value) { FormatSigned(value); } + explicit FormatInt(long_long value) { FormatSigned(value); } explicit FormatInt(unsigned value) : str_(format_decimal(value)) {} explicit FormatInt(unsigned long value) : str_(format_decimal(value)) {} - explicit FormatInt(ULongLong value) : str_(format_decimal(value)) {} + explicit FormatInt(ulong_long value) : str_(format_decimal(value)) {} /** Returns the number of characters written to the output buffer. */ std::size_t size() const { @@ -3150,22 +3137,22 @@ inline void format_decimal(char *&buffer, T value) { \endrst */ template -inline internal::NamedArg arg(StringRef name, const T &arg) { +inline internal::NamedArg arg(string_view name, const T &arg) { return internal::NamedArg(name, arg); } template -inline internal::NamedArg arg(WStringRef name, const T &arg) { +inline internal::NamedArg arg(wstring_view name, const T &arg) { return internal::NamedArg(name, arg); } // The following two functions are deleted intentionally to disable // nested named arguments as in ``format("{}", arg("a", arg("b", 42)))``. template -void arg(StringRef, const internal::NamedArg&) +void arg(string_view, const internal::NamedArg&) FMT_DELETED_OR_UNDEFINED; template -void arg(WStringRef, const internal::NamedArg&) +void arg(wstring_view, const internal::NamedArg&) FMT_DELETED_OR_UNDEFINED; } @@ -3269,7 +3256,7 @@ struct IsInteger { struct WidthHandler { template - typename std::enable_if::value, ULongLong>::type + typename std::enable_if::value, ulong_long>::type operator()(T value) { if (is_negative(value)) FMT_THROW(format_error("negative width")); @@ -3277,7 +3264,7 @@ struct WidthHandler { } template - typename std::enable_if::value, ULongLong>::type + typename std::enable_if::value, ulong_long>::type operator()(T value) { FMT_THROW(format_error("width is not integer")); return 0; @@ -3286,7 +3273,7 @@ struct WidthHandler { struct PrecisionHandler { template - typename std::enable_if::value, ULongLong>::type + typename std::enable_if::value, ulong_long>::type operator()(T value) { if (is_negative(value)) FMT_THROW(format_error("negative precision")); @@ -3294,7 +3281,7 @@ struct PrecisionHandler { } template - typename std::enable_if::value, ULongLong>::type + typename std::enable_if::value, ulong_long>::type operator()(T value) { FMT_THROW(format_error("precision is not integer")); return 0; @@ -3305,7 +3292,7 @@ struct PrecisionHandler { template inline typename basic_context::format_arg basic_context::get_arg( - BasicStringRef name, const char *&error) { + basic_string_view name, const char *&error) { if (this->check_no_auto_index(error)) { map_.init(this->args()); if (const format_arg *arg = map_.find(name)) @@ -3336,7 +3323,7 @@ inline typename basic_context::format_arg c = *++s; } while (internal::is_name_start(c) || ('0' <= c && c <= '9')); const char *error = 0; - format_arg arg = get_arg(BasicStringRef(start, s - start), error); + format_arg arg = get_arg(basic_string_view(start, s - start), error); if (error) FMT_THROW(format_error(error)); return arg; @@ -3424,7 +3411,7 @@ void do_format_arg(basic_buffer &buffer, basic_arg arg, auto width_arg = ctx.parse_arg_id(); if (*s++ != '}') FMT_THROW(format_error("invalid format string")); - ULongLong width = visit(internal::WidthHandler(), width_arg); + ulong_long width = visit(internal::WidthHandler(), width_arg); if (width > (std::numeric_limits::max)()) FMT_THROW(format_error("number is too big")); spec.width_ = static_cast(width); @@ -3441,7 +3428,7 @@ void do_format_arg(basic_buffer &buffer, basic_arg arg, auto precision_arg = ctx.parse_arg_id(); if (*s++ != '}') FMT_THROW(format_error("invalid format string")); - ULongLong precision = + ulong_long precision = visit(internal::PrecisionHandler(), precision_arg); if (precision > (std::numeric_limits::max)()) FMT_THROW(format_error("number is too big")); diff --git a/fmt/ostream.h b/fmt/ostream.h index 528ee16a..f99b9a71 100644 --- a/fmt/ostream.h +++ b/fmt/ostream.h @@ -85,7 +85,7 @@ void format_value(basic_buffer &buf, const T &value, basic_context &ctx) { internal::MemoryBuffer buffer; internal::format_value(buffer, value); - BasicStringRef str(buffer.data(), buffer.size()); + basic_string_view str(buffer.data(), buffer.size()); do_format_arg< ArgFormatter >( buf, internal::make_arg< basic_context >(str), ctx); } diff --git a/fmt/posix.cc b/fmt/posix.cc index bd25f61a..260f6341 100644 --- a/fmt/posix.cc +++ b/fmt/posix.cc @@ -124,7 +124,7 @@ void fmt::File::close() { throw SystemError(errno, "cannot close file"); } -fmt::LongLong fmt::File::size() const { +fmt::long_long fmt::File::size() const { #ifdef _WIN32 // Use GetFileSize instead of GetFileSizeEx for the case when _WIN32_WINNT // is less than 0x0500 as is the case with some default MinGW builds. @@ -137,14 +137,14 @@ fmt::LongLong fmt::File::size() const { if (error != NO_ERROR) throw WindowsError(GetLastError(), "cannot get file size"); } - fmt::ULongLong long_size = size_upper; + fmt::ulong_long long_size = size_upper; return (long_size << sizeof(DWORD) * CHAR_BIT) | size_lower; #else typedef struct stat Stat; Stat file_stat = Stat(); if (FMT_POSIX_CALL(fstat(fd_, &file_stat)) == -1) throw SystemError(errno, "cannot get file attributes"); - FMT_STATIC_ASSERT(sizeof(fmt::LongLong) >= sizeof(file_stat.st_size), + FMT_STATIC_ASSERT(sizeof(fmt::long_long) >= sizeof(file_stat.st_size), "return type of File::size is not large enough"); return file_stat.st_size; #endif diff --git a/fmt/posix.h b/fmt/posix.h index afc69584..45cf3c7c 100644 --- a/fmt/posix.h +++ b/fmt/posix.h @@ -274,7 +274,7 @@ class File { // Returns the file size. The size has signed type for consistency with // stat::st_size. - LongLong size() const; + long_long size() const; // Attempts to read count bytes from the file into the specified buffer. std::size_t read(void *buffer, std::size_t count); diff --git a/fmt/printf.h b/fmt/printf.h index 0b77ae34..a13684c5 100644 --- a/fmt/printf.h +++ b/fmt/printf.h @@ -119,7 +119,7 @@ class ArgConverter { // glibc's printf doesn't sign extend arguments of smaller types: // std::printf("%lld", -42); // prints "4294967254" // but we don't have to do the same because it's a UB. - arg_ = internal::make_arg(static_cast(value)); + arg_ = internal::make_arg(static_cast(value)); } else { arg_ = internal::make_arg( static_cast::Type>(value)); @@ -459,7 +459,7 @@ void printf_context::format(basic_buffer &buffer) { break; case 'l': if (*s == 'l') - convert_arg(arg, *++s); + convert_arg(arg, *++s); else convert_arg(arg, *s); break; diff --git a/test/format-impl-test.cc b/test/format-impl-test.cc index 6c86a484..9102db03 100644 --- a/test/format-impl-test.cc +++ b/test/format-impl-test.cc @@ -55,11 +55,11 @@ struct ValueExtractor { }; TEST(FormatTest, ArgConverter) { - fmt::LongLong value = std::numeric_limits::max(); + fmt::long_long value = std::numeric_limits::max(); auto arg = fmt::internal::make_arg(value); visit(fmt::internal::ArgConverter< - fmt::LongLong, fmt::context>(arg, 'd'), arg); - EXPECT_EQ(value, visit(ValueExtractor(), arg)); + fmt::long_long, fmt::context>(arg, 'd'), arg); + EXPECT_EQ(value, visit(ValueExtractor(), arg)); } TEST(FormatTest, FormatNegativeNaN) { diff --git a/test/format-test.cc b/test/format-test.cc index 56ea7136..bf2b153e 100644 --- a/test/format-test.cc +++ b/test/format-test.cc @@ -73,7 +73,7 @@ using std::size_t; using fmt::basic_writer; using fmt::format; using fmt::format_error; -using fmt::StringRef; +using fmt::string_view; using fmt::CStringRef; using fmt::MemoryWriter; using fmt::WMemoryWriter; @@ -148,16 +148,16 @@ struct WriteChecker { EXPECT_PRED_FORMAT1(WriteChecker(), value) } // namespace -TEST(StringRefTest, Ctor) { - EXPECT_STREQ("abc", StringRef("abc").data()); - EXPECT_EQ(3u, StringRef("abc").size()); +TEST(StringViewTest, Ctor) { + EXPECT_STREQ("abc", string_view("abc").data()); + EXPECT_EQ(3u, string_view("abc").size()); - EXPECT_STREQ("defg", StringRef(std::string("defg")).data()); - EXPECT_EQ(4u, StringRef(std::string("defg")).size()); + EXPECT_STREQ("defg", string_view(std::string("defg")).data()); + EXPECT_EQ(4u, string_view(std::string("defg")).size()); } -TEST(StringRefTest, ConvertToString) { - std::string s = StringRef("abc").to_string(); +TEST(StringViewTest, ConvertToString) { + std::string s = string_view("abc").to_string(); EXPECT_EQ("abc", s); } @@ -1320,7 +1320,7 @@ TEST(FormatterTest, FormatString) { } TEST(FormatterTest, FormatStringRef) { - EXPECT_EQ("test", format("{0}", StringRef("test"))); + EXPECT_EQ("test", format("{0}", string_view("test"))); } TEST(FormatterTest, FormatCStringRef) { diff --git a/test/gtest-extra.cc b/test/gtest-extra.cc index 5708eef7..325216d8 100644 --- a/test/gtest-extra.cc +++ b/test/gtest-extra.cc @@ -103,7 +103,7 @@ std::string read(File &f, std::size_t count) { #endif // FMT_USE_FILE_DESCRIPTORS -std::string format_system_error(int error_code, fmt::StringRef message) { +std::string format_system_error(int error_code, fmt::string_view message) { fmt::internal::MemoryBuffer out; fmt::format_system_error(out, error_code, message); return to_string(out); diff --git a/test/gtest-extra.h b/test/gtest-extra.h index 5f7fe29d..0f38dd31 100644 --- a/test/gtest-extra.h +++ b/test/gtest-extra.h @@ -81,7 +81,7 @@ FMT_TEST_THROW_(statement, expected_exception, \ expected_message, GTEST_NONFATAL_FAILURE_) -std::string format_system_error(int error_code, fmt::StringRef message); +std::string format_system_error(int error_code, fmt::string_view message); #define EXPECT_SYSTEM_ERROR(statement, error_code, message) \ EXPECT_THROW_MSG(statement, fmt::SystemError, \ diff --git a/test/posix-mock-test.cc b/test/posix-mock-test.cc index a87f8633..6b7104fc 100644 --- a/test/posix-mock-test.cc +++ b/test/posix-mock-test.cc @@ -213,7 +213,7 @@ int (test::fileno)(FILE *stream) { # define EXPECT_EQ_POSIX(expected, actual) #endif -void write_file(fmt::CStringRef filename, fmt::StringRef content) { +void write_file(fmt::CStringRef filename, fmt::string_view content) { fmt::BufferedFile f(filename, "w"); f.print("{}", content); } @@ -277,7 +277,7 @@ TEST(FileTest, Size) { write_file("test", content); File f("test", File::RDONLY); EXPECT_GE(f.size(), 0); - EXPECT_EQ(content.size(), static_cast(f.size())); + EXPECT_EQ(content.size(), static_cast(f.size())); #ifdef _WIN32 fmt::internal::MemoryBuffer message; fmt::internal::format_windows_error( diff --git a/test/posix-test.cc b/test/posix-test.cc index e6332bf0..c4b6f4dd 100644 --- a/test/posix-test.cc +++ b/test/posix-test.cc @@ -65,7 +65,7 @@ File open_file() { } // Attempts to write a string to a file. -void write(File &f, fmt::StringRef s) { +void write(File &f, fmt::string_view s) { std::size_t num_chars_left = s.size(); const char *ptr = s.data(); do { diff --git a/test/printf-test.cc b/test/printf-test.cc index e8df2181..65bcca72 100644 --- a/test/printf-test.cc +++ b/test/printf-test.cc @@ -40,7 +40,7 @@ using fmt::format_error; const unsigned BIG_NUM = INT_MAX + 1u; // Makes format string argument positional. -std::string make_positional(fmt::StringRef format) { +std::string make_positional(fmt::string_view format) { std::string s(format.to_string()); s.replace(s.find('%'), 1, "%1$"); return s; @@ -269,8 +269,8 @@ TEST(PrintfTest, DynamicPrecision) { "argument index out of range"); EXPECT_THROW_MSG(fmt::sprintf("%.*d", BIG_NUM, 42), format_error, "number is too big"); - if (sizeof(fmt::LongLong) != sizeof(int)) { - fmt::LongLong prec = static_cast(INT_MIN) - 1; + if (sizeof(fmt::long_long) != sizeof(int)) { + fmt::long_long prec = static_cast(INT_MIN) - 1; EXPECT_THROW_MSG(fmt::sprintf("%.*d", prec, 42), format_error, "number is too big"); } @@ -288,16 +288,16 @@ SPECIALIZE_MAKE_SIGNED(unsigned char, signed char); SPECIALIZE_MAKE_SIGNED(unsigned short, short); SPECIALIZE_MAKE_SIGNED(unsigned, int); SPECIALIZE_MAKE_SIGNED(unsigned long, long); -SPECIALIZE_MAKE_SIGNED(fmt::ULongLong, fmt::LongLong); +SPECIALIZE_MAKE_SIGNED(fmt::ulong_long, fmt::long_long); // Test length format specifier ``length_spec``. template void TestLength(const char *length_spec, U value) { - fmt::LongLong signed_value = 0; - fmt::ULongLong unsigned_value = 0; + fmt::long_long signed_value = 0; + fmt::ulong_long unsigned_value = 0; // Apply integer promotion to the argument. using std::numeric_limits; - fmt::ULongLong max = numeric_limits::max(); + fmt::ulong_long max = numeric_limits::max(); using fmt::internal::const_check; if (const_check(max <= static_cast(numeric_limits::max()))) { signed_value = static_cast(value); @@ -308,7 +308,7 @@ void TestLength(const char *length_spec, U value) { } using fmt::internal::MakeUnsigned; if (sizeof(U) <= sizeof(int) && sizeof(int) < sizeof(T)) { - signed_value = static_cast(value); + signed_value = static_cast(value); unsigned_value = static_cast::Type>(value); } else { signed_value = static_cast::Type>(value); @@ -339,20 +339,20 @@ void TestLength(const char *length_spec) { TestLength(length_spec, -42); TestLength(length_spec, min); TestLength(length_spec, max); - TestLength(length_spec, fmt::LongLong(min) - 1); - fmt::ULongLong long_long_max = std::numeric_limits::max(); - if (static_cast(max) < long_long_max) - TestLength(length_spec, fmt::LongLong(max) + 1); + TestLength(length_spec, fmt::long_long(min) - 1); + fmt::ulong_long long_long_max = std::numeric_limits::max(); + if (static_cast(max) < long_long_max) + TestLength(length_spec, fmt::long_long(max) + 1); TestLength(length_spec, std::numeric_limits::min()); TestLength(length_spec, std::numeric_limits::max()); TestLength(length_spec, std::numeric_limits::min()); TestLength(length_spec, std::numeric_limits::max()); TestLength(length_spec, std::numeric_limits::min()); TestLength(length_spec, std::numeric_limits::max()); - TestLength(length_spec, std::numeric_limits::min()); - TestLength(length_spec, std::numeric_limits::max()); - TestLength(length_spec, std::numeric_limits::min()); - TestLength(length_spec, std::numeric_limits::max()); + TestLength(length_spec, std::numeric_limits::min()); + TestLength(length_spec, std::numeric_limits::max()); + TestLength(length_spec, std::numeric_limits::min()); + TestLength(length_spec, std::numeric_limits::max()); } TEST(PrintfTest, Length) { @@ -363,8 +363,8 @@ TEST(PrintfTest, Length) { TestLength("h"); TestLength("l"); TestLength("l"); - TestLength("ll"); - TestLength("ll"); + TestLength("ll"); + TestLength("ll"); TestLength("j"); TestLength("z"); TestLength("t"); @@ -388,10 +388,10 @@ TEST(PrintfTest, Int) { EXPECT_PRINTF(fmt::format("{:X}", u), "%X", -42); } -TEST(PrintfTest, LongLong) { +TEST(PrintfTest, long_long) { // fmt::printf allows passing long long arguments to %d without length // specifiers. - fmt::LongLong max = std::numeric_limits::max(); + fmt::long_long max = std::numeric_limits::max(); EXPECT_PRINTF(fmt::format("{}", max), "%d", max); } diff --git a/test/util-test.cc b/test/util-test.cc index 370a704f..5978d914 100644 --- a/test/util-test.cc +++ b/test/util-test.cc @@ -54,7 +54,7 @@ using fmt::basic_arg; using fmt::basic_buffer; -using fmt::StringRef; +using fmt::string_view; using fmt::internal::MemoryBuffer; using fmt::internal::value; @@ -488,8 +488,8 @@ VISIT_TYPE(unsigned short, unsigned); VISIT_TYPE(long, int); VISIT_TYPE(unsigned long, unsigned); #else -VISIT_TYPE(long, fmt::LongLong); -VISIT_TYPE(unsigned long, fmt::ULongLong); +VISIT_TYPE(long, fmt::long_long); +VISIT_TYPE(unsigned long, fmt::ulong_long); #endif VISIT_TYPE(float, double); @@ -511,7 +511,7 @@ class NumericArgTest : public testing::Test {}; typedef ::testing::Types< bool, signed char, unsigned char, signed, unsigned short, - int, unsigned, long, unsigned long, fmt::LongLong, fmt::ULongLong, + int, unsigned, long, unsigned long, fmt::long_long, fmt::ulong_long, float, double, long double> Types; TYPED_TEST_CASE(NumericArgTest, Types); @@ -546,7 +546,7 @@ TEST(UtilTest, StringArg) { CHECK_ARG_(wchar_t, cstr, str); CHECK_ARG(cstr); - StringRef sref(str); + string_view sref(str); CHECK_ARG_(char, sref, std::string(str)); CHECK_ARG_(wchar_t, sref, std::string(str)); CHECK_ARG(sref); @@ -557,11 +557,11 @@ TEST(UtilTest, WStringArg) { wchar_t *str = str_data; const wchar_t *cstr = str; - fmt::WStringRef sref(str); + fmt::wstring_view sref(str); CHECK_ARG_(wchar_t, sref, str); CHECK_ARG_(wchar_t, sref, cstr); CHECK_ARG_(wchar_t, sref, std::wstring(str)); - CHECK_ARG_(wchar_t, sref, fmt::WStringRef(str)); + CHECK_ARG_(wchar_t, sref, fmt::wstring_view(str)); } TEST(UtilTest, PointerArg) { @@ -612,7 +612,7 @@ void test_count_digits() { TEST(UtilTest, StringRef) { // Test that StringRef::size() returns string length, not buffer size. char str[100] = "some string"; - EXPECT_EQ(std::strlen(str), StringRef(str).size()); + EXPECT_EQ(std::strlen(str), string_view(str).size()); EXPECT_LT(std::strlen(str), sizeof(str)); } @@ -623,18 +623,18 @@ void CheckOp() { std::size_t num_inputs = sizeof(inputs) / sizeof(*inputs); for (std::size_t i = 0; i < num_inputs; ++i) { for (std::size_t j = 0; j < num_inputs; ++j) { - StringRef lhs(inputs[i]), rhs(inputs[j]); - EXPECT_EQ(Op()(lhs.compare(rhs), 0), Op()(lhs, rhs)); + string_view lhs(inputs[i]), rhs(inputs[j]); + EXPECT_EQ(Op()(lhs.compare(rhs), 0), Op()(lhs, rhs)); } } } TEST(UtilTest, StringRefCompare) { - EXPECT_EQ(0, StringRef("foo").compare(StringRef("foo"))); - EXPECT_GT(StringRef("fop").compare(StringRef("foo")), 0); - EXPECT_LT(StringRef("foo").compare(StringRef("fop")), 0); - EXPECT_GT(StringRef("foo").compare(StringRef("fo")), 0); - EXPECT_LT(StringRef("fo").compare(StringRef("foo")), 0); + EXPECT_EQ(0, string_view("foo").compare(string_view("foo"))); + EXPECT_GT(string_view("fop").compare(string_view("foo")), 0); + EXPECT_LT(string_view("foo").compare(string_view("fop")), 0); + EXPECT_GT(string_view("foo").compare(string_view("fo")), 0); + EXPECT_LT(string_view("fo").compare(string_view("foo")), 0); CheckOp(); CheckOp(); CheckOp(); @@ -666,7 +666,7 @@ TEST(UtilTest, UTF8ToUTF16) { template void check_utf_conversion_error( const char *message, - fmt::BasicStringRef str = fmt::BasicStringRef(0, 0)) { + fmt::basic_string_view str = fmt::basic_string_view(0, 0)) { fmt::internal::MemoryBuffer out; fmt::internal::format_windows_error(out, ERROR_INVALID_PARAMETER, message); fmt::SystemError error(0, ""); @@ -688,19 +688,19 @@ TEST(UtilTest, UTF8ToUTF16Error) { const char *message = "cannot convert string from UTF-8 to UTF-16"; check_utf_conversion_error(message); check_utf_conversion_error( - message, fmt::StringRef("foo", INT_MAX + 1u)); + message, fmt::string_view("foo", INT_MAX + 1u)); } TEST(UtilTest, UTF16ToUTF8Convert) { fmt::internal::UTF16ToUTF8 u; - EXPECT_EQ(ERROR_INVALID_PARAMETER, u.convert(fmt::WStringRef(0, 0))); + EXPECT_EQ(ERROR_INVALID_PARAMETER, u.convert(fmt::wstring_view(0, 0))); EXPECT_EQ(ERROR_INVALID_PARAMETER, - u.convert(fmt::WStringRef(L"foo", INT_MAX + 1u))); + u.convert(fmt::wstring_view(L"foo", INT_MAX + 1u))); } #endif // _WIN32 typedef void (*FormatErrorMessage)( - fmt::buffer &out, int error_code, StringRef message); + fmt::buffer &out, int error_code, string_view message); template void check_throw_error(int error_code, FormatErrorMessage format) { @@ -723,7 +723,7 @@ TEST(UtilTest, FormatSystemError) { to_string(message)); message.clear(); fmt::format_system_error( - message, EDOM, fmt::StringRef(0, std::numeric_limits::max())); + message, EDOM, fmt::string_view(0, std::numeric_limits::max())); EXPECT_EQ(fmt::format("error {}", EDOM), to_string(message)); } @@ -760,7 +760,7 @@ TEST(UtilTest, FormatWindowsError) { actual_message.clear(); fmt::internal::format_windows_error( actual_message, ERROR_FILE_EXISTS, - fmt::StringRef(0, std::numeric_limits::max())); + fmt::string_view(0, std::numeric_limits::max())); EXPECT_EQ(fmt::format("error {}", ERROR_FILE_EXISTS), fmt::to_string(actual_message)); } From 4ec8860783ebef63db957fae49534cd846750cb8 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sat, 18 Feb 2017 07:46:32 -0800 Subject: [PATCH 092/340] ArgFormatter -> arg_formatter --- fmt/format.h | 16 ++++++++-------- fmt/ostream.h | 2 +- fmt/printf.h | 6 +++--- test/custom-formatter-test.cc | 18 +++++++++--------- test/ostream-test.cc | 4 ++-- 5 files changed, 23 insertions(+), 23 deletions(-) diff --git a/fmt/format.h b/fmt/format.h index 3eb8b1fe..bb3bbfd8 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -381,10 +381,10 @@ template class basic_arg; template -class ArgFormatter; +class arg_formatter; template -class PrintfArgFormatter; +class printf_arg_formatter; template class basic_context; @@ -2016,7 +2016,7 @@ class context_base { /** The default argument formatter. */ template -class ArgFormatter : public internal::ArgFormatterBase { +class arg_formatter : public internal::ArgFormatterBase { private: basic_context &ctx_; @@ -2033,8 +2033,8 @@ class ArgFormatter : public internal::ArgFormatterBase { format specifier information for standard argument types. \endrst */ - ArgFormatter(basic_buffer &buffer, basic_context &ctx, - format_specs &spec) + arg_formatter(basic_buffer &buffer, basic_context &ctx, + format_specs &spec) : internal::ArgFormatterBase(buffer, spec), ctx_(ctx) {} using internal::ArgFormatterBase::operator(); @@ -2277,7 +2277,7 @@ class basic_writer { friend class internal::ArgFormatterBase; template - friend class PrintfArgFormatter; + friend class printf_arg_formatter; public: /** @@ -2939,11 +2939,11 @@ void vformat_to(basic_buffer &buffer, BasicCStringRef format_str, basic_args args); inline void vformat_to(buffer &buf, CStringRef format_str, args args) { - vformat_to>(buf, format_str, args); + vformat_to>(buf, format_str, args); } inline void vformat_to(wbuffer &buf, WCStringRef format_str, wargs args) { - vformat_to>(buf, format_str, args); + vformat_to>(buf, format_str, args); } template diff --git a/fmt/ostream.h b/fmt/ostream.h index f99b9a71..45103734 100644 --- a/fmt/ostream.h +++ b/fmt/ostream.h @@ -86,7 +86,7 @@ void format_value(basic_buffer &buf, const T &value, internal::MemoryBuffer buffer; internal::format_value(buffer, value); basic_string_view str(buffer.data(), buffer.size()); - do_format_arg< ArgFormatter >( + do_format_arg< arg_formatter >( buf, internal::make_arg< basic_context >(str), ctx); } diff --git a/fmt/printf.h b/fmt/printf.h index a13684c5..0f3a200a 100644 --- a/fmt/printf.h +++ b/fmt/printf.h @@ -210,7 +210,7 @@ class PrintfWidthHandler { \endrst */ template -class PrintfArgFormatter : public internal::ArgFormatterBase { +class printf_arg_formatter : public internal::ArgFormatterBase { private: void write_null_pointer() { this->spec().type_ = 0; @@ -229,7 +229,7 @@ class PrintfArgFormatter : public internal::ArgFormatterBase { specifier information for standard argument types. \endrst */ - PrintfArgFormatter(basic_buffer &buffer, format_specs &spec) + printf_arg_formatter(basic_buffer &buffer, format_specs &spec) : internal::ArgFormatterBase(buffer, spec) {} using Base::operator(); @@ -295,7 +295,7 @@ class PrintfArgFormatter : public internal::ArgFormatterBase { /** This template formats data and writes the output to a writer. */ template > + typename ArgFormatter = printf_arg_formatter > class printf_context : private internal::context_base< Char, printf_context> { diff --git a/test/custom-formatter-test.cc b/test/custom-formatter-test.cc index 4a582c1a..c4d1f1e8 100644 --- a/test/custom-formatter-test.cc +++ b/test/custom-formatter-test.cc @@ -10,38 +10,38 @@ #include "fmt/printf.h" #include "gtest-extra.h" -using fmt::PrintfArgFormatter; +using fmt::printf_arg_formatter; // A custom argument formatter that doesn't print `-` for floating-point values // rounded to 0. -class CustomArgFormatter : public fmt::ArgFormatter { +class CustomArgFormatter : public fmt::arg_formatter { public: CustomArgFormatter(fmt::buffer &buf, fmt::basic_context &ctx, fmt::format_specs &s) - : fmt::ArgFormatter(buf, ctx, s) {} + : fmt::arg_formatter(buf, ctx, s) {} - using fmt::ArgFormatter::operator(); + using fmt::arg_formatter::operator(); void operator()(double value) { if (round(value * pow(10, spec().precision())) == 0) value = 0; - fmt::ArgFormatter::operator()(value); + fmt::arg_formatter::operator()(value); } }; // A custom argument formatter that doesn't print `-` for floating-point values // rounded to 0. -class CustomPrintfArgFormatter : public PrintfArgFormatter { +class CustomPrintfArgFormatter : public printf_arg_formatter { public: CustomPrintfArgFormatter(fmt::buffer &buf, fmt::format_specs &spec) - : PrintfArgFormatter(buf, spec) {} + : printf_arg_formatter(buf, spec) {} - using PrintfArgFormatter::operator(); + using printf_arg_formatter::operator(); void operator()(double value) { if (round(value * pow(10, spec().precision())) == 0) value = 0; - PrintfArgFormatter::operator()(value); + printf_arg_formatter::operator()(value); } }; diff --git a/test/ostream-test.cc b/test/ostream-test.cc index 761820b6..c28635b7 100644 --- a/test/ostream-test.cc +++ b/test/ostream-test.cc @@ -58,9 +58,9 @@ TEST(OStreamTest, Enum) { EXPECT_EQ("0", fmt::format("{}", A)); } -struct TestArgFormatter : fmt::ArgFormatter { +struct TestArgFormatter : fmt::arg_formatter { TestArgFormatter(fmt::buffer &buf, fmt::context &ctx, fmt::format_specs &s) - : fmt::ArgFormatter(buf, ctx, s) {} + : fmt::arg_formatter(buf, ctx, s) {} }; TEST(OStreamTest, CustomArg) { From eedfd07f8b4a81839024d5ee588a4782ac2c6030 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sat, 18 Feb 2017 09:13:12 -0800 Subject: [PATCH 093/340] internal::MemoryBuffer -> basic_memory_buffer --- fmt/format.cc | 14 +-- fmt/format.h | 210 +++++++++++++++------------------- fmt/ostream.cc | 2 +- fmt/ostream.h | 2 +- fmt/printf.h | 6 +- fmt/time.h | 2 +- test/custom-formatter-test.cc | 4 +- test/format-impl-test.cc | 28 ++--- test/format-test.cc | 127 ++++---------------- test/gtest-extra-test.cc | 6 +- test/gtest-extra.cc | 4 +- test/ostream-test.cc | 4 +- test/util-test.cc | 39 ++++--- 13 files changed, 173 insertions(+), 275 deletions(-) diff --git a/fmt/format.cc b/fmt/format.cc index 563a8f7d..3823c73c 100644 --- a/fmt/format.cc +++ b/fmt/format.cc @@ -205,7 +205,7 @@ void format_error_code(buffer &out, int error_code, void report_error(FormatFunc func, int error_code, string_view message) FMT_NOEXCEPT { - internal::MemoryBuffer full_message; + memory_buffer full_message; func(full_message, error_code, message); // Use Writer::data instead of Writer::c_str to avoid potential memory // allocation. @@ -217,10 +217,10 @@ void report_error(FormatFunc func, int error_code, FMT_FUNC void SystemError::init( int err_code, CStringRef format_str, args args) { error_code_ = err_code; - internal::MemoryBuffer buf; - format_system_error(buf, err_code, vformat(format_str, args)); + memory_buffer buffer; + format_system_error(buffer, err_code, vformat(format_str, args)); std::runtime_error &base = *this; - base = std::runtime_error(to_string(buf)); + base = std::runtime_error(to_string(buffer)); } template @@ -382,7 +382,7 @@ FMT_FUNC void internal::format_windows_error( FMT_FUNC void format_system_error( buffer &out, int error_code, string_view message) FMT_NOEXCEPT { FMT_TRY { - internal::MemoryBuffer buffer; + memory_buffer buffer; buffer.resize(internal::INLINE_BUFFER_SIZE); for (;;) { char *system_message = &buffer[0]; @@ -422,7 +422,7 @@ FMT_FUNC void report_windows_error( #endif FMT_FUNC void vprint(std::FILE *f, CStringRef format_str, args args) { - internal::MemoryBuffer buffer; + memory_buffer buffer; vformat_to(buffer, format_str, args); std::fwrite(buffer.data(), 1, buffer.size(), f); } @@ -444,7 +444,7 @@ void printf(basic_writer &w, BasicCStringRef format, args args); FMT_FUNC int vfprintf(std::FILE *f, CStringRef format, printf_args args) { - internal::MemoryBuffer buffer; + memory_buffer buffer; printf(buffer, format, args); std::size_t size = buffer.size(); return std::fwrite( diff --git a/fmt/format.h b/fmt/format.h index bb3bbfd8..d4de5ea6 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -659,13 +659,39 @@ inline std::basic_string to_string(const basic_buffer& buffer) { return std::basic_string(buffer.data(), buffer.size()); } -namespace internal { +/** + \rst + A dynamically growing memory buffer for trivially copyable/constructible types + with the first SIZE elements stored in the object itself. -// A memory buffer for trivially copyable/constructible types with the first -// SIZE elements stored in the object itself. -template | + +----------------+------------------------------+ + | wmemory_buffer | basic_memory_buffer | + +----------------+------------------------------+ + + **Example**:: + + memory_buffer out; + format_to(out, "The answer is {}.", 42); + + This will write the following output to the ``out`` object: + + .. code-block:: none + + The answer is 42. + + The output can be converted to an ``std::string`` with ``to_string(out)``. + \endrst + */ +// +template > -class MemoryBuffer : private Allocator, public basic_buffer { +class basic_memory_buffer : private Allocator, public basic_buffer { private: T data_[SIZE]; @@ -678,14 +704,14 @@ class MemoryBuffer : private Allocator, public basic_buffer { void grow(std::size_t size); public: - explicit MemoryBuffer(const Allocator &alloc = Allocator()) + explicit basic_memory_buffer(const Allocator &alloc = Allocator()) : Allocator(alloc), basic_buffer(data_, SIZE) {} - ~MemoryBuffer() { deallocate(); } + ~basic_memory_buffer() { deallocate(); } #if FMT_USE_RVALUE_REFERENCES private: // Move data from other to this buffer. - void move(MemoryBuffer &other) { + void move(basic_memory_buffer &other) { Allocator &this_alloc = *this, &other_alloc = other; this_alloc = std::move(other_alloc); this->size_ = other.size_; @@ -693,7 +719,7 @@ class MemoryBuffer : private Allocator, public basic_buffer { if (other.ptr_ == other.data_) { this->ptr_ = data_; std::uninitialized_copy(other.data_, other.data_ + this->size_, - make_ptr(data_, this->capacity_)); + internal::make_ptr(data_, this->capacity_)); } else { this->ptr_ = other.ptr_; // Set pointer to the inline array so that delete is not called @@ -703,11 +729,22 @@ class MemoryBuffer : private Allocator, public basic_buffer { } public: - MemoryBuffer(MemoryBuffer &&other) { + /** + \rst + Constructs a :class:`fmt::basic_memory_buffer` object moving the content + of the other object to it. + \endrst + */ + basic_memory_buffer(basic_memory_buffer &&other) { move(other); } - MemoryBuffer &operator=(MemoryBuffer &&other) { + /** + \rst + Moves the content of the other ``basic_memory_buffer`` object to this one. + \endrst + */ + basic_memory_buffer &operator=(basic_memory_buffer &&other) { assert(this != &other); deallocate(); move(other); @@ -720,14 +757,14 @@ class MemoryBuffer : private Allocator, public basic_buffer { }; template -void MemoryBuffer::grow(std::size_t size) { +void basic_memory_buffer::grow(std::size_t size) { std::size_t new_capacity = this->capacity_ + this->capacity_ / 2; if (size > new_capacity) new_capacity = size; T *new_ptr = this->allocate(new_capacity); // The following code doesn't throw, so the raw pointer above doesn't leak. std::uninitialized_copy(this->ptr_, this->ptr_ + this->size_, - make_ptr(new_ptr, new_capacity)); + internal::make_ptr(new_ptr, new_capacity)); std::size_t old_capacity = this->capacity_; T *old_ptr = this->ptr_; this->capacity_ = new_capacity; @@ -739,6 +776,45 @@ void MemoryBuffer::grow(std::size_t size) { Allocator::deallocate(old_ptr, old_capacity); } +typedef basic_memory_buffer memory_buffer; +typedef basic_memory_buffer wmemory_buffer; + +/** + \rst + A fixed-size memory buffer. For a dynamically growing buffer use + :class:`fmt::basic_memory_buffer`. + + Trying to increase the buffer size past the initial capacity will throw + ``std::runtime_error``. + \endrst + */ +template +class FixedBuffer : public basic_buffer { + public: + /** + \rst + Constructs a :class:`fmt::FixedBuffer` object for *array* of the + given size. + \endrst + */ + FixedBuffer(Char *array, std::size_t size) + : basic_buffer(array, size) {} + + /** + \rst + Constructs a :class:`fmt::FixedBuffer` object for *array* of the + size known at compile time. + \endrst + */ + template + explicit FixedBuffer(Char (&array)[SIZE]) : basic_buffer(array, SIZE) {} + + protected: + FMT_API void grow(std::size_t size); +}; + +namespace internal { + template class BasicCharTraits { public: @@ -1047,7 +1123,7 @@ struct ConvertToInt { #define FMT_DISABLE_CONVERSION_TO_INT(Type) \ template <> \ - struct ConvertToInt { enum { value = 0 }; } + struct ConvertToInt { enum { value = 0 }; } // Silence warnings about convering float to int. FMT_DISABLE_CONVERSION_TO_INT(float); @@ -2762,108 +2838,6 @@ void basic_writer::write_double(T value, const format_specs &spec) { grow_buffer(n); } -/** - \rst - This class template provides operations for formatting and writing data - into a memory buffer that grows dynamically. - - You can use one of the following typedefs for common character types - and the standard allocator: - - +---------------+-----------------------------------------------------+ - | Type | Definition | - +===============+=====================================================+ - | MemoryWriter | BasicMemoryWriter> | - +---------------+-----------------------------------------------------+ - | WMemoryWriter | BasicMemoryWriter> | - +---------------+-----------------------------------------------------+ - - **Example**:: - - MemoryWriter out; - out << "The answer is " << 42 << "\n"; - out.write("({:+f}, {:+f})", -3.14, 3.14); - - This will write the following output to the ``out`` object: - - .. code-block:: none - - The answer is 42 - (-3.140000, +3.140000) - - The output can be converted to an ``std::string`` with ``out.str()`` or - accessed as a C string with ``out.c_str()``. - \endrst - */ -template > -class BasicMemoryWriter : public basic_writer { - private: - internal::MemoryBuffer buffer_; - - public: - explicit BasicMemoryWriter(const Allocator& alloc = Allocator()) - : basic_writer(buffer_), buffer_(alloc) {} - -#if FMT_USE_RVALUE_REFERENCES - /** - \rst - Constructs a :class:`fmt::BasicMemoryWriter` object moving the content - of the other object to it. - \endrst - */ - BasicMemoryWriter(BasicMemoryWriter &&other) - : basic_writer(buffer_), buffer_(std::move(other.buffer_)) { - } - - /** - \rst - Moves the content of the other ``BasicMemoryWriter`` object to this one. - \endrst - */ - BasicMemoryWriter &operator=(BasicMemoryWriter &&other) { - buffer_ = std::move(other.buffer_); - return *this; - } -#endif -}; - -typedef BasicMemoryWriter MemoryWriter; -typedef BasicMemoryWriter WMemoryWriter; - -/** - \rst - A fixed-size memory buffer. For a dynamically growing buffer use - :class:`fmt::internal::MemoryBuffer`. - - Trying to increase the buffer size past the initial capacity will throw - ``std::runtime_error``. - \endrst - */ -template -class FixedBuffer : public basic_buffer { - public: - /** - \rst - Constructs a :class:`fmt::FixedBuffer` object for *array* of the - given size. - \endrst - */ - FixedBuffer(Char *array, std::size_t size) - : basic_buffer(array, size) {} - - /** - \rst - Constructs a :class:`fmt::FixedBuffer` object for *array* of the - size known at compile time. - \endrst - */ - template - explicit FixedBuffer(Char (&array)[SIZE]) : basic_buffer(array, SIZE) {} - - protected: - FMT_API void grow(std::size_t size); -}; - // Reports a system error without throwing an exception. // Can be used to report errors from destructors. FMT_API void report_system_error(int error_code, @@ -2959,7 +2933,7 @@ inline void format_to(wbuffer &buf, WCStringRef format_str, } inline std::string vformat(CStringRef format_str, args args) { - internal::MemoryBuffer buffer; + memory_buffer buffer; vformat_to(buffer, format_str, args); return to_string(buffer); } @@ -2979,7 +2953,7 @@ inline std::string format(CStringRef format_str, const Args & ... args) { } inline std::wstring vformat(WCStringRef format_str, wargs args) { - internal::MemoryBuffer buffer; + wmemory_buffer buffer; vformat_to(buffer, format_str, args); return to_string(buffer); } diff --git a/fmt/ostream.cc b/fmt/ostream.cc index f900664c..f9136482 100644 --- a/fmt/ostream.cc +++ b/fmt/ostream.cc @@ -28,7 +28,7 @@ FMT_FUNC void write(std::ostream &os, buffer &buf) { } FMT_FUNC void vprint(std::ostream &os, CStringRef format_str, args args) { - internal::MemoryBuffer buffer; + memory_buffer buffer; vformat_to(buffer, format_str, args); internal::write(os, buffer); } diff --git a/fmt/ostream.h b/fmt/ostream.h index 45103734..8672ac6c 100644 --- a/fmt/ostream.h +++ b/fmt/ostream.h @@ -83,7 +83,7 @@ void format_value(basic_buffer &buffer, const T &value) { template void format_value(basic_buffer &buf, const T &value, basic_context &ctx) { - internal::MemoryBuffer buffer; + basic_memory_buffer buffer; internal::format_value(buffer, value); basic_string_view str(buffer.data(), buffer.size()); do_format_arg< arg_formatter >( diff --git a/fmt/printf.h b/fmt/printf.h index 0f3a200a..02c33fba 100644 --- a/fmt/printf.h +++ b/fmt/printf.h @@ -522,7 +522,7 @@ void printf(basic_buffer &buf, BasicCStringRef format, typedef basic_args> printf_args; inline std::string vsprintf(CStringRef format, printf_args args) { - internal::MemoryBuffer buffer; + memory_buffer buffer; printf(buffer, format, args); return to_string(buffer); } @@ -543,7 +543,7 @@ inline std::string sprintf(CStringRef format_str, const Args & ... args) { inline std::wstring vsprintf( WCStringRef format, basic_args> args) { - internal::MemoryBuffer buffer; + wmemory_buffer buffer; printf(buffer, format, args); return to_string(buffer); } @@ -590,7 +590,7 @@ inline int printf(CStringRef format_str, const Args & ... args) { } inline int vfprintf(std::ostream &os, CStringRef format_str, printf_args args) { - internal::MemoryBuffer buffer; + memory_buffer buffer; printf(buffer, format_str, args); internal::write(os, buffer); return static_cast(buffer.size()); diff --git a/fmt/time.h b/fmt/time.h index f4ec4812..c4700fbc 100644 --- a/fmt/time.h +++ b/fmt/time.h @@ -24,7 +24,7 @@ void format_value(buffer &buf, const std::tm &tm, context &ctx) { ++end; if (*end != '}') FMT_THROW(format_error("missing '}' in format string")); - internal::MemoryBuffer format; + memory_buffer format; format.append(s, end + 1); format[format.size() - 1] = '\0'; std::size_t start = buf.size(); diff --git a/test/custom-formatter-test.cc b/test/custom-formatter-test.cc index c4d1f1e8..3e226d71 100644 --- a/test/custom-formatter-test.cc +++ b/test/custom-formatter-test.cc @@ -46,7 +46,7 @@ class CustomPrintfArgFormatter : public printf_arg_formatter { }; std::string custom_vformat(fmt::CStringRef format_str, fmt::args args) { - fmt::internal::MemoryBuffer buffer; + fmt::memory_buffer buffer; // Pass custom argument formatter as a template arg to vwrite. fmt::vformat_to(buffer, format_str, args); return std::string(buffer.data(), buffer.size()); @@ -64,7 +64,7 @@ typedef fmt::printf_context std::string custom_vsprintf( const char* format_str, fmt::basic_args args) { - fmt::internal::MemoryBuffer buffer; + fmt::memory_buffer buffer; CustomPrintfFormatter formatter(format_str, args); formatter.format(buffer); return std::string(buffer.data(), buffer.size()); diff --git a/test/format-impl-test.cc b/test/format-impl-test.cc index 9102db03..f12b6450 100644 --- a/test/format-impl-test.cc +++ b/test/format-impl-test.cc @@ -105,33 +105,33 @@ TEST(FormatTest, StrError) { TEST(FormatTest, FormatErrorCode) { std::string msg = "error 42", sep = ": "; { - fmt::MemoryWriter w; - w.write("garbage"); - fmt::format_error_code(w.buffer(), 42, "test"); - EXPECT_EQ("test: " + msg, w.str()); + fmt::memory_buffer buffer; + format_to(buffer, "garbage"); + fmt::format_error_code(buffer, 42, "test"); + EXPECT_EQ("test: " + msg, to_string(buffer)); } { - fmt::MemoryWriter w; + fmt::memory_buffer buffer; std::string prefix( fmt::internal::INLINE_BUFFER_SIZE - msg.size() - sep.size() + 1, 'x'); - fmt::format_error_code(w.buffer(), 42, prefix); - EXPECT_EQ(msg, w.str()); + fmt::format_error_code(buffer, 42, prefix); + EXPECT_EQ(msg, to_string(buffer)); } int codes[] = {42, -1}; for (std::size_t i = 0, n = sizeof(codes) / sizeof(*codes); i < n; ++i) { // Test maximum buffer size. msg = fmt::format("error {}", codes[i]); - fmt::MemoryWriter w; + fmt::memory_buffer buffer; std::string prefix( fmt::internal::INLINE_BUFFER_SIZE - msg.size() - sep.size(), 'x'); - fmt::format_error_code(w.buffer(), codes[i], prefix); - EXPECT_EQ(prefix + sep + msg, w.str()); + fmt::format_error_code(buffer, codes[i], prefix); + EXPECT_EQ(prefix + sep + msg, to_string(buffer)); std::size_t size = fmt::internal::INLINE_BUFFER_SIZE; - EXPECT_EQ(size, w.size()); - w.clear(); + EXPECT_EQ(size, buffer.size()); + buffer.clear(); // Test with a message that doesn't fit into the buffer. prefix += 'x'; - fmt::format_error_code(w.buffer(), codes[i], prefix); - EXPECT_EQ(msg, w.str()); + fmt::format_error_code(buffer, codes[i], prefix); + EXPECT_EQ(msg, to_string(buffer)); } } diff --git a/test/format-test.cc b/test/format-test.cc index bf2b153e..2e1baaf2 100644 --- a/test/format-test.cc +++ b/test/format-test.cc @@ -75,8 +75,8 @@ using fmt::format; using fmt::format_error; using fmt::string_view; using fmt::CStringRef; -using fmt::MemoryWriter; -using fmt::WMemoryWriter; +using fmt::memory_buffer; +using fmt::wmemory_buffer; using fmt::fill; using fmt::type; using fmt::width; @@ -109,7 +109,8 @@ void std_format(long double value, std::wstring &result) { // as writing it to std::basic_ostringstream. template ::testing::AssertionResult check_write(const T &value, const char *type) { - fmt::BasicMemoryWriter writer; + fmt::basic_memory_buffer buffer; + fmt::basic_writer writer(buffer); writer.write(value); std::basic_string actual = writer.str(); std::basic_string expected; @@ -177,90 +178,16 @@ TEST(WriterTest, NotCopyAssignable) { #endif TEST(WriterTest, Ctor) { - MemoryWriter w; + memory_buffer buf; + fmt::basic_writer w(buf); EXPECT_EQ(0u, w.size()); EXPECT_STREQ("", w.c_str()); EXPECT_EQ("", w.str()); } -#if FMT_USE_RVALUE_REFERENCES - -void check_move_writer(const std::string &str, MemoryWriter &w) { - MemoryWriter w2(std::move(w)); - // Move shouldn't destroy the inline content of the first writer. - EXPECT_EQ(str, w.str()); - EXPECT_EQ(str, w2.str()); -} - -TEST(WriterTest, MoveCtor) { - MemoryWriter w; - w.write("test"); - check_move_writer("test", w); - // This fills the inline buffer, but doesn't cause dynamic allocation. - std::string s; - for (int i = 0; i < fmt::internal::INLINE_BUFFER_SIZE; ++i) - s += '*'; - w.clear(); - w.write(s); - check_move_writer(s, w); - const char *inline_buffer_ptr = w.data(); - // Adding one more character causes the content to move from the inline to - // a dynamically allocated buffer. - w.write('*'); - MemoryWriter w2(std::move(w)); - // Move should rip the guts of the first writer. - EXPECT_EQ(inline_buffer_ptr, w.data()); - EXPECT_EQ(s + '*', w2.str()); -} - -void CheckMoveAssignWriter(const std::string &str, MemoryWriter &w) { - MemoryWriter w2; - w2 = std::move(w); - // Move shouldn't destroy the inline content of the first writer. - EXPECT_EQ(str, w.str()); - EXPECT_EQ(str, w2.str()); -} - -TEST(WriterTest, MoveAssignment) { - MemoryWriter w; - w.write("test"); - CheckMoveAssignWriter("test", w); - // This fills the inline buffer, but doesn't cause dynamic allocation. - std::string s; - for (int i = 0; i < fmt::internal::INLINE_BUFFER_SIZE; ++i) - s += '*'; - w.clear(); - w.write(s); - CheckMoveAssignWriter(s, w); - const char *inline_buffer_ptr = w.data(); - // Adding one more character causes the content to move from the inline to - // a dynamically allocated buffer. - w.write('*'); - MemoryWriter w2; - w2 = std::move(w); - // Move should rip the guts of the first writer. - EXPECT_EQ(inline_buffer_ptr, w.data()); - EXPECT_EQ(s + '*', w2.str()); -} - -#endif // FMT_USE_RVALUE_REFERENCES - -TEST(WriterTest, Allocator) { - typedef testing::StrictMock< MockAllocator > MockAllocator; - typedef AllocatorRef TestAllocator; - MockAllocator alloc; - fmt::BasicMemoryWriter w((TestAllocator(&alloc))); - std::size_t size = - static_cast(1.5 * fmt::internal::INLINE_BUFFER_SIZE); - std::vector mem(size); - EXPECT_CALL(alloc, allocate(size)).WillOnce(testing::Return(&mem[0])); - for (int i = 0; i < fmt::internal::INLINE_BUFFER_SIZE + 1; ++i) - w.write('*'); - EXPECT_CALL(alloc, deallocate(&mem[0], size)); -} - TEST(WriterTest, Data) { - MemoryWriter w; + memory_buffer buf; + fmt::basic_writer w(buf); w.write(42); EXPECT_EQ("42", std::string(w.data(), w.size())); } @@ -312,13 +239,15 @@ TEST(WriterTest, WriteLongDouble) { } TEST(WriterTest, WriteDoubleAtBufferBoundary) { - MemoryWriter writer; + memory_buffer buf; + fmt::basic_writer writer(buf); for (int i = 0; i < 100; ++i) writer.write(1.23456789); } TEST(WriterTest, WriteDoubleWithFilledBuffer) { - MemoryWriter writer; + memory_buffer buf; + fmt::basic_writer writer(buf); // Fill the buffer. for (int i = 0; i < fmt::internal::INLINE_BUFFER_SIZE; ++i) writer.write(' '); @@ -349,7 +278,8 @@ TEST(WriterTest, WriteWideString) { template std::string write_str(T... args) { - MemoryWriter writer; + memory_buffer buf; + fmt::basic_writer writer(buf); using namespace fmt; writer.write(args...); return writer.str(); @@ -357,7 +287,8 @@ std::string write_str(T... args) { template std::wstring write_wstr(T... args) { - WMemoryWriter writer; + wmemory_buffer buf; + fmt::basic_writer writer(buf); using namespace fmt; writer.write(args...); return writer.str(); @@ -447,7 +378,8 @@ TEST(WriterTest, pad) { EXPECT_EQ(" 33", write_str(33ll, width=7)); EXPECT_EQ(" 44", write_str(44ull, width=7)); - MemoryWriter w; + memory_buffer buf; + fmt::basic_writer w(buf); w.clear(); w.write(42, fmt::width=5, fmt::fill='0'); EXPECT_EQ("00042", w.str()); @@ -475,13 +407,13 @@ TEST(WriterTest, WWriter) { } TEST(FormatToTest, FormatWithoutArgs) { - fmt::internal::MemoryBuffer buffer; + fmt::memory_buffer buffer; format_to(buffer, "test"); EXPECT_EQ("test", std::string(buffer.data(), buffer.size())); } TEST(FormatToTest, Format) { - fmt::internal::MemoryBuffer buffer; + fmt::memory_buffer buffer; format_to(buffer, "part{0}", 1); EXPECT_EQ(strlen("part1"), buffer.size()); EXPECT_EQ("part1", std::string(buffer.data(), buffer.size())); @@ -1370,18 +1302,9 @@ TEST(FormatterTest, FormatExamples) { EXPECT_EQ("42", format("{}", 42)); EXPECT_EQ("42", format(std::string("{}"), 42)); - MemoryWriter out; - out.write("The answer is "); - out.write(42); - out.write("\n"); - - { - MemoryWriter writer; - for (int i = 0; i < 10; i++) - format_to(writer.buffer(), "{}", i); - std::string s = writer.str(); // s == 0123456789 - EXPECT_EQ("0123456789", s); - } + memory_buffer out; + format_to(out, "The answer is {}.", 42); + EXPECT_EQ("The answer is 42.", to_string(out)); const char *filename = "nonexistent"; FILE *ftest = safe_fopen(filename, "r"); @@ -1522,7 +1445,7 @@ TEST(StrTest, Convert) { } std::string vformat_message(int id, const char *format, fmt::args args) { - fmt::internal::MemoryBuffer buffer; + fmt::memory_buffer buffer; format_to(buffer, "[{}] ", id); vformat_to(buffer, format, args); return to_string(buffer); @@ -1612,7 +1535,7 @@ class MockArgFormatter : public fmt::internal::ArgFormatterBase { }; void custom_vformat(fmt::CStringRef format_str, fmt::args args) { - fmt::internal::MemoryBuffer buffer; + fmt::memory_buffer buffer; fmt::vformat_to(buffer, format_str, args); } diff --git a/test/gtest-extra-test.cc b/test/gtest-extra-test.cc index 4de17ee3..97c4bee1 100644 --- a/test/gtest-extra-test.cc +++ b/test/gtest-extra-test.cc @@ -319,9 +319,9 @@ TEST(StreamingAssertionsTest, EXPECT_WRITE) { } TEST(UtilTest, FormatSystemError) { - fmt::MemoryWriter out; - fmt::format_system_error(out.buffer(), EDOM, "test message"); - EXPECT_EQ(out.str(), format_system_error(EDOM, "test message")); + fmt::memory_buffer out; + fmt::format_system_error(out, EDOM, "test message"); + EXPECT_EQ(to_string(out), format_system_error(EDOM, "test message")); } #if FMT_USE_FILE_DESCRIPTORS diff --git a/test/gtest-extra.cc b/test/gtest-extra.cc index 325216d8..34daf4db 100644 --- a/test/gtest-extra.cc +++ b/test/gtest-extra.cc @@ -104,7 +104,7 @@ std::string read(File &f, std::size_t count) { #endif // FMT_USE_FILE_DESCRIPTORS std::string format_system_error(int error_code, fmt::string_view message) { - fmt::internal::MemoryBuffer out; - fmt::format_system_error(out, error_code, message); + fmt::memory_buffer out; + format_system_error(out, error_code, message); return to_string(out); } diff --git a/test/ostream-test.cc b/test/ostream-test.cc index c28635b7..2ab22248 100644 --- a/test/ostream-test.cc +++ b/test/ostream-test.cc @@ -64,7 +64,7 @@ struct TestArgFormatter : fmt::arg_formatter { }; TEST(OStreamTest, CustomArg) { - fmt::internal::MemoryBuffer buffer; + fmt::memory_buffer buffer; fmt::context ctx("}", fmt::args()); fmt::format_specs spec; TestArgFormatter af(buffer, ctx, spec); @@ -121,7 +121,7 @@ TEST(OStreamTest, Print) { TEST(OStreamTest, WriteToOStream) { std::ostringstream os; - fmt::internal::MemoryBuffer buffer; + fmt::memory_buffer buffer; const char *foo = "foo"; buffer.append(foo, foo + std::strlen(foo)); fmt::internal::write(os, buffer); diff --git a/test/util-test.cc b/test/util-test.cc index 5978d914..f9ca8e5a 100644 --- a/test/util-test.cc +++ b/test/util-test.cc @@ -54,8 +54,8 @@ using fmt::basic_arg; using fmt::basic_buffer; +using fmt::basic_memory_buffer; using fmt::string_view; -using fmt::internal::MemoryBuffer; using fmt::internal::value; using testing::_; @@ -238,7 +238,7 @@ TEST(BufferTest, AppendAllocatesEnoughStorage) { } TEST(MemoryBufferTest, Ctor) { - MemoryBuffer buffer; + basic_memory_buffer buffer; EXPECT_EQ(0u, buffer.size()); EXPECT_EQ(123u, buffer.capacity()); } @@ -248,9 +248,9 @@ TEST(MemoryBufferTest, Ctor) { typedef AllocatorRef< std::allocator > TestAllocator; void check_move_buffer(const char *str, - MemoryBuffer &buffer) { + basic_memory_buffer &buffer) { std::allocator *alloc = buffer.get_allocator().get(); - MemoryBuffer buffer2(std::move(buffer)); + basic_memory_buffer buffer2(std::move(buffer)); // Move shouldn't destroy the inline content of the first buffer. EXPECT_EQ(str, std::string(&buffer[0], buffer.size())); EXPECT_EQ(str, std::string(&buffer2[0], buffer2.size())); @@ -262,7 +262,7 @@ void check_move_buffer(const char *str, TEST(MemoryBufferTest, MoveCtor) { std::allocator alloc; - MemoryBuffer buffer((TestAllocator(&alloc))); + basic_memory_buffer buffer((TestAllocator(&alloc))); const char test[] = "test"; buffer.append(test, test + 4); check_move_buffer("test", buffer); @@ -274,15 +274,16 @@ TEST(MemoryBufferTest, MoveCtor) { // Adding one more character causes the content to move from the inline to // a dynamically allocated buffer. buffer.push_back('b'); - MemoryBuffer buffer2(std::move(buffer)); + basic_memory_buffer buffer2(std::move(buffer)); // Move should rip the guts of the first buffer. EXPECT_EQ(inline_buffer_ptr, &buffer[0]); EXPECT_EQ("testab", std::string(&buffer2[0], buffer2.size())); EXPECT_GT(buffer2.capacity(), 5u); } -void check_move_assign_buffer(const char *str, MemoryBuffer &buffer) { - MemoryBuffer buffer2; +void check_move_assign_buffer( + const char *str, basic_memory_buffer &buffer) { + basic_memory_buffer buffer2; buffer2 = std::move(buffer); // Move shouldn't destroy the inline content of the first buffer. EXPECT_EQ(str, std::string(&buffer[0], buffer.size())); @@ -291,7 +292,7 @@ void check_move_assign_buffer(const char *str, MemoryBuffer &buffer) { } TEST(MemoryBufferTest, MoveAssignment) { - MemoryBuffer buffer; + basic_memory_buffer buffer; const char test[] = "test"; buffer.append(test, test + 4); check_move_assign_buffer("test", buffer); @@ -303,7 +304,7 @@ TEST(MemoryBufferTest, MoveAssignment) { // Adding one more character causes the content to move from the inline to // a dynamically allocated buffer. buffer.push_back('b'); - MemoryBuffer buffer2; + basic_memory_buffer buffer2; buffer2 = std::move(buffer); // Move should rip the guts of the first buffer. EXPECT_EQ(inline_buffer_ptr, &buffer[0]); @@ -315,7 +316,7 @@ TEST(MemoryBufferTest, MoveAssignment) { TEST(MemoryBufferTest, Grow) { typedef AllocatorRef< MockAllocator > Allocator; - typedef MemoryBuffer Base; + typedef basic_memory_buffer Base; MockAllocator alloc; struct TestMemoryBuffer : Base { TestMemoryBuffer(Allocator alloc) : Base(alloc) {} @@ -341,12 +342,12 @@ TEST(MemoryBufferTest, Grow) { TEST(MemoryBufferTest, Allocator) { typedef AllocatorRef< MockAllocator > TestAllocator; - MemoryBuffer buffer; + basic_memory_buffer buffer; EXPECT_EQ(0, buffer.get_allocator().get()); StrictMock< MockAllocator > alloc; char mem; { - MemoryBuffer buffer2((TestAllocator(&alloc))); + basic_memory_buffer buffer2((TestAllocator(&alloc))); EXPECT_EQ(&alloc, buffer2.get_allocator().get()); std::size_t size = 2 * fmt::internal::INLINE_BUFFER_SIZE; EXPECT_CALL(alloc, allocate(size)).WillOnce(Return(&mem)); @@ -358,7 +359,7 @@ TEST(MemoryBufferTest, Allocator) { TEST(MemoryBufferTest, ExceptionInDeallocate) { typedef AllocatorRef< MockAllocator > TestAllocator; StrictMock< MockAllocator > alloc; - MemoryBuffer buffer((TestAllocator(&alloc))); + basic_memory_buffer buffer((TestAllocator(&alloc))); std::size_t size = 2 * fmt::internal::INLINE_BUFFER_SIZE; std::vector mem(size); { @@ -435,7 +436,7 @@ TEST(UtilTest, MakeValueWithCustomFormatter) { ::Test t; fmt::internal::value arg(t); CustomContext ctx = {false}; - fmt::internal::MemoryBuffer buffer; + fmt::memory_buffer buffer; arg.custom.format(buffer, &t, &ctx); EXPECT_TRUE(ctx.called); } @@ -579,7 +580,7 @@ TEST(UtilTest, CustomArg) { EXPECT_CALL(visitor, visit(_)).WillOnce( testing::Invoke([&](fmt::internal::CustomValue custom) { EXPECT_EQ(&test, custom.value); - fmt::internal::MemoryBuffer buffer; + fmt::memory_buffer buffer; fmt::context ctx("}", fmt::args()); custom.format(buffer, &test, &ctx); EXPECT_EQ("test", std::string(buffer.data(), buffer.size())); @@ -710,14 +711,14 @@ void check_throw_error(int error_code, FormatErrorMessage format) { } catch (const fmt::SystemError &e) { error = e; } - fmt::internal::MemoryBuffer message; + fmt::memory_buffer message; format(message, error_code, "test error"); EXPECT_EQ(to_string(message), error.what()); EXPECT_EQ(error_code, error.error_code()); } TEST(UtilTest, FormatSystemError) { - fmt::internal::MemoryBuffer message; + fmt::memory_buffer message; fmt::format_system_error(message, EDOM, "test"); EXPECT_EQ(fmt::format("test: {}", get_system_error(EDOM)), to_string(message)); @@ -735,7 +736,7 @@ TEST(UtilTest, SystemError) { } TEST(UtilTest, ReportSystemError) { - fmt::internal::MemoryBuffer out; + fmt::memory_buffer out; fmt::format_system_error(out, EDOM, "test error"); out.push_back('\n'); EXPECT_WRITE(stderr, fmt::report_system_error(EDOM, "test error"), From 6a2ff287b20924db5b2cebd60311f132dced268a Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sun, 19 Feb 2017 06:46:51 -0800 Subject: [PATCH 094/340] Follow standard naming conventions --- fmt/format.cc | 36 ++++---- fmt/format.h | 199 +++++++++++++++++++--------------------- fmt/ostream.cc | 2 +- fmt/printf.h | 10 +- test/format-test.cc | 2 +- test/ostream-test.cc | 2 +- test/posix-mock-test.cc | 2 +- test/printf-test.cc | 12 +-- test/util-test.cc | 34 +++---- 9 files changed, 143 insertions(+), 156 deletions(-) diff --git a/fmt/format.cc b/fmt/format.cc index 3823c73c..b4a8f078 100644 --- a/fmt/format.cc +++ b/fmt/format.cc @@ -186,8 +186,8 @@ void format_error_code(buffer &out, int error_code, static const char ERROR_STR[] = "error "; // Subtract 2 to account for terminating null characters in SEP and ERROR_STR. std::size_t error_code_size = sizeof(SEP) + sizeof(ERROR_STR) - 2; - typedef internal::IntTraits::MainType MainType; - MainType abs_value = static_cast(error_code); + typedef internal::int_traits::main_type main_type; + main_type abs_value = static_cast(error_code); if (internal::is_negative(error_code)) { abs_value = 0 - abs_value; ++error_code_size; @@ -224,7 +224,7 @@ FMT_FUNC void SystemError::init( } template -int internal::CharTraits::format_float( +int internal::char_traits::format_float( char *buffer, std::size_t size, const char *format, unsigned width, int precision, T value) { if (width == 0) { @@ -238,7 +238,7 @@ int internal::CharTraits::format_float( } template -int internal::CharTraits::format_float( +int internal::char_traits::format_float( wchar_t *buffer, std::size_t size, const wchar_t *format, unsigned width, int precision, T value) { if (width == 0) { @@ -252,7 +252,7 @@ int internal::CharTraits::format_float( } template -const char internal::BasicData::DIGITS[] = +const char internal::basic_data::DIGITS[] = "0001020304050607080910111213141516171819" "2021222324252627282930313233343536373839" "4041424344454647484950515253545556575859" @@ -271,12 +271,12 @@ const char internal::BasicData::DIGITS[] = factor * 1000000000 template -const uint32_t internal::BasicData::POWERS_OF_10_32[] = { +const uint32_t internal::basic_data::POWERS_OF_10_32[] = { 0, FMT_POWERS_OF_10(1) }; template -const uint64_t internal::BasicData::POWERS_OF_10_64[] = { +const uint64_t internal::basic_data::POWERS_OF_10_64[] = { 0, FMT_POWERS_OF_10(1), FMT_POWERS_OF_10(ulong_long(1000000000)), @@ -298,7 +298,7 @@ FMT_FUNC void internal::report_unknown_type(char code, const char *type) { #if FMT_USE_WINDOWS_H -FMT_FUNC internal::UTF8ToUTF16::UTF8ToUTF16(string_view s) { +FMT_FUNC internal::utf8_to_utf16::utf8_to_utf16(string_view s) { static const char ERROR_MSG[] = "cannot convert string from UTF-8 to UTF-16"; if (s.size() > INT_MAX) FMT_THROW(WindowsError(ERROR_INVALID_PARAMETER, ERROR_MSG)); @@ -341,7 +341,7 @@ FMT_FUNC int internal::UTF16ToUTF8::convert(wstring_view s) { FMT_FUNC void WindowsError::init( int err_code, CStringRef format_str, args args) { error_code_ = err_code; - internal::MemoryBuffer buffer; + memory_buffer buffer; internal::format_windows_error(buffer, err_code, vformat(format_str, args)); std::runtime_error &base = *this; base = std::runtime_error(to_string(buffer)); @@ -350,7 +350,7 @@ FMT_FUNC void WindowsError::init( FMT_FUNC void internal::format_windows_error( buffer &out, int error_code, string_view message) FMT_NOEXCEPT { FMT_TRY { - MemoryBuffer buffer; + wmemory_buffer buffer; buffer.resize(INLINE_BUFFER_SIZE); for (;;) { wchar_t *system_message = &buffer[0]; @@ -403,7 +403,7 @@ FMT_FUNC void format_system_error( } template -void FixedBuffer::grow(std::size_t) { +void basic_fixed_buffer::grow(std::size_t) { FMT_THROW(std::runtime_error("buffer overflow")); } @@ -453,21 +453,21 @@ FMT_FUNC int vfprintf(std::FILE *f, CStringRef format, printf_args args) { #ifndef FMT_HEADER_ONLY -template struct internal::BasicData; +template struct internal::basic_data; // Explicit instantiations for char. -template void FixedBuffer::grow(std::size_t); +template void basic_fixed_buffer::grow(std::size_t); template void internal::ArgMap::init(const args &args); template void printf_context::format(buffer &); -template int internal::CharTraits::format_float( +template int internal::char_traits::format_float( char *buffer, std::size_t size, const char *format, unsigned width, int precision, double value); -template int internal::CharTraits::format_float( +template int internal::char_traits::format_float( char *buffer, std::size_t size, const char *format, unsigned width, int precision, long double value); @@ -475,17 +475,17 @@ template int internal::CharTraits::format_float( template class basic_context; -template void FixedBuffer::grow(std::size_t); +template void basic_fixed_buffer::grow(std::size_t); template void internal::ArgMap::init(const wargs &args); template void printf_context::format(wbuffer &); -template int internal::CharTraits::format_float( +template int internal::char_traits::format_float( wchar_t *buffer, std::size_t size, const wchar_t *format, unsigned width, int precision, double value); -template int internal::CharTraits::format_float( +template int internal::char_traits::format_float( wchar_t *buffer, std::size_t size, const wchar_t *format, unsigned width, int precision, long double value); diff --git a/fmt/format.h b/fmt/format.h index d4de5ea6..eea1b83e 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -532,13 +532,14 @@ class format_error : public std::runtime_error { namespace internal { -// MakeUnsigned::Type gives an unsigned type corresponding to integer type T. +// make_unsigned::type gives an unsigned type corresponding to integer +// type T. template -struct MakeUnsigned { typedef T Type; }; +struct make_unsigned { typedef T type; }; #define FMT_SPECIALIZE_MAKE_UNSIGNED(T, U) \ template <> \ - struct MakeUnsigned { typedef U Type; } + struct make_unsigned { typedef U type; } FMT_SPECIALIZE_MAKE_UNSIGNED(char, unsigned char); FMT_SPECIALIZE_MAKE_UNSIGNED(signed char, unsigned char); @@ -549,9 +550,9 @@ FMT_SPECIALIZE_MAKE_UNSIGNED(long_long, ulong_long); // Casts nonnegative integer to unsigned. template -inline typename MakeUnsigned::Type to_unsigned(Int value) { +inline typename make_unsigned::type to_unsigned(Int value) { FMT_ASSERT(value >= 0, "negative value"); - return static_cast::Type>(value); + return static_cast::type>(value); } // The number of characters to store in the MemoryBuffer object itself @@ -789,25 +790,26 @@ typedef basic_memory_buffer wmemory_buffer; \endrst */ template -class FixedBuffer : public basic_buffer { +class basic_fixed_buffer : public basic_buffer { public: /** \rst - Constructs a :class:`fmt::FixedBuffer` object for *array* of the + Constructs a :class:`fmt::basic_fixed_buffer` object for *array* of the given size. \endrst */ - FixedBuffer(Char *array, std::size_t size) + basic_fixed_buffer(Char *array, std::size_t size) : basic_buffer(array, size) {} /** \rst - Constructs a :class:`fmt::FixedBuffer` object for *array* of the + Constructs a :class:`fmt::basic_fixed_buffer` object for *array* of the size known at compile time. \endrst */ template - explicit FixedBuffer(Char (&array)[SIZE]) : basic_buffer(array, SIZE) {} + explicit basic_fixed_buffer(Char (&array)[SIZE]) + : basic_buffer(array, SIZE) {} protected: FMT_API void grow(std::size_t size); @@ -816,7 +818,7 @@ class FixedBuffer : public basic_buffer { namespace internal { template -class BasicCharTraits { +class basic_char_traits { public: #if FMT_SECURE_SCL typedef stdext::checked_array_iterator CharPtr; @@ -827,10 +829,10 @@ class BasicCharTraits { }; template -class CharTraits; +class char_traits; template <> -class CharTraits : public BasicCharTraits { +class char_traits : public basic_char_traits { private: // Conversion from wchar_t to char is not allowed. static char convert(wchar_t); @@ -845,7 +847,7 @@ class CharTraits : public BasicCharTraits { }; template <> -class CharTraits : public BasicCharTraits { +class char_traits : public basic_char_traits { public: static wchar_t convert(char value) { return value; } static wchar_t convert(wchar_t value) { return value; } @@ -855,39 +857,37 @@ class CharTraits : public BasicCharTraits { const wchar_t *format, unsigned width, int precision, T value); }; -// Checks if a number is negative - used to avoid warnings. -template -struct SignChecker { - template - static bool is_negative(T value) { return value < 0; } -}; +template +struct enable_if {}; -template <> -struct SignChecker { - template - static bool is_negative(T) { return false; } -}; +template +struct enable_if { typedef T type; }; + +template +struct conditional { typedef T type; }; + +template +struct conditional { typedef F type; }; // Returns true if value is negative, false otherwise. // Same as (value < 0) but doesn't produce warnings if T is an unsigned type. template -inline bool is_negative(T value) { - return SignChecker::is_signed>::is_negative(value); +inline typename enable_if::is_signed, bool>::type + is_negative(T value) { + return value < 0; +} +template +inline typename enable_if::is_signed, bool>::type + is_negative(T) { + return false; } -// Selects uint32_t if FitsIn32Bits is true, uint64_t otherwise. -template -struct TypeSelector { typedef uint32_t Type; }; - -template <> -struct TypeSelector { typedef uint64_t Type; }; - template -struct IntTraits { +struct int_traits { // Smallest of uint32_t and uint64_t that is large enough to represent // all values of T. - typedef typename - TypeSelector::digits <= 32>::Type MainType; + typedef typename conditional< + std::numeric_limits::digits <= 32, uint32_t, uint64_t>::type main_type; }; FMT_API void report_unknown_type(char code, const char *type); @@ -895,7 +895,7 @@ FMT_API void report_unknown_type(char code, const char *type); // Static data is placed in this class template to allow header-only // configuration. template -struct FMT_API BasicData { +struct FMT_API basic_data { static const uint32_t POWERS_OF_10_32[]; static const uint64_t POWERS_OF_10_64[]; static const char DIGITS[]; @@ -908,10 +908,10 @@ struct FMT_API BasicData { #endif #if FMT_USE_EXTERN_TEMPLATES && !defined(FMT_HEADER_ONLY) -extern template struct BasicData; +extern template struct basic_data; #endif -typedef BasicData<> Data; +typedef basic_data<> data; #ifdef FMT_BUILTIN_CLZLL // Returns the number of decimal digits in n. Leading zeros are not counted @@ -920,7 +920,7 @@ inline unsigned count_digits(uint64_t n) { // Based on http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10 // and the benchmark https://github.com/localvoid/cxx-benchmark-count-digits. int t = (64 - FMT_BUILTIN_CLZLL(n | 1)) * 1233 >> 12; - return to_unsigned(t) - (n < Data::POWERS_OF_10_64[t]) + 1; + return to_unsigned(t) - (n < data::POWERS_OF_10_64[t]) + 1; } #else // Fallback version of count_digits used when __builtin_clz is not available. @@ -944,18 +944,18 @@ inline unsigned count_digits(uint64_t n) { // Optional version of count_digits for better performance on 32-bit platforms. inline unsigned count_digits(uint32_t n) { int t = (32 - FMT_BUILTIN_CLZ(n | 1)) * 1233 >> 12; - return to_unsigned(t) - (n < Data::POWERS_OF_10_32[t]) + 1; + return to_unsigned(t) - (n < data::POWERS_OF_10_32[t]) + 1; } #endif // A functor that doesn't add a thousands separator. -struct NoThousandsSep { +struct no_thousands_sep { template void operator()(Char *) {} }; // A functor that adds a thousands separator. -class ThousandsSep { +class add_thousands_sep { private: fmt::string_view sep_; @@ -963,7 +963,8 @@ class ThousandsSep { unsigned digit_index_; public: - explicit ThousandsSep(fmt::string_view sep) : sep_(sep), digit_index_(0) {} + explicit add_thousands_sep(fmt::string_view sep) + : sep_(sep), digit_index_(0) {} template void operator()(Char *&buffer) { @@ -988,9 +989,9 @@ inline void format_decimal(Char *buffer, UInt value, unsigned num_digits, // "Three Optimization Tips for C++". See speed-test for a comparison. unsigned index = static_cast((value % 100) * 2); value /= 100; - *--buffer = Data::DIGITS[index + 1]; + *--buffer = data::DIGITS[index + 1]; thousands_sep(buffer); - *--buffer = Data::DIGITS[index]; + *--buffer = data::DIGITS[index]; thousands_sep(buffer); } if (value < 10) { @@ -998,14 +999,14 @@ inline void format_decimal(Char *buffer, UInt value, unsigned num_digits, return; } unsigned index = static_cast(value * 2); - *--buffer = Data::DIGITS[index + 1]; + *--buffer = data::DIGITS[index + 1]; thousands_sep(buffer); - *--buffer = Data::DIGITS[index]; + *--buffer = data::DIGITS[index]; } template inline void format_decimal(Char *buffer, UInt value, unsigned num_digits) { - return format_decimal(buffer, value, num_digits, NoThousandsSep()); + return format_decimal(buffer, value, num_digits, no_thousands_sep()); } #ifndef _WIN32 @@ -1019,12 +1020,12 @@ inline void format_decimal(Char *buffer, UInt value, unsigned num_digits) { #if FMT_USE_WINDOWS_H // A converter from UTF-8 to UTF-16. // It is only provided for Windows since other systems support UTF-8 natively. -class UTF8ToUTF16 { +class utf8_to_utf16 { private: - MemoryBuffer buffer_; + wmemory_buffer buffer_; public: - FMT_API explicit UTF8ToUTF16(string_view s); + FMT_API explicit utf8_to_utf16(string_view s); operator wstring_view() const { return wstring_view(&buffer_[0], size()); } size_t size() const { return buffer_.size() - 1; } const wchar_t *c_str() const { return &buffer_[0]; } @@ -1035,7 +1036,7 @@ class UTF8ToUTF16 { // It is only provided for Windows since other systems support UTF-8 natively. class UTF16ToUTF8 { private: - MemoryBuffer buffer_; + memory_buffer buffer_; public: UTF16ToUTF8() {} @@ -1055,21 +1056,6 @@ FMT_API void format_windows_error(fmt::buffer &out, int error_code, fmt::string_view message) FMT_NOEXCEPT; #endif -template -struct EnableIf {}; - -template -struct EnableIf { typedef T type; }; - -template -struct Conditional { typedef T type; }; - -template -struct Conditional { typedef F type; }; - -template -struct False { enum { value = 0 }; }; - template struct Null {}; @@ -1146,7 +1132,7 @@ struct string_value { }; template -struct CustomValue { +struct custom_value { typedef void (*FormatFunc)( basic_buffer &buffer, const void *arg, void *ctx); @@ -1229,7 +1215,7 @@ class value { string_value sstring; string_value ustring; string_value tstring; - CustomValue custom; + custom_value custom; }; typedef typename Context::char_type Char; @@ -1358,7 +1344,7 @@ class value { template value(const T &value, - typename EnableIf::value, int>::type = 0) { + typename enable_if::value, int>::type = 0) { static_assert(internal::type() == internal::CUSTOM, "invalid type"); this->custom.value = &value; this->custom.format = &format_custom_arg; @@ -1366,7 +1352,7 @@ class value { template value(const T &value, - typename EnableIf::value, int>::type = 0) { + typename enable_if::value, int>::type = 0) { static_assert(internal::type() == internal::INT, "invalid type"); this->int_value = value; } @@ -1528,10 +1514,10 @@ inline fmt::string_view thousands_sep(...) { return ""; } template void format_value(basic_buffer &, const T &, Formatter &, const Char *) { - FMT_STATIC_ASSERT(False::value, + FMT_STATIC_ASSERT(sizeof(T) < 0, "Cannot format argument. To enable the use of ostream " "operator<< include fmt/ostream.h. Otherwise provide " - "an overload of format_arg."); + "an overload of format_value."); } template @@ -1933,18 +1919,18 @@ class ArgFormatterBase { } template - void write_str(basic_string_view value, - typename EnableIf< - std::is_same::value && - std::is_same::value, int>::type = 0) { + typename enable_if< + std::is_same::value && + std::is_same::value>::type + write_str(basic_string_view value) { writer_.write_str(value, spec_); } template - void write_str(basic_string_view value, - typename EnableIf< - !std::is_same::value || - !std::is_same::value, int>::type = 0) { + typename enable_if< + !std::is_same::value || + !std::is_same::value>::type + write_str(basic_string_view value) { // Do nothing. } @@ -1994,7 +1980,7 @@ class ArgFormatterBase { if (spec_.align_ == ALIGN_NUMERIC || spec_.flags_ != 0) FMT_THROW(format_error("invalid format specifier for char")); typedef typename basic_writer::CharPtr CharPtr; - Char fill = internal::CharTraits::cast(spec_.fill()); + Char fill = internal::char_traits::cast(spec_.fill()); CharPtr out = CharPtr(); const unsigned CHAR_WIDTH = 1; if (spec_.width_ > CHAR_WIDTH) { @@ -2012,7 +1998,7 @@ class ArgFormatterBase { } else { out = writer_.grow_buffer(CHAR_WIDTH); } - *out = internal::CharTraits::cast(value); + *out = internal::char_traits::cast(value); } void operator()(const char *value) { @@ -2116,7 +2102,7 @@ class arg_formatter : public internal::ArgFormatterBase { using internal::ArgFormatterBase::operator(); /** Formats an argument of a custom (user-defined) type. */ - void operator()(internal::CustomValue c) { + void operator()(internal::custom_value c) { c.format(this->writer().buffer(), c.value, &ctx_); } }; @@ -2260,7 +2246,7 @@ class basic_writer { FMT_DISALLOW_COPY_AND_ASSIGN(basic_writer); - typedef typename internal::CharTraits::CharPtr CharPtr; + typedef typename internal::char_traits::CharPtr CharPtr; #if FMT_SECURE_SCL // Returns pointer value. @@ -2294,8 +2280,8 @@ class basic_writer { // Writes a decimal integer. template void write_decimal(Int value) { - typedef typename internal::IntTraits::MainType MainType; - MainType abs_value = static_cast(value); + typedef typename internal::int_traits::main_type main_type; + main_type abs_value = static_cast(value); if (internal::is_negative(value)) { abs_value = 0 - abs_value; *write_unsigned_decimal(abs_value, 1) = '-'; @@ -2478,7 +2464,7 @@ typename basic_writer::CharPtr basic_writer::write_str( CharPtr out = CharPtr(); if (spec.width() > size) { out = grow_buffer(spec.width()); - Char fill = internal::CharTraits::cast(spec.fill()); + Char fill = internal::char_traits::cast(spec.fill()); if (spec.align() == ALIGN_RIGHT) { std::uninitialized_fill_n(out, spec.width() - size, fill); out += spec.width() - size; @@ -2499,7 +2485,7 @@ template void basic_writer::write_str( basic_string_view s, const format_specs &spec) { // Check if StrChar is convertible to Char. - internal::CharTraits::convert(StrChar()); + internal::char_traits::convert(StrChar()); if (spec.type_ && spec.type_ != 's') internal::report_unknown_type(spec.type_, "string"); const StrChar *str_value = s.data(); @@ -2521,7 +2507,7 @@ typename basic_writer::CharPtr basic_writer::fill_padding( std::size_t content_size, wchar_t fill) { std::size_t padding = total_size - content_size; std::size_t left_padding = padding / 2; - Char fill_char = internal::CharTraits::cast(fill); + Char fill_char = internal::char_traits::cast(fill); std::uninitialized_fill_n(buffer, left_padding, fill_char); buffer += left_padding; CharPtr content = buffer; @@ -2537,7 +2523,7 @@ typename basic_writer::CharPtr basic_writer::prepare_int_buffer( const char *prefix, unsigned prefix_size) { unsigned width = spec.width(); Alignment align = spec.align(); - Char fill = internal::CharTraits::cast(spec.fill()); + Char fill = internal::char_traits::cast(spec.fill()); if (spec.precision() > static_cast(num_digits)) { // Octal prefix '0' is counted as a digit, so ignore it if precision // is specified. @@ -2597,7 +2583,7 @@ template template void basic_writer::write_int(T value, Spec spec) { unsigned prefix_size = 0; - typedef typename internal::IntTraits::MainType UnsignedType; + typedef typename internal::int_traits::main_type UnsignedType; UnsignedType abs_value = static_cast(value); char prefix[4] = ""; if (internal::is_negative(value)) { @@ -2673,7 +2659,8 @@ void basic_writer::write_int(T value, Spec spec) { unsigned size = static_cast( num_digits + sep.size() * ((num_digits - 1) / 3)); CharPtr p = prepare_int_buffer(size, spec, prefix, prefix_size) + 1; - internal::format_decimal(get(p), abs_value, 0, internal::ThousandsSep(sep)); + internal::format_decimal(get(p), abs_value, 0, + internal::add_thousands_sep(sep)); break; } default: @@ -2784,7 +2771,7 @@ void basic_writer::write_double(T value, const format_specs &spec) { *format_ptr = '\0'; // Format using snprintf. - Char fill = internal::CharTraits::cast(spec.fill()); + Char fill = internal::char_traits::cast(spec.fill()); unsigned n = 0; Char *start = 0; for (;;) { @@ -2799,7 +2786,7 @@ void basic_writer::write_double(T value, const format_specs &spec) { } #endif start = &buffer_[offset]; - int result = internal::CharTraits::format_float( + int result = internal::char_traits::format_float( start, buffer_size, format, width_for_sprintf, spec.precision(), value); if (result >= 0) { n = internal::to_unsigned(result); @@ -3015,16 +3002,16 @@ class FormatInt { // "Three Optimization Tips for C++". See speed-test for a comparison. unsigned index = static_cast((value % 100) * 2); value /= 100; - *--buffer_end = internal::Data::DIGITS[index + 1]; - *--buffer_end = internal::Data::DIGITS[index]; + *--buffer_end = internal::data::DIGITS[index + 1]; + *--buffer_end = internal::data::DIGITS[index]; } if (value < 10) { *--buffer_end = static_cast('0' + value); return buffer_end; } unsigned index = static_cast(value * 2); - *--buffer_end = internal::Data::DIGITS[index + 1]; - *--buffer_end = internal::Data::DIGITS[index]; + *--buffer_end = internal::data::DIGITS[index + 1]; + *--buffer_end = internal::data::DIGITS[index]; return buffer_end; } @@ -3079,8 +3066,8 @@ class FormatInt { // write a terminating null character. template inline void format_decimal(char *&buffer, T value) { - typedef typename internal::IntTraits::MainType MainType; - MainType abs_value = static_cast(value); + typedef typename internal::int_traits::main_type main_type; + main_type abs_value = static_cast(value); if (internal::is_negative(value)) { *buffer++ = '-'; abs_value = 0 - abs_value; @@ -3091,8 +3078,8 @@ inline void format_decimal(char *&buffer, T value) { return; } unsigned index = static_cast(abs_value * 2); - *buffer++ = internal::Data::DIGITS[index]; - *buffer++ = internal::Data::DIGITS[index + 1]; + *buffer++ = internal::data::DIGITS[index]; + *buffer++ = internal::data::DIGITS[index + 1]; return; } unsigned num_digits = internal::count_digits(abs_value); @@ -3211,7 +3198,7 @@ class CustomFormatter { CustomFormatter(basic_buffer &buffer, Context &ctx) : buffer_(buffer), ctx_(ctx) {} - bool operator()(internal::CustomValue custom) { + bool operator()(internal::custom_value custom) { custom.format(buffer_, custom.value, &ctx_); return true; } diff --git a/fmt/ostream.cc b/fmt/ostream.cc index f9136482..34c0bc99 100644 --- a/fmt/ostream.cc +++ b/fmt/ostream.cc @@ -14,7 +14,7 @@ namespace fmt { namespace internal { FMT_FUNC void write(std::ostream &os, buffer &buf) { const char *data = buf.data(); - typedef internal::MakeUnsigned::Type UnsignedStreamSize; + typedef internal::make_unsigned::type UnsignedStreamSize; UnsignedStreamSize size = buf.size(); UnsignedStreamSize max_size = internal::to_unsigned((std::numeric_limits::max)()); diff --git a/fmt/printf.h b/fmt/printf.h index 02c33fba..c77100a8 100644 --- a/fmt/printf.h +++ b/fmt/printf.h @@ -101,7 +101,7 @@ class ArgConverter { typename std::enable_if::value>::type operator()(U value) { bool is_signed = type_ == 'd' || type_ == 'i'; - typedef typename internal::Conditional< + typedef typename internal::conditional< is_same::value, U, T>::type TargetType; typedef basic_context context; if (sizeof(TargetType) <= sizeof(int)) { @@ -110,7 +110,7 @@ class ArgConverter { arg_ = internal::make_arg( static_cast(static_cast(value))); } else { - typedef typename internal::MakeUnsigned::Type Unsigned; + typedef typename internal::make_unsigned::type Unsigned; arg_ = internal::make_arg( static_cast(static_cast(value))); } @@ -122,7 +122,7 @@ class ArgConverter { arg_ = internal::make_arg(static_cast(value)); } else { arg_ = internal::make_arg( - static_cast::Type>(value)); + static_cast::type>(value)); } } } @@ -183,7 +183,7 @@ class PrintfWidthHandler { template typename std::enable_if::value, unsigned>::type operator()(T value) { - typedef typename internal::IntTraits::MainType UnsignedType; + typedef typename internal::int_traits::main_type UnsignedType; UnsignedType width = static_cast(value); if (internal::is_negative(value)) { spec_.align_ = ALIGN_LEFT; @@ -285,7 +285,7 @@ class printf_arg_formatter : public internal::ArgFormatterBase { } /** Formats an argument of a custom (user-defined) type. */ - void operator()(internal::CustomValue c) { + void operator()(internal::custom_value c) { const Char format_str[] = {'}', '\0'}; auto args = basic_args>(); basic_context ctx(format_str, args); diff --git a/test/format-test.cc b/test/format-test.cc index 2e1baaf2..14b95361 100644 --- a/test/format-test.cc +++ b/test/format-test.cc @@ -1531,7 +1531,7 @@ class MockArgFormatter : public fmt::internal::ArgFormatterBase { void operator()(int value) { call(value); } - void operator()(fmt::internal::CustomValue) {} + void operator()(fmt::internal::custom_value) {} }; void custom_vformat(fmt::CStringRef format_str, fmt::args args) { diff --git a/test/ostream-test.cc b/test/ostream-test.cc index 2ab22248..fd40a2a1 100644 --- a/test/ostream-test.cc +++ b/test/ostream-test.cc @@ -155,7 +155,7 @@ TEST(OStreamTest, WriteToOStreamMaxSize) { const char *data = 0; std::size_t size = max_size; do { - typedef fmt::internal::MakeUnsigned::Type UStreamSize; + typedef fmt::internal::make_unsigned::type UStreamSize; UStreamSize n = std::min( size, fmt::internal::to_unsigned(max_streamsize)); EXPECT_CALL(streambuf, xsputn(data, static_cast(n))) diff --git a/test/posix-mock-test.cc b/test/posix-mock-test.cc index 6b7104fc..5a337b6e 100644 --- a/test/posix-mock-test.cc +++ b/test/posix-mock-test.cc @@ -279,7 +279,7 @@ TEST(FileTest, Size) { EXPECT_GE(f.size(), 0); EXPECT_EQ(content.size(), static_cast(f.size())); #ifdef _WIN32 - fmt::internal::MemoryBuffer message; + fmt::memory_buffer message; fmt::internal::format_windows_error( message, ERROR_ACCESS_DENIED, "cannot get file size"); fstat_sim = ERROR; diff --git a/test/printf-test.cc b/test/printf-test.cc index 65bcca72..312f714f 100644 --- a/test/printf-test.cc +++ b/test/printf-test.cc @@ -277,11 +277,11 @@ TEST(PrintfTest, DynamicPrecision) { } template -struct MakeSigned { typedef T Type; }; +struct make_signed { typedef T type; }; #define SPECIALIZE_MAKE_SIGNED(T, S) \ template <> \ - struct MakeSigned { typedef S Type; } + struct make_signed { typedef S type; } SPECIALIZE_MAKE_SIGNED(char, signed char); SPECIALIZE_MAKE_SIGNED(unsigned char, signed char); @@ -306,13 +306,13 @@ void TestLength(const char *length_spec, U value) { signed_value = static_cast(value); unsigned_value = static_cast(value); } - using fmt::internal::MakeUnsigned; + using fmt::internal::make_unsigned; if (sizeof(U) <= sizeof(int) && sizeof(int) < sizeof(T)) { signed_value = static_cast(value); - unsigned_value = static_cast::Type>(value); + unsigned_value = static_cast::type>(value); } else { - signed_value = static_cast::Type>(value); - unsigned_value = static_cast::Type>(value); + signed_value = static_cast::type>(value); + unsigned_value = static_cast::type>(value); } std::ostringstream os; os << signed_value; diff --git a/test/util-test.cc b/test/util-test.cc index f9ca8e5a..387203e5 100644 --- a/test/util-test.cc +++ b/test/util-test.cc @@ -383,7 +383,7 @@ TEST(MemoryBufferTest, ExceptionInDeallocate) { TEST(FixedBufferTest, Ctor) { char array[10] = "garbage"; - fmt::FixedBuffer buffer(array, sizeof(array)); + fmt::basic_fixed_buffer buffer(array, sizeof(array)); EXPECT_EQ(0u, buffer.size()); EXPECT_EQ(10u, buffer.capacity()); EXPECT_EQ(array, buffer.data()); @@ -391,7 +391,7 @@ TEST(FixedBufferTest, Ctor) { TEST(FixedBufferTest, CompileTimeSizeCtor) { char array[10] = "garbage"; - fmt::FixedBuffer buffer(array); + fmt::basic_fixed_buffer buffer(array); EXPECT_EQ(0u, buffer.size()); EXPECT_EQ(10u, buffer.capacity()); EXPECT_EQ(array, buffer.data()); @@ -399,7 +399,7 @@ TEST(FixedBufferTest, CompileTimeSizeCtor) { TEST(FixedBufferTest, BufferOverflow) { char array[10]; - fmt::FixedBuffer buffer(array); + fmt::basic_fixed_buffer buffer(array); buffer.resize(10); EXPECT_THROW_MSG(buffer.resize(11), std::runtime_error, "buffer overflow"); } @@ -445,7 +445,7 @@ namespace fmt { namespace internal { template -bool operator==(CustomValue lhs, CustomValue rhs) { +bool operator==(custom_value lhs, custom_value rhs) { return lhs.value == rhs.value; } } @@ -575,10 +575,10 @@ TEST(UtilTest, PointerArg) { TEST(UtilTest, CustomArg) { ::Test test; - typedef MockVisitor> Visitor; + typedef MockVisitor> Visitor; testing::StrictMock visitor; EXPECT_CALL(visitor, visit(_)).WillOnce( - testing::Invoke([&](fmt::internal::CustomValue custom) { + testing::Invoke([&](fmt::internal::custom_value custom) { EXPECT_EQ(&test, custom.value); fmt::memory_buffer buffer; fmt::context ctx("}", fmt::args()); @@ -659,7 +659,7 @@ TEST(UtilTest, UTF16ToUTF8) { TEST(UtilTest, UTF8ToUTF16) { std::string s = "лошадка"; - fmt::internal::UTF8ToUTF16 u(s.c_str()); + fmt::internal::utf8_to_utf16 u(s.c_str()); EXPECT_EQ(L"\x043B\x043E\x0448\x0430\x0434\x043A\x0430", u.str()); EXPECT_EQ(7, u.size()); } @@ -668,7 +668,7 @@ template void check_utf_conversion_error( const char *message, fmt::basic_string_view str = fmt::basic_string_view(0, 0)) { - fmt::internal::MemoryBuffer out; + fmt::memory_buffer out; fmt::internal::format_windows_error(out, ERROR_INVALID_PARAMETER, message); fmt::SystemError error(0, ""); try { @@ -687,8 +687,8 @@ TEST(UtilTest, UTF16ToUTF8Error) { TEST(UtilTest, UTF8ToUTF16Error) { const char *message = "cannot convert string from UTF-8 to UTF-16"; - check_utf_conversion_error(message); - check_utf_conversion_error( + check_utf_conversion_error(message); + check_utf_conversion_error( message, fmt::string_view("foo", INT_MAX + 1u)); } @@ -753,7 +753,7 @@ TEST(UtilTest, FormatWindowsError) { reinterpret_cast(&message), 0, 0); fmt::internal::UTF16ToUTF8 utf8_message(message); LocalFree(message); - fmt::internal::MemoryBuffer actual_message; + fmt::memory_buffer actual_message; fmt::internal::format_windows_error( actual_message, ERROR_FILE_EXISTS, "test"); EXPECT_EQ(fmt::format("test: {}", utf8_message.str()), @@ -780,7 +780,7 @@ TEST(UtilTest, FormatLongWindowsError) { } fmt::internal::UTF16ToUTF8 utf8_message(message); LocalFree(message); - fmt::internal::MemoryBuffer actual_message; + fmt::memory_buffer actual_message; fmt::internal::format_windows_error( actual_message, provisioning_not_allowed, "test"); EXPECT_EQ(fmt::format("test: {}", utf8_message.str()), @@ -793,7 +793,7 @@ TEST(UtilTest, WindowsError) { } TEST(UtilTest, ReportWindowsError) { - fmt::internal::MemoryBuffer out; + fmt::memory_buffer out; fmt::internal::format_windows_error(out, ERROR_FILE_EXISTS, "test error"); out.push_back('\n'); EXPECT_WRITE(stderr, @@ -820,13 +820,13 @@ TEST(UtilTest, IsEnumConvertibleToInt) { template bool check_enable_if( - typename fmt::internal::EnableIf::type *) { + typename fmt::internal::enable_if::type *) { return true; } template bool check_enable_if( - typename fmt::internal::EnableIf::type *) { + typename fmt::internal::enable_if::type *) { return false; } @@ -839,10 +839,10 @@ TEST(UtilTest, EnableIf) { TEST(UtilTest, Conditional) { int i = 0; - fmt::internal::Conditional::type *pi = &i; + fmt::internal::conditional::type *pi = &i; (void)pi; char c = 0; - fmt::internal::Conditional::type *pc = &c; + fmt::internal::conditional::type *pc = &c; (void)pc; } From c333dca065d98e9ca75c3f4cd645835ba670b9bf Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sun, 19 Feb 2017 08:41:38 -0800 Subject: [PATCH 095/340] Follow standard naming conventions --- fmt/format.cc | 37 +++--- fmt/format.h | 259 +++++++++++++++++---------------------- fmt/ostream.h | 10 +- fmt/posix.cc | 28 ++--- fmt/posix.h | 4 +- fmt/printf.h | 6 +- test/format-test.cc | 8 +- test/gtest-extra-test.cc | 6 +- test/gtest-extra.cc | 2 +- test/ostream-test.cc | 2 +- test/posix-mock-test.cc | 2 +- test/posix-test.cc | 2 +- test/util-test.cc | 26 ++-- 13 files changed, 180 insertions(+), 212 deletions(-) diff --git a/fmt/format.cc b/fmt/format.cc index b4a8f078..d1a449d6 100644 --- a/fmt/format.cc +++ b/fmt/format.cc @@ -70,18 +70,17 @@ // Dummy implementations of strerror_r and strerror_s called if corresponding // system functions are not available. -static inline fmt::internal::Null<> strerror_r(int, char *, ...) { - return fmt::internal::Null<>(); +static inline fmt::internal::null<> strerror_r(int, char *, ...) { + return fmt::internal::null<>(); } -static inline fmt::internal::Null<> strerror_s(char *, std::size_t, ...) { - return fmt::internal::Null<>(); +static inline fmt::internal::null<> strerror_s(char *, std::size_t, ...) { + return fmt::internal::null<>(); } namespace fmt { -FMT_FUNC internal::RuntimeError::~RuntimeError() throw() {} FMT_FUNC format_error::~format_error() throw() {} -FMT_FUNC SystemError::~SystemError() throw() {} +FMT_FUNC system_error::~system_error() throw() {} namespace { @@ -146,7 +145,7 @@ int safe_strerror( } // Handle the case when strerror_r is not available. - int handle(internal::Null<>) { + int handle(internal::null<>) { return fallback(strerror_s(buffer_, buffer_size_, error_code_)); } @@ -158,7 +157,7 @@ int safe_strerror( } // Fallback to strerror if strerror_r and strerror_s are not available. - int fallback(internal::Null<>) { + int fallback(internal::null<>) { errno = 0; buffer_ = strerror(error_code_); return errno; @@ -214,7 +213,7 @@ void report_error(FormatFunc func, int error_code, } } // namespace -FMT_FUNC void SystemError::init( +FMT_FUNC void system_error::init( int err_code, CStringRef format_str, args args) { error_code_ = err_code; memory_buffer buffer; @@ -301,28 +300,28 @@ FMT_FUNC void internal::report_unknown_type(char code, const char *type) { FMT_FUNC internal::utf8_to_utf16::utf8_to_utf16(string_view s) { static const char ERROR_MSG[] = "cannot convert string from UTF-8 to UTF-16"; if (s.size() > INT_MAX) - FMT_THROW(WindowsError(ERROR_INVALID_PARAMETER, ERROR_MSG)); + FMT_THROW(windows_error(ERROR_INVALID_PARAMETER, ERROR_MSG)); int s_size = static_cast(s.size()); int length = MultiByteToWideChar( CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size, 0, 0); if (length == 0) - FMT_THROW(WindowsError(GetLastError(), ERROR_MSG)); + FMT_THROW(windows_error(GetLastError(), ERROR_MSG)); buffer_.resize(length + 1); length = MultiByteToWideChar( CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size, &buffer_[0], length); if (length == 0) - FMT_THROW(WindowsError(GetLastError(), ERROR_MSG)); + FMT_THROW(windows_error(GetLastError(), ERROR_MSG)); buffer_[length] = 0; } -FMT_FUNC internal::UTF16ToUTF8::UTF16ToUTF8(wstring_view s) { +FMT_FUNC internal::utf16_to_utf8::utf16_to_utf8(wstring_view s) { if (int error_code = convert(s)) { - FMT_THROW(WindowsError(error_code, + FMT_THROW(windows_error(error_code, "cannot convert string from UTF-16 to UTF-8")); } } -FMT_FUNC int internal::UTF16ToUTF8::convert(wstring_view s) { +FMT_FUNC int internal::utf16_to_utf8::convert(wstring_view s) { if (s.size() > INT_MAX) return ERROR_INVALID_PARAMETER; int s_size = static_cast(s.size()); @@ -338,7 +337,7 @@ FMT_FUNC int internal::UTF16ToUTF8::convert(wstring_view s) { return 0; } -FMT_FUNC void WindowsError::init( +FMT_FUNC void windows_error::init( int err_code, CStringRef format_str, args args) { error_code_ = err_code; memory_buffer buffer; @@ -359,7 +358,7 @@ FMT_FUNC void internal::format_windows_error( 0, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), system_message, static_cast(buffer.size()), 0); if (result != 0) { - UTF16ToUTF8 utf8_message; + utf16_to_utf8 utf8_message; if (utf8_message.convert(system_message) == ERROR_SUCCESS) { basic_writer w(out); w.write(message); @@ -459,7 +458,7 @@ template struct internal::basic_data; template void basic_fixed_buffer::grow(std::size_t); -template void internal::ArgMap::init(const args &args); +template void internal::arg_map::init(const args &args); template void printf_context::format(buffer &); @@ -477,7 +476,7 @@ template class basic_context; template void basic_fixed_buffer::grow(std::size_t); -template void internal::ArgMap::init(const wargs &args); +template void internal::arg_map::init(const wargs &args); template void printf_context::format(wbuffer &); diff --git a/fmt/format.h b/fmt/format.h index eea1b83e..b4b41fbd 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -555,7 +555,7 @@ inline typename make_unsigned::type to_unsigned(Int value) { return static_cast::type>(value); } -// The number of characters to store in the MemoryBuffer object itself +// The number of characters to store in the basic_memory_buffer object itself // to avoid dynamic memory allocation. enum { INLINE_BUFFER_SIZE = 500 }; @@ -1034,13 +1034,13 @@ class utf8_to_utf16 { // A converter from UTF-16 to UTF-8. // It is only provided for Windows since other systems support UTF-8 natively. -class UTF16ToUTF8 { +class utf16_to_utf8 { private: memory_buffer buffer_; public: - UTF16ToUTF8() {} - FMT_API explicit UTF16ToUTF8(wstring_view s); + utf16_to_utf8() {} + FMT_API explicit utf16_to_utf8(wstring_view s); operator string_view() const { return string_view(&buffer_[0], size()); } size_t size() const { return buffer_.size() - 1; } const char *c_str() const { return &buffer_[0]; } @@ -1057,59 +1057,59 @@ FMT_API void format_windows_error(fmt::buffer &out, int error_code, #endif template -struct Null {}; +struct null {}; // A helper class template to enable or disable overloads taking wide // characters and strings in value's constructor. template -struct WCharHelper { - typedef Null Supported; - typedef T Unsupported; +struct wchar_helper { + typedef null supported; + typedef T unsupported; }; template -struct WCharHelper { - typedef T Supported; - typedef Null Unsupported; +struct wchar_helper { + typedef T supported; + typedef null unsupported; }; -typedef char Yes[1]; -typedef char No[2]; +typedef char yes[1]; +typedef char no[2]; template T &get(); -// These are non-members to workaround an overload resolution bug in bcc32. -Yes &convert(fmt::ulong_long); -No &convert(...); +yes &convert(fmt::ulong_long); +no &convert(...); template -struct ConvertToIntImpl { +struct convert_to_int_impl { enum { value = ENABLE_CONVERSION }; }; template -struct ConvertToIntImpl2 { +struct convert_to_int_impl2 { enum { value = false }; }; template -struct ConvertToIntImpl2 { +struct convert_to_int_impl2 { enum { // Don't convert numeric types. - value = ConvertToIntImpl::is_specialized>::value + value = convert_to_int_impl< + T, !std::numeric_limits::is_specialized>::value }; }; template -struct ConvertToInt { - enum { enable_conversion = sizeof(convert(get())) == sizeof(Yes) }; - enum { value = ConvertToIntImpl2::value }; +struct convert_to_int { + enum { enable_conversion = sizeof(convert(get())) == sizeof(yes) }; + enum { value = convert_to_int_impl2::value }; }; #define FMT_DISABLE_CONVERSION_TO_INT(Type) \ template <> \ - struct ConvertToInt { enum { value = 0 }; } + struct convert_to_int { enum { value = 0 }; } // Silence warnings about convering float to int. FMT_DISABLE_CONVERSION_TO_INT(float); @@ -1141,18 +1141,18 @@ struct custom_value { }; template -struct NamedArg; +struct named_arg; template -struct IsNamedArg : std::false_type {}; +struct is_named_arg : std::false_type {}; template -struct IsNamedArg< NamedArg > : std::true_type {}; +struct is_named_arg< named_arg > : std::true_type {}; template constexpr Type gettype() { - return IsNamedArg::value ? - NAMED_ARG : (ConvertToInt::value ? INT : CUSTOM); + return is_named_arg::value ? + NAMED_ARG : (convert_to_int::value ? INT : CUSTOM); } template <> constexpr Type gettype() { return BOOL; } @@ -1236,12 +1236,12 @@ class value { // fmt::format("{}", L"test"); // To fix this, use a wide format string: fmt::format(L"{}", L"test"). #if !FMT_MSC_VER || defined(_NATIVE_WCHAR_T_DEFINED) - value(typename WCharHelper::Unsupported); + value(typename wchar_helper::unsupported); #endif - value(typename WCharHelper::Unsupported); - value(typename WCharHelper::Unsupported); - value(typename WCharHelper::Unsupported); - value(typename WCharHelper::Unsupported); + value(typename wchar_helper::unsupported); + value(typename wchar_helper::unsupported); + value(typename wchar_helper::unsupported); + value(typename wchar_helper::unsupported); void set_string(string_view str) { this->string.value = str.data(); @@ -1305,7 +1305,7 @@ class value { FMT_MAKE_VALUE(char, int_value, CHAR) #if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED) - typedef typename WCharHelper::Supported WChar; + typedef typename wchar_helper::supported WChar; value(WChar value) { static_assert(internal::type() == internal::CHAR, "invalid type"); this->int_value = value; @@ -1329,7 +1329,7 @@ class value { FMT_MAKE_VALUE_(CStringRef, string.value, CSTRING, value.c_str()) #define FMT_MAKE_WSTR_VALUE(Type, TYPE) \ - value(typename WCharHelper::Supported value) { \ + value(typename wchar_helper::supported value) { \ static_assert(internal::type() == internal::TYPE, "invalid type"); \ set_string(value); \ } @@ -1344,7 +1344,7 @@ class value { template value(const T &value, - typename enable_if::value, int>::type = 0) { + typename enable_if::value, int>::type = 0) { static_assert(internal::type() == internal::CUSTOM, "invalid type"); this->custom.value = &value; this->custom.format = &format_custom_arg; @@ -1352,7 +1352,7 @@ class value { template value(const T &value, - typename enable_if::value, int>::type = 0) { + typename enable_if::value, int>::type = 0) { static_assert(internal::type() == internal::INT, "invalid type"); this->int_value = value; } @@ -1360,16 +1360,16 @@ class value { // Additional template param `Char_` is needed here because make_type always // uses char. template - value(const NamedArg &value) { + value(const named_arg &value) { static_assert( - internal::type &>() == internal::NAMED_ARG, + internal::type &>() == internal::NAMED_ARG, "invalid type"); this->pointer = &value; } }; template -class ArgMap; +class arg_map; template basic_arg make_arg(const T &value); @@ -1381,7 +1381,7 @@ template class basic_args; // A formatting argument. It is a trivially copyable/constructible type to -// allow storage in internal::MemoryBuffer. +// allow storage in basic_memory_buffer. template class basic_arg { private: @@ -1396,7 +1396,7 @@ class basic_arg { visit(Visitor &&vis, basic_arg arg); friend class basic_args; - friend class internal::ArgMap; + friend class internal::arg_map; public: basic_arg() : type_(internal::NONE) {} @@ -1476,8 +1476,8 @@ basic_arg make_arg(const T &value) { return arg; } -template struct LConvCheck { - LConvCheck(int) {} +template struct lconv_check { + lconv_check(int) {} }; // Returns the thousands separator for the current locale. @@ -1485,7 +1485,7 @@ template struct LConvCheck { // ``lconv`` is stubbed as an empty struct. template inline string_view thousands_sep( - LConv *lc, LConvCheck = 0) { + LConv *lc, lconv_check = 0) { return lc->thousands_sep; } @@ -1521,22 +1521,16 @@ void format_value(basic_buffer &, const T &, Formatter &, const Char *) { } template -struct NamedArg : basic_arg { +struct named_arg : basic_arg { typedef typename Context::char_type Char; basic_string_view name; template - NamedArg(basic_string_view argname, const T &value) + named_arg(basic_string_view argname, const T &value) : basic_arg(make_arg(value)), name(argname) {} }; -class RuntimeError : public std::runtime_error { - protected: - RuntimeError() : std::runtime_error("") {} - ~RuntimeError() throw(); -}; - template constexpr uint64_t make_type() { return type() | (make_type() << 4); @@ -1625,7 +1619,7 @@ class basic_args { (types_ & (mask << shift)) >> shift); } - friend class internal::ArgMap; + friend class internal::arg_map; void set_data(const internal::value *values) { values_ = values; } void set_data(const format_arg *args) { args_ = args; } @@ -1674,7 +1668,7 @@ class basic_args { typedef basic_args args; typedef basic_args wargs; -enum Alignment { +enum alignment { ALIGN_DEFAULT, ALIGN_LEFT, ALIGN_RIGHT, ALIGN_CENTER, ALIGN_NUMERIC }; @@ -1736,53 +1730,26 @@ constexpr format_spec_factory width; constexpr format_spec_factory type; // An empty format specifier. -struct EmptySpec {}; +struct empty_spec {}; -// A type specifier. -template -struct TypeSpec : EmptySpec { - Alignment align() const { return ALIGN_DEFAULT; } - unsigned width() const { return 0; } - int precision() const { return -1; } - bool flag(unsigned) const { return false; } - char type() const { return TYPE; } - char fill() const { return ' '; } -}; - -// A width specifier. -struct WidthSpec { +// An alignment specifier. +struct AlignSpec : empty_spec { unsigned width_; // Fill is always wchar_t and cast to char if necessary to avoid having // two specialization of WidthSpec and its subclasses. wchar_t fill_; + alignment align_; - WidthSpec(unsigned width, wchar_t fill) : width_(width), fill_(fill) {} + AlignSpec(unsigned width, wchar_t fill, alignment align = ALIGN_DEFAULT) + : width_(width), fill_(fill), align_(align) {} unsigned width() const { return width_; } wchar_t fill() const { return fill_; } -}; - -// An alignment specifier. -struct AlignSpec : WidthSpec { - Alignment align_; - - AlignSpec(unsigned width, wchar_t fill, Alignment align = ALIGN_DEFAULT) - : WidthSpec(width, fill), align_(align) {} - - Alignment align() const { return align_; } + alignment align() const { return align_; } int precision() const { return -1; } }; -// An alignment and type specifier. -template -struct AlignTypeSpec : AlignSpec { - AlignTypeSpec(unsigned width, wchar_t fill) : AlignSpec(width, fill) {} - - bool flag(unsigned) const { return false; } - char type() const { return TYPE; } -}; - // Format specifiers. template class basic_format_specs : public AlignSpec { @@ -1832,7 +1799,7 @@ typedef basic_format_specs format_specs; namespace internal { template -class ArgMap { +class arg_map { private: typedef typename Context::char_type Char; typedef std::vector< @@ -1857,10 +1824,10 @@ class ArgMap { }; template -void ArgMap::init(const basic_args &args) { +void arg_map::init(const basic_args &args) { if (!map_.empty()) return; - typedef internal::NamedArg NamedArg; + typedef internal::named_arg NamedArg; const NamedArg *named_arg = 0; bool use_values = args.type(MAX_PACKED_ARGS - 1) == internal::NONE; @@ -1902,7 +1869,7 @@ void ArgMap::init(const basic_args &args) { } template -class ArgFormatterBase { +class arg_formatter_base { public: typedef basic_format_specs format_specs; @@ -1910,7 +1877,7 @@ class ArgFormatterBase { basic_writer writer_; format_specs &spec_; - FMT_DISALLOW_COPY_AND_ASSIGN(ArgFormatterBase); + FMT_DISALLOW_COPY_AND_ASSIGN(arg_formatter_base); void write_pointer(const void *p) { spec_.flags_ = HASH_FLAG; @@ -1950,7 +1917,7 @@ class ArgFormatterBase { public: typedef Char char_type; - ArgFormatterBase(basic_buffer &b, format_specs &s) + arg_formatter_base(basic_buffer &b, format_specs &s) : writer_(b), spec_(s) {} void operator()(monostate) { @@ -2078,11 +2045,11 @@ class context_base { /** The default argument formatter. */ template -class arg_formatter : public internal::ArgFormatterBase { +class arg_formatter : public internal::arg_formatter_base { private: basic_context &ctx_; - typedef internal::ArgFormatterBase Base; + typedef internal::arg_formatter_base Base; public: typedef typename Base::format_specs format_specs; @@ -2097,9 +2064,9 @@ class arg_formatter : public internal::ArgFormatterBase { */ arg_formatter(basic_buffer &buffer, basic_context &ctx, format_specs &spec) - : internal::ArgFormatterBase(buffer, spec), ctx_(ctx) {} + : internal::arg_formatter_base(buffer, spec), ctx_(ctx) {} - using internal::ArgFormatterBase::operator(); + using internal::arg_formatter_base::operator(); /** Formats an argument of a custom (user-defined) type. */ void operator()(internal::custom_value c) { @@ -2115,7 +2082,7 @@ class basic_context : typedef Char char_type; private: - internal::ArgMap> map_; + internal::arg_map> map_; FMT_DISALLOW_COPY_AND_ASSIGN(basic_context); @@ -2149,40 +2116,41 @@ class basic_context : An error returned by an operating system or a language runtime, for example a file opening error. */ -class SystemError : public internal::RuntimeError { +class system_error : public std::runtime_error { private: void init(int err_code, CStringRef format_str, args args); protected: int error_code_; - SystemError() {} + system_error() : std::runtime_error("") {} public: /** \rst - Constructs a :class:`fmt::SystemError` object with a description + Constructs a :class:`fmt::system_error` object with a description formatted with `fmt::format_system_error`. *message* and additional arguments passed into the constructor are formatted similarly to `fmt::format`. **Example**:: - // This throws a SystemError with the description + // This throws a system_error with the description // cannot open file 'madeup': No such file or directory // or similar (system message may vary). const char *filename = "madeup"; std::FILE *file = std::fopen(filename, "r"); if (!file) - throw fmt::SystemError(errno, "cannot open file '{}'", filename); + throw fmt::system_error(errno, "cannot open file '{}'", filename); \endrst */ template - SystemError(int error_code, CStringRef message, const Args & ... args) { + system_error(int error_code, CStringRef message, const Args & ... args) + : std::runtime_error("") { init(error_code, message, make_args(args...)); } - ~SystemError() throw(); + ~system_error() throw(); int error_code() const { return error_code_; } }; @@ -2292,7 +2260,7 @@ class basic_writer { // Prepare a buffer for integer formatting. CharPtr prepare_int_buffer(unsigned num_digits, - const EmptySpec &, const char *prefix, unsigned prefix_size) { + const empty_spec &, const char *prefix, unsigned prefix_size) { unsigned size = prefix_size + num_digits; CharPtr p = grow_buffer(size); std::uninitialized_copy(prefix, prefix + prefix_size, p); @@ -2322,9 +2290,9 @@ class basic_writer { // and strings to a char buffer. If you want to print a wide string as a // pointer as std::ostream does, cast it to const void*. // Do not implement! - void operator<<(typename internal::WCharHelper::Unsupported); + void operator<<(typename internal::wchar_helper::unsupported); void operator<<( - typename internal::WCharHelper::Unsupported); + typename internal::wchar_helper::unsupported); // Appends floating-point length specifier to the format string. // The second argument is only used for overload resolution. @@ -2336,7 +2304,7 @@ class basic_writer { void append_float_length(Char *&, T) {} template - friend class internal::ArgFormatterBase; + friend class internal::arg_formatter_base; template friend class printf_arg_formatter; @@ -2427,7 +2395,7 @@ class basic_writer { buffer_.push_back(value); } - void write(typename internal::WCharHelper::Supported value) { + void write(typename internal::wchar_helper::supported value) { buffer_.push_back(value); } @@ -2442,7 +2410,7 @@ class basic_writer { } void write( - typename internal::WCharHelper::Supported value) { + typename internal::wchar_helper::supported value) { const char *str = value.data(); buffer_.append(str, str + value.size()); } @@ -2522,7 +2490,7 @@ typename basic_writer::CharPtr basic_writer::prepare_int_buffer( unsigned num_digits, const Spec &spec, const char *prefix, unsigned prefix_size) { unsigned width = spec.width(); - Alignment align = spec.align(); + alignment align = spec.align(); Char fill = internal::char_traits::cast(spec.fill()); if (spec.precision() > static_cast(num_digits)) { // Octal prefix '0' is counted as a digit, so ignore it if precision @@ -2833,14 +2801,14 @@ FMT_API void report_system_error(int error_code, #if FMT_USE_WINDOWS_H /** A Windows error. */ -class WindowsError : public SystemError { +class windows_error : public system_error { private: FMT_API void init(int error_code, CStringRef format_str, args args); public: /** \rst - Constructs a :class:`fmt::WindowsError` object with the description + Constructs a :class:`fmt::windows_error` object with the description of the form .. parsed-literal:: @@ -2854,20 +2822,20 @@ class WindowsError : public SystemError { **Example**:: - // This throws a WindowsError with the description + // This throws a windows_error with the description // cannot open file 'madeup': The system cannot find the file specified. // or similar (system message may vary). const char *filename = "madeup"; LPOFSTRUCT of = LPOFSTRUCT(); HFILE file = OpenFile(filename, &of, OF_READ); if (file == HFILE_ERROR) { - throw fmt::WindowsError(GetLastError(), - "cannot open file '{}'", filename); + throw fmt::windows_error(GetLastError(), + "cannot open file '{}'", filename); } \endrst */ template - WindowsError(int error_code, CStringRef message, const Args & ... args) { + windows_error(int error_code, CStringRef message, const Args & ... args) { init(error_code, message, make_args(args...)); } }; @@ -3098,22 +3066,22 @@ inline void format_decimal(char *&buffer, T value) { \endrst */ template -inline internal::NamedArg arg(string_view name, const T &arg) { - return internal::NamedArg(name, arg); +inline internal::named_arg arg(string_view name, const T &arg) { + return internal::named_arg(name, arg); } template -inline internal::NamedArg arg(wstring_view name, const T &arg) { - return internal::NamedArg(name, arg); +inline internal::named_arg arg(wstring_view name, const T &arg) { + return internal::named_arg(name, arg); } // The following two functions are deleted intentionally to disable // nested named arguments as in ``format("{}", arg("a", arg("b", 42)))``. template -void arg(string_view, const internal::NamedArg&) +void arg(string_view, const internal::named_arg&) FMT_DELETED_OR_UNDEFINED; template -void arg(wstring_view, const internal::NamedArg&) +void arg(wstring_view, const internal::named_arg&) FMT_DELETED_OR_UNDEFINED; } @@ -3163,7 +3131,8 @@ inline void require_numeric_argument( } } -struct IsUnsigned { +// An argument visitor that checks if argument is unsigned. +struct is_unsigned { template typename std::enable_if::value, bool>::type operator()(T value) { @@ -3181,7 +3150,7 @@ template void check_sign(const Char *&s, const basic_arg &arg) { char sign = static_cast(*s); require_numeric_argument(arg, sign); - if (visit(IsUnsigned(), arg)) { + if (visit(is_unsigned(), arg)) { FMT_THROW(format_error(fmt::format( "format specifier '{}' requires signed argument", sign))); } @@ -3189,13 +3158,13 @@ void check_sign(const Char *&s, const basic_arg &arg) { } template -class CustomFormatter { +class custom_formatter { private: basic_buffer &buffer_; Context &ctx_; public: - CustomFormatter(basic_buffer &buffer, Context &ctx) + custom_formatter(basic_buffer &buffer, Context &ctx) : buffer_(buffer), ctx_(ctx) {} bool operator()(internal::custom_value custom) { @@ -3208,16 +3177,16 @@ class CustomFormatter { }; template -struct IsInteger { +struct is_integer { enum { value = std::is_integral::value && !std::is_same::value && !std::is_same::value && !std::is_same::value }; }; -struct WidthHandler { +struct width_handler { template - typename std::enable_if::value, ulong_long>::type + typename std::enable_if::value, ulong_long>::type operator()(T value) { if (is_negative(value)) FMT_THROW(format_error("negative width")); @@ -3225,16 +3194,16 @@ struct WidthHandler { } template - typename std::enable_if::value, ulong_long>::type + typename std::enable_if::value, ulong_long>::type operator()(T value) { FMT_THROW(format_error("width is not integer")); return 0; } }; -struct PrecisionHandler { +struct precision_handler { template - typename std::enable_if::value, ulong_long>::type + typename std::enable_if::value, ulong_long>::type operator()(T value) { if (is_negative(value)) FMT_THROW(format_error("negative precision")); @@ -3242,7 +3211,7 @@ struct PrecisionHandler { } template - typename std::enable_if::value, ulong_long>::type + typename std::enable_if::value, ulong_long>::type operator()(T value) { FMT_THROW(format_error("precision is not integer")); return 0; @@ -3297,7 +3266,7 @@ void do_format_arg(basic_buffer &buffer, basic_arg arg, const Char *&s = ctx.ptr(); basic_format_specs spec; if (*s == ':') { - if (visit(internal::CustomFormatter(buffer, ctx), arg)) + if (visit(internal::custom_formatter(buffer, ctx), arg)) return; ++s; // Parse fill and alignment. @@ -3372,7 +3341,7 @@ void do_format_arg(basic_buffer &buffer, basic_arg arg, auto width_arg = ctx.parse_arg_id(); if (*s++ != '}') FMT_THROW(format_error("invalid format string")); - ulong_long width = visit(internal::WidthHandler(), width_arg); + ulong_long width = visit(internal::width_handler(), width_arg); if (width > (std::numeric_limits::max)()) FMT_THROW(format_error("number is too big")); spec.width_ = static_cast(width); @@ -3390,7 +3359,7 @@ void do_format_arg(basic_buffer &buffer, basic_arg arg, if (*s++ != '}') FMT_THROW(format_error("invalid format string")); ulong_long precision = - visit(internal::PrecisionHandler(), precision_arg); + visit(internal::precision_handler(), precision_arg); if (precision > (std::numeric_limits::max)()) FMT_THROW(format_error("number is too big")); spec.precision_ = static_cast(precision); @@ -3448,7 +3417,7 @@ namespace fmt { namespace internal { template -struct UdlFormat { +struct udl_format { const Char *str; template @@ -3463,7 +3432,7 @@ struct UdlArg { const Char *str; template - NamedArg> operator=(T &&value) const { + named_arg> operator=(T &&value) const { return {str, std::forward(value)}; } }; @@ -3482,9 +3451,9 @@ inline namespace literals { std::string message = "The answer is {}"_format(42); \endrst */ -inline internal::UdlFormat +inline internal::udl_format operator"" _format(const char *s, std::size_t) { return {s}; } -inline internal::UdlFormat +inline internal::udl_format operator"" _format(const wchar_t *s, std::size_t) { return {s}; } /** diff --git a/fmt/ostream.h b/fmt/ostream.h index 8672ac6c..59ccc83e 100644 --- a/fmt/ostream.h +++ b/fmt/ostream.h @@ -49,21 +49,21 @@ class FormatBuf : public std::basic_streambuf { } }; -Yes &convert(std::ostream &); +yes &convert(std::ostream &); struct DummyStream : std::ostream { DummyStream(); // Suppress a bogus warning in MSVC. // Hide all operator<< overloads from std::ostream. - void operator<<(Null<>); + void operator<<(null<>); }; -No &operator<<(std::ostream &, int); +no &operator<<(std::ostream &, int); template -struct ConvertToIntImpl { +struct convert_to_int_impl { // Convert to int only if T doesn't have an overloaded operator<<. enum { - value = sizeof(convert(get() << get())) == sizeof(No) + value = sizeof(convert(get() << get())) == sizeof(no) }; }; diff --git a/fmt/posix.cc b/fmt/posix.cc index 260f6341..f8ce6b9e 100644 --- a/fmt/posix.cc +++ b/fmt/posix.cc @@ -72,7 +72,7 @@ fmt::BufferedFile::BufferedFile( fmt::CStringRef filename, fmt::CStringRef mode) { FMT_RETRY_VAL(file_, FMT_SYSTEM(fopen(filename.c_str(), mode.c_str())), 0); if (!file_) - throw SystemError(errno, "cannot open file {}", filename); + throw system_error(errno, "cannot open file {}", filename); } void fmt::BufferedFile::close() { @@ -81,7 +81,7 @@ void fmt::BufferedFile::close() { int result = FMT_SYSTEM(fclose(file_)); file_ = 0; if (result != 0) - throw SystemError(errno, "cannot close file"); + throw system_error(errno, "cannot close file"); } // A macro used to prevent expansion of fileno on broken versions of MinGW. @@ -90,7 +90,7 @@ void fmt::BufferedFile::close() { int fmt::BufferedFile::fileno() const { int fd = FMT_POSIX_CALL(fileno FMT_ARGS(file_)); if (fd == -1) - throw SystemError(errno, "cannot get file descriptor"); + throw system_error(errno, "cannot get file descriptor"); return fd; } @@ -103,7 +103,7 @@ fmt::File::File(fmt::CStringRef path, int oflag) { FMT_RETRY(fd_, FMT_POSIX_CALL(open(path.c_str(), oflag, mode))); #endif if (fd_ == -1) - throw SystemError(errno, "cannot open file {}", path); + throw system_error(errno, "cannot open file {}", path); } fmt::File::~File() FMT_NOEXCEPT { @@ -121,7 +121,7 @@ void fmt::File::close() { int result = FMT_POSIX_CALL(close(fd_)); fd_ = -1; if (result != 0) - throw SystemError(errno, "cannot close file"); + throw system_error(errno, "cannot close file"); } fmt::long_long fmt::File::size() const { @@ -135,7 +135,7 @@ fmt::long_long fmt::File::size() const { if (size_lower == INVALID_FILE_SIZE) { DWORD error = GetLastError(); if (error != NO_ERROR) - throw WindowsError(GetLastError(), "cannot get file size"); + throw windows_error(GetLastError(), "cannot get file size"); } fmt::ulong_long long_size = size_upper; return (long_size << sizeof(DWORD) * CHAR_BIT) | size_lower; @@ -143,7 +143,7 @@ fmt::long_long fmt::File::size() const { typedef struct stat Stat; Stat file_stat = Stat(); if (FMT_POSIX_CALL(fstat(fd_, &file_stat)) == -1) - throw SystemError(errno, "cannot get file attributes"); + throw system_error(errno, "cannot get file attributes"); FMT_STATIC_ASSERT(sizeof(fmt::long_long) >= sizeof(file_stat.st_size), "return type of File::size is not large enough"); return file_stat.st_size; @@ -154,7 +154,7 @@ std::size_t fmt::File::read(void *buffer, std::size_t count) { RWResult result = 0; FMT_RETRY(result, FMT_POSIX_CALL(read(fd_, buffer, convert_rwcount(count)))); if (result < 0) - throw SystemError(errno, "cannot read from file"); + throw system_error(errno, "cannot read from file"); return internal::to_unsigned(result); } @@ -162,7 +162,7 @@ std::size_t fmt::File::write(const void *buffer, std::size_t count) { RWResult result = 0; FMT_RETRY(result, FMT_POSIX_CALL(write(fd_, buffer, convert_rwcount(count)))); if (result < 0) - throw SystemError(errno, "cannot write to file"); + throw system_error(errno, "cannot write to file"); return internal::to_unsigned(result); } @@ -171,7 +171,7 @@ fmt::File fmt::File::dup(int fd) { // http://pubs.opengroup.org/onlinepubs/009695399/functions/dup.html int new_fd = FMT_POSIX_CALL(dup(fd)); if (new_fd == -1) - throw SystemError(errno, "cannot duplicate file descriptor {}", fd); + throw system_error(errno, "cannot duplicate file descriptor {}", fd); return File(new_fd); } @@ -179,7 +179,7 @@ void fmt::File::dup2(int fd) { int result = 0; FMT_RETRY(result, FMT_POSIX_CALL(dup2(fd_, fd))); if (result == -1) { - throw SystemError(errno, + throw system_error(errno, "cannot duplicate file descriptor {} to {}", fd_, fd); } } @@ -207,7 +207,7 @@ void fmt::File::pipe(File &read_end, File &write_end) { int result = FMT_POSIX_CALL(pipe(fds)); #endif if (result != 0) - throw SystemError(errno, "cannot create pipe"); + throw system_error(errno, "cannot create pipe"); // The following assignments don't throw because read_fd and write_fd // are closed. read_end = File(fds[0]); @@ -218,7 +218,7 @@ fmt::BufferedFile fmt::File::fdopen(const char *mode) { // Don't retry as fdopen doesn't return EINTR. FILE *f = FMT_POSIX_CALL(fdopen(fd_, mode)); if (!f) - throw SystemError(errno, "cannot associate stream with file descriptor"); + throw system_error(errno, "cannot associate stream with file descriptor"); BufferedFile file(f); fd_ = -1; return file; @@ -232,7 +232,7 @@ long fmt::getpagesize() { #else long size = FMT_POSIX_CALL(sysconf(_SC_PAGESIZE)); if (size < 0) - throw SystemError(errno, "cannot get memory page size"); + throw system_error(errno, "cannot get memory page size"); return size; #endif } diff --git a/fmt/posix.h b/fmt/posix.h index 45cf3c7c..03cbc664 100644 --- a/fmt/posix.h +++ b/fmt/posix.h @@ -178,7 +178,7 @@ public: // A file. Closed file is represented by a File object with descriptor -1. // Methods that are not declared with FMT_NOEXCEPT may throw -// fmt::SystemError in case of failure. Note that some errors such as +// fmt::system_error in case of failure. Note that some errors such as // closing the file multiple times will cause a crash on Windows rather // than an exception. You can get standard behavior by overriding the // invalid parameter handler with _set_invalid_parameter_handler. @@ -341,7 +341,7 @@ class Locale { Locale() : locale_(newlocale(LC_NUMERIC_MASK, "C", NULL)) { if (!locale_) - throw fmt::SystemError(errno, "cannot create locale"); + throw fmt::system_error(errno, "cannot create locale"); } ~Locale() { freelocale(locale_); } diff --git a/fmt/printf.h b/fmt/printf.h index c77100a8..88a5450c 100644 --- a/fmt/printf.h +++ b/fmt/printf.h @@ -210,14 +210,14 @@ class PrintfWidthHandler { \endrst */ template -class printf_arg_formatter : public internal::ArgFormatterBase { +class printf_arg_formatter : public internal::arg_formatter_base { private: void write_null_pointer() { this->spec().type_ = 0; this->write("(nil)"); } - typedef internal::ArgFormatterBase Base; + typedef internal::arg_formatter_base Base; public: typedef typename Base::format_specs format_specs; @@ -230,7 +230,7 @@ class printf_arg_formatter : public internal::ArgFormatterBase { \endrst */ printf_arg_formatter(basic_buffer &buffer, format_specs &spec) - : internal::ArgFormatterBase(buffer, spec) {} + : internal::arg_formatter_base(buffer, spec) {} using Base::operator(); diff --git a/test/format-test.cc b/test/format-test.cc index 14b95361..66397856 100644 --- a/test/format-test.cc +++ b/test/format-test.cc @@ -1314,7 +1314,7 @@ TEST(FormatterTest, FormatExamples) { EXPECT_SYSTEM_ERROR({ FILE *f = safe_fopen(filename, "r"); if (!f) - throw fmt::SystemError(errno, "Cannot open file '{}'", filename); + throw fmt::system_error(errno, "Cannot open file '{}'", filename); fclose(f); }, error_code, "Cannot open file 'nonexistent'"); } @@ -1514,16 +1514,16 @@ TEST(FormatTest, Enum) { EXPECT_EQ("0", fmt::format("{}", A)); } -class MockArgFormatter : public fmt::internal::ArgFormatterBase { +class MockArgFormatter : public fmt::internal::arg_formatter_base { private: MOCK_METHOD1(call, void (int value)); public: - typedef fmt::internal::ArgFormatterBase Base; + typedef fmt::internal::arg_formatter_base Base; MockArgFormatter(fmt::buffer &b, fmt::context &ctx, fmt::format_specs &s) - : fmt::internal::ArgFormatterBase(b, s) { + : fmt::internal::arg_formatter_base(b, s) { EXPECT_CALL(*this, call(42)); } diff --git a/test/gtest-extra-test.cc b/test/gtest-extra-test.cc index 97c4bee1..ac11cf94 100644 --- a/test/gtest-extra-test.cc +++ b/test/gtest-extra-test.cc @@ -78,7 +78,7 @@ void throw_exception() { } void throw_system_error() { - throw fmt::SystemError(EDOM, "test"); + throw fmt::system_error(EDOM, "test"); } // Tests that when EXPECT_THROW_MSG fails, it evaluates its message argument @@ -207,11 +207,11 @@ TEST(ExpectThrowTest, DoesNotGenerateUnreachableCodeWarning) { // EXPECT_SYSTEM_ERROR macro. TEST(ExpectSystemErrorTest, DoesNotGenerateUnreachableCodeWarning) { int n = 0; - EXPECT_SYSTEM_ERROR(throw fmt::SystemError(EDOM, "test"), EDOM, "test"); + EXPECT_SYSTEM_ERROR(throw fmt::system_error(EDOM, "test"), EDOM, "test"); EXPECT_NONFATAL_FAILURE(EXPECT_SYSTEM_ERROR(n++, EDOM, ""), ""); EXPECT_NONFATAL_FAILURE(EXPECT_SYSTEM_ERROR(throw 1, EDOM, ""), ""); EXPECT_NONFATAL_FAILURE(EXPECT_SYSTEM_ERROR( - throw fmt::SystemError(EDOM, "aaa"), EDOM, "bbb"), ""); + throw fmt::system_error(EDOM, "aaa"), EDOM, "bbb"), ""); } TEST(AssertionSyntaxTest, ExceptionAssertionBehavesLikeSingleStatement) { diff --git a/test/gtest-extra.cc b/test/gtest-extra.cc index 34daf4db..307bd84d 100644 --- a/test/gtest-extra.cc +++ b/test/gtest-extra.cc @@ -38,7 +38,7 @@ void OutputRedirect::flush() { int result = 0; FMT_RETRY(result, fflush(file_)); if (result != 0) - throw fmt::SystemError(errno, "cannot flush stream"); + throw fmt::system_error(errno, "cannot flush stream"); } void OutputRedirect::restore() { diff --git a/test/ostream-test.cc b/test/ostream-test.cc index fd40a2a1..a3cc4ddb 100644 --- a/test/ostream-test.cc +++ b/test/ostream-test.cc @@ -53,7 +53,7 @@ std::ostream &operator<<(std::ostream &os, TestEnum) { enum TestEnum2 {A}; TEST(OStreamTest, Enum) { - EXPECT_FALSE(fmt::internal::ConvertToInt::value); + EXPECT_FALSE(fmt::internal::convert_to_int::value); EXPECT_EQ("TestEnum", fmt::format("{}", TestEnum())); EXPECT_EQ("0", fmt::format("{}", A)); } diff --git a/test/posix-mock-test.cc b/test/posix-mock-test.cc index 5a337b6e..69f44567 100644 --- a/test/posix-mock-test.cc +++ b/test/posix-mock-test.cc @@ -415,7 +415,7 @@ TEST(BufferedFileTest, OpenRetry) { #ifndef _WIN32 char c = 0; if (fread(&c, 1, 1, f->get()) < 1) - throw fmt::SystemError(errno, "fread failed"); + throw fmt::system_error(errno, "fread failed"); #endif } diff --git a/test/posix-test.cc b/test/posix-test.cc index c4b6f4dd..a0b2c90d 100644 --- a/test/posix-test.cc +++ b/test/posix-test.cc @@ -173,7 +173,7 @@ TEST(BufferedFileTest, Fileno) { EXPECT_DEATH_IF_SUPPORTED({ try { f.fileno(); - } catch (fmt::SystemError) { + } catch (fmt::system_error) { std::exit(1); } }, ""); diff --git a/test/util-test.cc b/test/util-test.cc index 387203e5..19e960f1 100644 --- a/test/util-test.cc +++ b/test/util-test.cc @@ -652,7 +652,7 @@ TEST(UtilTest, CountDigits) { #ifdef _WIN32 TEST(UtilTest, UTF16ToUTF8) { std::string s = "ёжик"; - fmt::internal::UTF16ToUTF8 u(L"\x0451\x0436\x0438\x043A"); + fmt::internal::utf16_to_utf8 u(L"\x0451\x0436\x0438\x043A"); EXPECT_EQ(s, u.str()); EXPECT_EQ(s.size(), u.size()); } @@ -681,7 +681,7 @@ void check_utf_conversion_error( } TEST(UtilTest, UTF16ToUTF8Error) { - check_utf_conversion_error( + check_utf_conversion_error( "cannot convert string from UTF-16 to UTF-8"); } @@ -693,7 +693,7 @@ TEST(UtilTest, UTF8ToUTF16Error) { } TEST(UtilTest, UTF16ToUTF8Convert) { - fmt::internal::UTF16ToUTF8 u; + fmt::internal::utf16_to_utf8 u; EXPECT_EQ(ERROR_INVALID_PARAMETER, u.convert(fmt::wstring_view(0, 0))); EXPECT_EQ(ERROR_INVALID_PARAMETER, u.convert(fmt::wstring_view(L"foo", INT_MAX + 1u))); @@ -705,10 +705,10 @@ typedef void (*FormatErrorMessage)( template void check_throw_error(int error_code, FormatErrorMessage format) { - fmt::SystemError error(0, ""); + fmt::system_error error(0, ""); try { throw Error(error_code, "test {}", "error"); - } catch (const fmt::SystemError &e) { + } catch (const fmt::system_error &e) { error = e; } fmt::memory_buffer message; @@ -729,10 +729,10 @@ TEST(UtilTest, FormatSystemError) { } TEST(UtilTest, SystemError) { - fmt::SystemError e(EDOM, "test"); + fmt::system_error e(EDOM, "test"); EXPECT_EQ(fmt::format("test: {}", get_system_error(EDOM)), e.what()); EXPECT_EQ(EDOM, e.error_code()); - check_throw_error(EDOM, fmt::format_system_error); + check_throw_error(EDOM, fmt::format_system_error); } TEST(UtilTest, ReportSystemError) { @@ -751,7 +751,7 @@ TEST(UtilTest, FormatWindowsError) { FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 0, ERROR_FILE_EXISTS, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), reinterpret_cast(&message), 0, 0); - fmt::internal::UTF16ToUTF8 utf8_message(message); + fmt::internal::utf16_to_utf8 utf8_message(message); LocalFree(message); fmt::memory_buffer actual_message; fmt::internal::format_windows_error( @@ -778,7 +778,7 @@ TEST(UtilTest, FormatLongWindowsError) { reinterpret_cast(&message), 0, 0) == 0) { return; } - fmt::internal::UTF16ToUTF8 utf8_message(message); + fmt::internal::utf16_to_utf8 utf8_message(message); LocalFree(message); fmt::memory_buffer actual_message; fmt::internal::format_windows_error( @@ -806,15 +806,15 @@ TEST(UtilTest, ReportWindowsError) { enum TestEnum2 {}; TEST(UtilTest, ConvertToInt) { - EXPECT_TRUE(fmt::internal::ConvertToInt::enable_conversion); - EXPECT_FALSE(fmt::internal::ConvertToInt::enable_conversion); - EXPECT_TRUE(fmt::internal::ConvertToInt::value); + EXPECT_TRUE(fmt::internal::convert_to_int::enable_conversion); + EXPECT_FALSE(fmt::internal::convert_to_int::enable_conversion); + EXPECT_TRUE(fmt::internal::convert_to_int::value); } #if FMT_USE_ENUM_BASE enum TestEnum : char {TestValue}; TEST(UtilTest, IsEnumConvertibleToInt) { - EXPECT_TRUE(fmt::internal::ConvertToInt::enable_conversion); + EXPECT_TRUE(fmt::internal::convert_to_int::enable_conversion); } #endif From 572491ad1fe013af6cf241f05e1b0f0413bf4dfe Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Fri, 24 Feb 2017 07:04:44 -0800 Subject: [PATCH 096/340] Document which header defines formatting functions --- doc/api.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/api.rst b/doc/api.rst index 53376188..e43fb1e3 100644 --- a/doc/api.rst +++ b/doc/api.rst @@ -11,8 +11,8 @@ namespace is usually omitted in examples. Format API ========== -The following functions use :ref:`format string syntax ` similar -to the one used by Python's `str.format +The following functions defined in ``fmt/format.h`` use :ref:`format string +syntax ` similar to the one used by Python's `str.format `_ function. They take *format_str* and *args* as arguments. From 3610f34c70f0db4b4fde1362d37e1fb32c5b0f7d Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sat, 4 Mar 2017 07:10:54 -0800 Subject: [PATCH 097/340] Fix windows build --- test/gtest-extra.h | 2 +- test/posix-mock-test.cc | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/test/gtest-extra.h b/test/gtest-extra.h index 0f38dd31..be6708c0 100644 --- a/test/gtest-extra.h +++ b/test/gtest-extra.h @@ -84,7 +84,7 @@ std::string format_system_error(int error_code, fmt::string_view message); #define EXPECT_SYSTEM_ERROR(statement, error_code, message) \ - EXPECT_THROW_MSG(statement, fmt::SystemError, \ + EXPECT_THROW_MSG(statement, fmt::system_error, \ format_system_error(error_code, message)) #if FMT_USE_FILE_DESCRIPTORS diff --git a/test/posix-mock-test.cc b/test/posix-mock-test.cc index 69f44567..f4722b79 100644 --- a/test/posix-mock-test.cc +++ b/test/posix-mock-test.cc @@ -283,7 +283,7 @@ TEST(FileTest, Size) { fmt::internal::format_windows_error( message, ERROR_ACCESS_DENIED, "cannot get file size"); fstat_sim = ERROR; - EXPECT_THROW_MSG(f.size(), fmt::WindowsError, fmt::to_string(message)); + EXPECT_THROW_MSG(f.size(), fmt::windows_error, fmt::to_string(message)); fstat_sim = NONE; #else f.close(); @@ -340,7 +340,7 @@ TEST(FileTest, ConvertReadCount) { ++size; read_count = 1; read_nbyte = 0; - EXPECT_THROW(read_end.read(&c, size), fmt::SystemError); + EXPECT_THROW(read_end.read(&c, size), fmt::system_error); read_count = 0; EXPECT_EQ(UINT_MAX, read_nbyte); } @@ -354,7 +354,7 @@ TEST(FileTest, ConvertWriteCount) { ++size; write_count = 1; write_nbyte = 0; - EXPECT_THROW(write_end.write(&c, size), fmt::SystemError); + EXPECT_THROW(write_end.write(&c, size), fmt::system_error); write_count = 0; EXPECT_EQ(UINT_MAX, write_nbyte); } From 7258d1b8f3a231ef02304892ba9a65c7cb4e9d23 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Wed, 8 Mar 2017 07:34:10 -0800 Subject: [PATCH 098/340] Fix tests --- test/gtest-extra-test.cc | 4 ++-- test/util-test.cc | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/test/gtest-extra-test.cc b/test/gtest-extra-test.cc index ac11cf94..b86a5636 100644 --- a/test/gtest-extra-test.cc +++ b/test/gtest-extra-test.cc @@ -268,10 +268,10 @@ TEST(ExpectTest, EXPECT_SYSTEM_ERROR) { EXPECT_NONFATAL_FAILURE( EXPECT_SYSTEM_ERROR(throw_exception(), EDOM, "test"), "Expected: throw_exception() throws an exception of " - "type fmt::SystemError.\n Actual: it throws a different type."); + "type fmt::system_error.\n Actual: it throws a different type."); EXPECT_NONFATAL_FAILURE( EXPECT_SYSTEM_ERROR(do_nothing(), EDOM, "test"), - "Expected: do_nothing() throws an exception of type fmt::SystemError.\n" + "Expected: do_nothing() throws an exception of type fmt::system_error.\n" " Actual: it throws nothing."); EXPECT_NONFATAL_FAILURE( EXPECT_SYSTEM_ERROR(throw_system_error(), EDOM, "other"), diff --git a/test/util-test.cc b/test/util-test.cc index 19e960f1..e8d8ac80 100644 --- a/test/util-test.cc +++ b/test/util-test.cc @@ -670,10 +670,10 @@ void check_utf_conversion_error( fmt::basic_string_view str = fmt::basic_string_view(0, 0)) { fmt::memory_buffer out; fmt::internal::format_windows_error(out, ERROR_INVALID_PARAMETER, message); - fmt::SystemError error(0, ""); + fmt::system_error error(0, ""); try { (Converter)(str); - } catch (const fmt::SystemError &e) { + } catch (const fmt::system_error &e) { error = e; } EXPECT_EQ(ERROR_INVALID_PARAMETER, error.error_code()); @@ -788,7 +788,7 @@ TEST(UtilTest, FormatLongWindowsError) { } TEST(UtilTest, WindowsError) { - check_throw_error( + check_throw_error( ERROR_FILE_EXISTS, fmt::internal::format_windows_error); } From 7175bd8ae65665acc5b05f3dc7cb44f5b02b2d38 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sat, 25 Feb 2017 06:53:55 -0800 Subject: [PATCH 099/340] Fix error on MinGW --- support/cmake/cxx11.cmake | 9 ++++++++- test/gtest/gtest.h | 6 +++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/support/cmake/cxx11.cmake b/support/cmake/cxx11.cmake index 02795a93..21d12543 100644 --- a/support/cmake/cxx11.cmake +++ b/support/cmake/cxx11.cmake @@ -20,7 +20,14 @@ if (FMT_USE_CPP11) check_cxx_source_compiles(" #include int main() {}" FMT_CPP11_UNISTD_H) - if (FMT_CPP11_CMATH AND FMT_CPP11_UNISTD_H) + # Check if snprintf works with -std=c++11. It may not in MinGW. + check_cxx_source_compiles(" + #include + int main() { + char buffer[10]; + snprintf(buffer, 10, \"foo\"); + }" FMT_CPP11_SNPRINTF) + if (FMT_CPP11_CMATH AND FMT_CPP11_UNISTD_H AND FMT_CPP11_SNPRINTF) set(CPP11_FLAG -std=c++11) else () check_cxx_compiler_flag(-std=gnu++11 HAVE_STD_GNUPP11_FLAG) diff --git a/test/gtest/gtest.h b/test/gtest/gtest.h index 4f3804f7..52d2ed6d 100644 --- a/test/gtest/gtest.h +++ b/test/gtest/gtest.h @@ -2823,7 +2823,11 @@ inline int IsATTY(int /* fd */) { return 0; } inline int IsATTY(int fd) { return _isatty(fd); } # endif // GTEST_OS_WINDOWS_MOBILE inline int StrCaseCmp(const char* s1, const char* s2) { - return _stricmp(s1, s2); +# if _EMULATE_GLIBC + return strcasecmp(s1, s2); +# else + return _stricmp(s1, s2); +# endif } inline char* StrDup(const char* src) { return _strdup(src); } # endif // __BORLANDC__ From 23b8c24da4d68320bdabf6daff6a5affcc62e061 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sat, 11 Mar 2017 07:38:16 -0800 Subject: [PATCH 100/340] Add noexcept --- fmt/format.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/fmt/format.h b/fmt/format.h index b4b41fbd..9d670a6b 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -591,23 +591,23 @@ class basic_buffer { /** \rst - Increases the buffer capacity to hold at least *size* elements updating + Increases the buffer capacity to hold at least *capacity* elements updating ``ptr_`` and ``capacity_``. \endrst */ - virtual void grow(std::size_t size) = 0; + virtual void grow(std::size_t capacity) = 0; public: virtual ~basic_buffer() {} /** Returns the size of this buffer. */ - std::size_t size() const { return size_; } + std::size_t size() const FMT_NOEXCEPT { return size_; } /** Returns the capacity of this buffer. */ - std::size_t capacity() const { return capacity_; } + std::size_t capacity() const FMT_NOEXCEPT { return capacity_; } /** Returns a pointer to the buffer data. */ - const T *data() const { return ptr_; } + const T *data() const FMT_NOEXCEPT { return ptr_; } /** Resizes the buffer. If T is a POD type new elements may not be initialized. From f423e468354b04b84e31cd5ab42436ec2685cdb1 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sat, 11 Mar 2017 07:43:26 -0800 Subject: [PATCH 101/340] Replace clear() with resize(0) and data_ -> store_ --- fmt/format.cc | 2 +- fmt/format.h | 31 +++++++++++++------------------ fmt/string.h | 10 +++++----- test/format-impl-test.cc | 2 +- test/util-test.cc | 6 +++--- 5 files changed, 23 insertions(+), 28 deletions(-) diff --git a/fmt/format.cc b/fmt/format.cc index d1a449d6..2b6afc2f 100644 --- a/fmt/format.cc +++ b/fmt/format.cc @@ -180,7 +180,7 @@ void format_error_code(buffer &out, int error_code, // Report error code making sure that the output fits into // INLINE_BUFFER_SIZE to avoid dynamic memory allocation and potential // bad_alloc. - out.clear(); + out.resize(0); static const char SEP[] = ": "; static const char ERROR_STR[] = "error "; // Subtract 2 to account for terminating null characters in SEP and ERROR_STR. diff --git a/fmt/format.h b/fmt/format.h index 9d670a6b..8ea618c9 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -613,8 +613,7 @@ class basic_buffer { Resizes the buffer. If T is a POD type new elements may not be initialized. */ void resize(std::size_t new_size) { - if (new_size > capacity_) - grow(new_size); + reserve(new_size); size_ = new_size; } @@ -628,11 +627,8 @@ class basic_buffer { grow(capacity); } - void clear() FMT_NOEXCEPT { size_ = 0; } - void push_back(const T &value) { - if (size_ == capacity_) - grow(size_ + 1); + reserve(size_ + 1); ptr_[size_++] = value; } @@ -648,8 +644,7 @@ template template void basic_buffer::append(const U *begin, const U *end) { std::size_t new_size = size_ + internal::to_unsigned(end - begin); - if (new_size > capacity_) - grow(new_size); + reserve(new_size); std::uninitialized_copy(begin, end, internal::make_ptr(ptr_, capacity_) + size_); size_ = new_size; @@ -694,11 +689,11 @@ template > class basic_memory_buffer : private Allocator, public basic_buffer { private: - T data_[SIZE]; + T store_[SIZE]; // Deallocate memory allocated by the buffer. void deallocate() { - if (this->ptr_ != data_) Allocator::deallocate(this->ptr_, this->capacity_); + if (this->ptr_ != store_) Allocator::deallocate(this->ptr_, this->capacity_); } protected: @@ -706,7 +701,7 @@ class basic_memory_buffer : private Allocator, public basic_buffer { public: explicit basic_memory_buffer(const Allocator &alloc = Allocator()) - : Allocator(alloc), basic_buffer(data_, SIZE) {} + : Allocator(alloc), basic_buffer(store_, SIZE) {} ~basic_memory_buffer() { deallocate(); } #if FMT_USE_RVALUE_REFERENCES @@ -717,15 +712,15 @@ class basic_memory_buffer : private Allocator, public basic_buffer { this_alloc = std::move(other_alloc); this->size_ = other.size_; this->capacity_ = other.capacity_; - if (other.ptr_ == other.data_) { - this->ptr_ = data_; - std::uninitialized_copy(other.data_, other.data_ + this->size_, - internal::make_ptr(data_, this->capacity_)); + if (other.ptr_ == other.store_) { + this->ptr_ = store_; + std::uninitialized_copy(other.store_, other.store_ + this->size_, + internal::make_ptr(store_, this->capacity_)); } else { this->ptr_ = other.ptr_; // Set pointer to the inline array so that delete is not called // when deallocating. - other.ptr_ = other.data_; + other.ptr_ = other.store_; } } @@ -773,7 +768,7 @@ void basic_memory_buffer::grow(std::size_t size) { // deallocate may throw (at least in principle), but it doesn't matter since // the buffer already uses the new storage and will deallocate it in case // of exception. - if (old_ptr != data_) + if (old_ptr != store_) Allocator::deallocate(old_ptr, old_capacity); } @@ -2420,7 +2415,7 @@ class basic_writer { write_str(str, format_specs(specs...)); } - void clear() FMT_NOEXCEPT { buffer_.clear(); } + void clear() FMT_NOEXCEPT { buffer_.resize(0); } basic_buffer &buffer() FMT_NOEXCEPT { return buffer_; } }; diff --git a/fmt/string.h b/fmt/string.h index eae6d8ab..c0a62510 100644 --- a/fmt/string.h +++ b/fmt/string.h @@ -45,12 +45,12 @@ namespace fmt { */template class basic_string_buffer : public basic_buffer { private: - std::basic_string data_; + std::basic_string str_; protected: virtual void grow(std::size_t size) { - data_.resize(size); - this->ptr_ = &data_[0]; + str_.resize(size); + this->ptr_ = &str_[0]; this->capacity_ = size; } @@ -61,8 +61,8 @@ class basic_string_buffer : public basic_buffer { \endrst */ void move_to(std::basic_string &str) { - data_.resize(this->size_); - str.swap(data_); + str_.resize(this->size_); + str.swap(str_); this->capacity_ = this->size_ = 0; this->ptr_ = 0; } diff --git a/test/format-impl-test.cc b/test/format-impl-test.cc index f12b6450..fbe6d4f7 100644 --- a/test/format-impl-test.cc +++ b/test/format-impl-test.cc @@ -128,7 +128,7 @@ TEST(FormatTest, FormatErrorCode) { EXPECT_EQ(prefix + sep + msg, to_string(buffer)); std::size_t size = fmt::internal::INLINE_BUFFER_SIZE; EXPECT_EQ(size, buffer.size()); - buffer.clear(); + buffer.resize(0); // Test with a message that doesn't fit into the buffer. prefix += 'x'; fmt::format_error_code(buffer, codes[i], prefix); diff --git a/test/util-test.cc b/test/util-test.cc index e8d8ac80..57a74a42 100644 --- a/test/util-test.cc +++ b/test/util-test.cc @@ -208,7 +208,7 @@ TEST(BufferTest, Resize) { TEST(BufferTest, Clear) { TestBuffer buffer; buffer.resize(20); - buffer.clear(); + buffer.resize(0); EXPECT_EQ(0u, buffer.size()); EXPECT_EQ(20u, buffer.capacity()); } @@ -722,7 +722,7 @@ TEST(UtilTest, FormatSystemError) { fmt::format_system_error(message, EDOM, "test"); EXPECT_EQ(fmt::format("test: {}", get_system_error(EDOM)), to_string(message)); - message.clear(); + message.resize(0); fmt::format_system_error( message, EDOM, fmt::string_view(0, std::numeric_limits::max())); EXPECT_EQ(fmt::format("error {}", EDOM), to_string(message)); @@ -758,7 +758,7 @@ TEST(UtilTest, FormatWindowsError) { actual_message, ERROR_FILE_EXISTS, "test"); EXPECT_EQ(fmt::format("test: {}", utf8_message.str()), fmt::to_string(actual_message)); - actual_message.clear(); + actual_message.resize(0); fmt::internal::format_windows_error( actual_message, ERROR_FILE_EXISTS, fmt::string_view(0, std::numeric_limits::max())); From b4f4b7e21a22d1711708fcc90170c654a9e99565 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sun, 12 Mar 2017 07:30:20 -0700 Subject: [PATCH 102/340] Clean the buffer API (#477) --- fmt/format.h | 79 +++++++++++++++++++++++++------------------- fmt/string.h | 13 ++++---- test/ostream-test.cc | 2 +- test/util-test.cc | 14 ++++---- 4 files changed, 59 insertions(+), 49 deletions(-) diff --git a/fmt/format.h b/fmt/format.h index 8ea618c9..502a6ab8 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -581,18 +581,22 @@ class basic_buffer { private: FMT_DISALLOW_COPY_AND_ASSIGN(basic_buffer); - protected: T *ptr_; std::size_t size_; std::size_t capacity_; - basic_buffer(T *ptr = 0, std::size_t capacity = 0) - : ptr_(ptr), size_(0), capacity_(capacity) {} + protected: + basic_buffer() FMT_NOEXCEPT : ptr_(0), size_(0), capacity_(0) {} + + /** Sets the buffer data and capacity. */ + void set(T* data, std::size_t capacity) FMT_NOEXCEPT { + ptr_ = data; + capacity_ = capacity; + } /** \rst - Increases the buffer capacity to hold at least *capacity* elements updating - ``ptr_`` and ``capacity_``. + Increases the buffer capacity to hold at least *capacity* elements. \endrst */ virtual void grow(std::size_t capacity) = 0; @@ -606,6 +610,9 @@ class basic_buffer { /** Returns the capacity of this buffer. */ std::size_t capacity() const FMT_NOEXCEPT { return capacity_; } + /** Returns a pointer to the buffer data. */ + T *data() FMT_NOEXCEPT { return ptr_; } + /** Returns a pointer to the buffer data. */ const T *data() const FMT_NOEXCEPT { return ptr_; } @@ -693,7 +700,8 @@ class basic_memory_buffer : private Allocator, public basic_buffer { // Deallocate memory allocated by the buffer. void deallocate() { - if (this->ptr_ != store_) Allocator::deallocate(this->ptr_, this->capacity_); + T* data = this->data(); + if (data != store_) Allocator::deallocate(data, this->capacity()); } protected: @@ -701,7 +709,9 @@ class basic_memory_buffer : private Allocator, public basic_buffer { public: explicit basic_memory_buffer(const Allocator &alloc = Allocator()) - : Allocator(alloc), basic_buffer(store_, SIZE) {} + : Allocator(alloc) { + this->set(store_, SIZE); + } ~basic_memory_buffer() { deallocate(); } #if FMT_USE_RVALUE_REFERENCES @@ -710,18 +720,19 @@ class basic_memory_buffer : private Allocator, public basic_buffer { void move(basic_memory_buffer &other) { Allocator &this_alloc = *this, &other_alloc = other; this_alloc = std::move(other_alloc); - this->size_ = other.size_; - this->capacity_ = other.capacity_; - if (other.ptr_ == other.store_) { - this->ptr_ = store_; - std::uninitialized_copy(other.store_, other.store_ + this->size_, - internal::make_ptr(store_, this->capacity_)); + T* data = other.data(); + std::size_t size = other.size(), capacity = other.capacity(); + if (data == other.store_) { + this->set(store_, capacity); + std::uninitialized_copy(other.store_, other.store_ + size, + internal::make_ptr(store_, capacity)); } else { - this->ptr_ = other.ptr_; + this->set(data, capacity); // Set pointer to the inline array so that delete is not called // when deallocating. - other.ptr_ = other.store_; + other.set(other.store_, 0); } + this->resize(size); } public: @@ -754,22 +765,21 @@ class basic_memory_buffer : private Allocator, public basic_buffer { template void basic_memory_buffer::grow(std::size_t size) { - std::size_t new_capacity = this->capacity_ + this->capacity_ / 2; + std::size_t old_capacity = this->capacity(); + std::size_t new_capacity = old_capacity + old_capacity / 2; if (size > new_capacity) new_capacity = size; - T *new_ptr = this->allocate(new_capacity); + T *old_data = this->data(); + T *new_data = this->allocate(new_capacity); // The following code doesn't throw, so the raw pointer above doesn't leak. - std::uninitialized_copy(this->ptr_, this->ptr_ + this->size_, - internal::make_ptr(new_ptr, new_capacity)); - std::size_t old_capacity = this->capacity_; - T *old_ptr = this->ptr_; - this->capacity_ = new_capacity; - this->ptr_ = new_ptr; - // deallocate may throw (at least in principle), but it doesn't matter since - // the buffer already uses the new storage and will deallocate it in case - // of exception. - if (old_ptr != store_) - Allocator::deallocate(old_ptr, old_capacity); + std::uninitialized_copy(old_data, old_data + this->size(), + internal::make_ptr(new_data, new_capacity)); + this->set(new_data, new_capacity); + // deallocate must not throw according to the standard, but even if it does, + // the buffer already uses the new storage and will deallocate it in + // destructor. + if (old_data != store_) + Allocator::deallocate(old_data, old_capacity); } typedef basic_memory_buffer memory_buffer; @@ -793,8 +803,9 @@ class basic_fixed_buffer : public basic_buffer { given size. \endrst */ - basic_fixed_buffer(Char *array, std::size_t size) - : basic_buffer(array, size) {} + basic_fixed_buffer(Char *array, std::size_t size) { + this->set(array, size); + } /** \rst @@ -803,8 +814,9 @@ class basic_fixed_buffer : public basic_buffer { \endrst */ template - explicit basic_fixed_buffer(Char (&array)[SIZE]) - : basic_buffer(array, SIZE) {} + explicit basic_fixed_buffer(Char (&array)[SIZE]) { + this->set(array, SIZE); + } protected: FMT_API void grow(std::size_t size); @@ -2097,8 +2109,7 @@ class basic_context : stored in the object so make sure they have appropriate lifetimes. \endrst */ - basic_context(const Char *format_str, - basic_args args) + basic_context(const Char *format_str, basic_args args) : Base(format_str, args) {} // Parses argument id and returns corresponding argument. diff --git a/fmt/string.h b/fmt/string.h index c0a62510..1f1d8339 100644 --- a/fmt/string.h +++ b/fmt/string.h @@ -48,10 +48,9 @@ class basic_string_buffer : public basic_buffer { std::basic_string str_; protected: - virtual void grow(std::size_t size) { - str_.resize(size); - this->ptr_ = &str_[0]; - this->capacity_ = size; + virtual void grow(std::size_t capacity) { + str_.resize(capacity); + this->set(&str_[0], capacity); } public: @@ -61,10 +60,10 @@ class basic_string_buffer : public basic_buffer { \endrst */ void move_to(std::basic_string &str) { - str_.resize(this->size_); + str_.resize(this->size()); str.swap(str_); - this->capacity_ = this->size_ = 0; - this->ptr_ = 0; + this->resize(0); + this->set(0, 0); } }; diff --git a/test/ostream-test.cc b/test/ostream-test.cc index a3cc4ddb..c0bc4b0d 100644 --- a/test/ostream-test.cc +++ b/test/ostream-test.cc @@ -135,7 +135,7 @@ TEST(OStreamTest, WriteToOStreamMaxSize) { return; struct TestBuffer : fmt::basic_buffer { - explicit TestBuffer(std::size_t size) { size_ = size; } + explicit TestBuffer(std::size_t size) { resize(size); } void grow(std::size_t) {} } buffer(max_size); diff --git a/test/util-test.cc b/test/util-test.cc index 57a74a42..fc805b8f 100644 --- a/test/util-test.cc +++ b/test/util-test.cc @@ -120,21 +120,21 @@ TEST(BufferTest, Nonmoveable) { // A test buffer with a dummy grow method. template struct TestBuffer : basic_buffer { - void grow(std::size_t size) { this->capacity_ = size; } + void grow(std::size_t capacity) { this->set(0, capacity); } }; template struct MockBuffer : basic_buffer { - MOCK_METHOD1(do_grow, void (std::size_t size)); + MOCK_METHOD1(do_grow, void (std::size_t capacity)); - void grow(std::size_t size) { - this->capacity_ = size; - do_grow(size); + void grow(std::size_t capacity) { + this->set(this->data(), capacity); + do_grow(capacity); } MockBuffer() {} - MockBuffer(T *ptr) : basic_buffer(ptr) {} - MockBuffer(T *ptr, std::size_t capacity) : basic_buffer(ptr, capacity) {} + MockBuffer(T *data) { this->set(data, 0); } + MockBuffer(T *data, std::size_t capacity) { this->set(data, capacity); } }; TEST(BufferTest, Ctor) { From 32ec13f1490f14876d52e72b5047eaac2e335008 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sat, 25 Mar 2017 08:20:06 -0700 Subject: [PATCH 103/340] Switch to C++ locale --- fmt/format.h | 36 ++++++++++++++---------------------- test/format-test.cc | 25 ++----------------------- test/util-test.cc | 14 -------------- 3 files changed, 16 insertions(+), 59 deletions(-) diff --git a/fmt/format.h b/fmt/format.h index 502a6ab8..1e96513b 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -30,11 +30,11 @@ #include #include -#include #include #include #include #include +#include #include #include #include @@ -645,6 +645,8 @@ class basic_buffer { T &operator[](std::size_t index) { return ptr_[index]; } const T &operator[](std::size_t index) const { return ptr_[index]; } + + virtual const std::locale* locale() const { return 0; } }; template @@ -962,18 +964,18 @@ struct no_thousands_sep { }; // A functor that adds a thousands separator. +template class add_thousands_sep { private: - fmt::string_view sep_; + fmt::basic_string_view sep_; // Index of a decimal digit with the least significant digit having index 0. unsigned digit_index_; public: - explicit add_thousands_sep(fmt::string_view sep) + explicit add_thousands_sep(fmt::basic_string_view sep) : sep_(sep), digit_index_(0) {} - template void operator()(Char *&buffer) { if (++digit_index_ % 3 != 0) return; @@ -1483,21 +1485,6 @@ basic_arg make_arg(const T &value) { return arg; } -template struct lconv_check { - lconv_check(int) {} -}; - -// Returns the thousands separator for the current locale. -// We check if ``lconv`` contains ``thousands_sep`` because on Android -// ``lconv`` is stubbed as an empty struct. -template -inline string_view thousands_sep( - LConv *lc, lconv_check = 0) { - return lc->thousands_sep; -} - -inline fmt::string_view thousands_sep(...) { return ""; } - #define FMT_CONCAT(a, b) a##b #if FMT_GCC_VERSION >= 407 @@ -2323,7 +2310,7 @@ class basic_writer { /** \rst - Destroys a ``basic_writer`` object. + Destroys the ``basic_writer`` object. \endrst */ virtual ~basic_writer() {} @@ -2629,12 +2616,17 @@ void basic_writer::write_int(T value, Spec spec) { } case 'n': { unsigned num_digits = internal::count_digits(abs_value); - fmt::string_view sep = internal::thousands_sep(std::localeconv()); + const std::locale *loc = buffer_.locale(); + if (!loc) + loc = &std::locale::classic(); + Char thousands_sep = + std::use_facet>(*loc).thousands_sep(); + fmt::basic_string_view sep(&thousands_sep, 1); unsigned size = static_cast( num_digits + sep.size() * ((num_digits - 1) / 3)); CharPtr p = prepare_int_buffer(size, spec, prefix, prefix_size) + 1; internal::format_decimal(get(p), abs_value, 0, - internal::add_thousands_sep(sep)); + internal::add_thousands_sep(sep)); break; } default: diff --git a/test/format-test.cc b/test/format-test.cc index 66397856..b5414d81 100644 --- a/test/format-test.cc +++ b/test/format-test.cc @@ -43,22 +43,6 @@ // Test that the library compiles if None is defined to 0 as done by xlib.h. #define None 0 -struct LocaleMock { - static LocaleMock *instance; - - MOCK_METHOD0(localeconv, lconv *()); -} *LocaleMock::instance; - -namespace fmt { -namespace std { -using namespace ::std; -lconv *localeconv() { - return LocaleMock::instance ? - LocaleMock::instance->localeconv() : ::std::localeconv(); -} -} -} - #include "fmt/format.h" #include "util.h" @@ -1115,14 +1099,9 @@ TEST(FormatterTest, FormatOct) { } TEST(FormatterTest, FormatIntLocale) { - ScopedMock mock; - lconv lc = {}; - char sep[] = "--"; - lc.thousands_sep = sep; - EXPECT_CALL(mock, localeconv()).Times(3).WillRepeatedly(testing::Return(&lc)); EXPECT_EQ("123", format("{:n}", 123)); - EXPECT_EQ("1--234", format("{:n}", 1234)); - EXPECT_EQ("1--234--567", format("{:n}", 1234567)); + EXPECT_EQ("1,234", format("{:n}", 1234)); + EXPECT_EQ("1,234,567", format("{:n}", 1234567)); } TEST(FormatterTest, FormatFloat) { diff --git a/test/util-test.cc b/test/util-test.cc index fc805b8f..1ca29817 100644 --- a/test/util-test.cc +++ b/test/util-test.cc @@ -845,17 +845,3 @@ TEST(UtilTest, Conditional) { fmt::internal::conditional::type *pc = &c; (void)pc; } - -struct TestLConv { - char *thousands_sep; -}; - -struct EmptyLConv {}; - -TEST(UtilTest, ThousandsSep) { - char foo[] = "foo"; - TestLConv lc = {foo}; - EXPECT_EQ("foo", fmt::internal::thousands_sep(&lc).to_string()); - EmptyLConv empty_lc; - EXPECT_EQ("", fmt::internal::thousands_sep(&empty_lc)); -} From 5aa8d6ea217709789d52f7b3a84084fbb0ab7c49 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sat, 25 Mar 2017 08:57:23 -0700 Subject: [PATCH 104/340] Return locale by value --- fmt/format.h | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/fmt/format.h b/fmt/format.h index 1e96513b..13b260ea 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -646,7 +646,7 @@ class basic_buffer { T &operator[](std::size_t index) { return ptr_[index]; } const T &operator[](std::size_t index) const { return ptr_[index]; } - virtual const std::locale* locale() const { return 0; } + virtual std::locale locale() const { return std::locale(); } }; template @@ -2616,11 +2616,9 @@ void basic_writer::write_int(T value, Spec spec) { } case 'n': { unsigned num_digits = internal::count_digits(abs_value); - const std::locale *loc = buffer_.locale(); - if (!loc) - loc = &std::locale::classic(); + std::locale loc = buffer_.locale(); Char thousands_sep = - std::use_facet>(*loc).thousands_sep(); + std::use_facet>(loc).thousands_sep(); fmt::basic_string_view sep(&thousands_sep, 1); unsigned size = static_cast( num_digits + sep.size() * ((num_digits - 1) / 3)); From 12252152acfdd4f35c6c63f414c25815c9d2c1f2 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sun, 26 Mar 2017 15:13:10 -0700 Subject: [PATCH 105/340] CStringRef -> cstring_view --- fmt/format.cc | 15 ++++--- fmt/format.h | 75 ++++++++++++++++++----------------- fmt/ostream.cc | 2 +- fmt/ostream.h | 4 +- fmt/posix.cc | 4 +- fmt/posix.h | 8 ++-- fmt/printf.h | 24 +++++------ test/custom-formatter-test.cc | 2 +- test/format-test.cc | 21 +++++----- test/posix-mock-test.cc | 2 +- 10 files changed, 78 insertions(+), 79 deletions(-) diff --git a/fmt/format.cc b/fmt/format.cc index 2b6afc2f..f8cd4c54 100644 --- a/fmt/format.cc +++ b/fmt/format.cc @@ -214,7 +214,7 @@ void report_error(FormatFunc func, int error_code, } // namespace FMT_FUNC void system_error::init( - int err_code, CStringRef format_str, args args) { + int err_code, cstring_view format_str, args args) { error_code_ = err_code; memory_buffer buffer; format_system_error(buffer, err_code, vformat(format_str, args)); @@ -338,7 +338,7 @@ FMT_FUNC int internal::utf16_to_utf8::convert(wstring_view s) { } FMT_FUNC void windows_error::init( - int err_code, CStringRef format_str, args args) { + int err_code, cstring_view format_str, args args) { error_code_ = err_code; memory_buffer buffer; internal::format_windows_error(buffer, err_code, vformat(format_str, args)); @@ -420,17 +420,17 @@ FMT_FUNC void report_windows_error( } #endif -FMT_FUNC void vprint(std::FILE *f, CStringRef format_str, args args) { +FMT_FUNC void vprint(std::FILE *f, cstring_view format_str, args args) { memory_buffer buffer; vformat_to(buffer, format_str, args); std::fwrite(buffer.data(), 1, buffer.size(), f); } -FMT_FUNC void vprint(CStringRef format_str, args args) { +FMT_FUNC void vprint(cstring_view format_str, args args) { vprint(stdout, format_str, args); } -FMT_FUNC void vprint_colored(Color c, CStringRef format, args args) { +FMT_FUNC void vprint_colored(Color c, cstring_view format, args args) { char escape[] = "\x1b[30m"; escape[3] = static_cast('0' + c); std::fputs(escape, stdout); @@ -439,10 +439,9 @@ FMT_FUNC void vprint_colored(Color c, CStringRef format, args args) { } template -void printf(basic_writer &w, BasicCStringRef format, - args args); +void printf(basic_writer &w, basic_cstring_view format, args args); -FMT_FUNC int vfprintf(std::FILE *f, CStringRef format, printf_args args) { +FMT_FUNC int vfprintf(std::FILE *f, cstring_view format, printf_args args) { memory_buffer buffer; printf(buffer, format, args); std::size_t size = buffer.size(); diff --git a/fmt/format.h b/fmt/format.h index 13b260ea..4ee87c8b 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -476,56 +476,56 @@ typedef basic_string_view wstring_view; /** \rst - A reference to a null terminated string. It can be constructed from a C + A reference to a null-terminated string. It can be constructed from a C string or ``std::string``. You can use one of the following typedefs for common character types: - +-------------+--------------------------+ - | Type | Definition | - +=============+==========================+ - | CStringRef | BasicCStringRef | - +-------------+--------------------------+ - | WCStringRef | BasicCStringRef | - +-------------+--------------------------+ + +---------------+-----------------------------+ + | Type | Definition | + +===============+=============================+ + | cstring_view | basic_cstring_view | + +---------------+-----------------------------+ + | wcstring_view | basic_cstring_view | + +---------------+-----------------------------+ This class is most useful as a parameter type to allow passing different types of strings to a function, for example:: template - std::string format(CStringRef format_str, const Args & ... args); + std::string format(cstring_view format_str, const Args & ... args); format("{}", 42); format(std::string("{}"), 42); \endrst */ template -class BasicCStringRef { +class basic_cstring_view { private: const Char *data_; public: /** Constructs a string reference object from a C string. */ - BasicCStringRef(const Char *s) : data_(s) {} + basic_cstring_view(const Char *s) : data_(s) {} /** \rst Constructs a string reference from an ``std::string`` object. \endrst */ - BasicCStringRef(const std::basic_string &s) : data_(s.c_str()) {} + basic_cstring_view(const std::basic_string &s) : data_(s.c_str()) {} /** Returns the pointer to a C string. */ const Char *c_str() const { return data_; } }; -typedef BasicCStringRef CStringRef; -typedef BasicCStringRef WCStringRef; +typedef basic_cstring_view cstring_view; +typedef basic_cstring_view wcstring_view; /** A formatting error such as invalid format string. */ class format_error : public std::runtime_error { public: - explicit format_error(CStringRef message) + explicit format_error(cstring_view message) : std::runtime_error(message.c_str()) {} ~format_error() throw(); }; @@ -1197,7 +1197,7 @@ template <> constexpr Type gettype() { return CSTRING; } template <> constexpr Type gettype() { return CSTRING; } template <> constexpr Type gettype() { return STRING; } template <> constexpr Type gettype() { return STRING; } -template <> constexpr Type gettype() { return CSTRING; } +template <> constexpr Type gettype() { return CSTRING; } template <> constexpr Type gettype() { return TSTRING; } template <> constexpr Type gettype() { return TSTRING; } template <> constexpr Type gettype() { return TSTRING; } @@ -1335,7 +1335,7 @@ class value { FMT_MAKE_VALUE(const unsigned char *, ustring.value, CSTRING) FMT_MAKE_STR_VALUE(const std::string &, STRING) FMT_MAKE_STR_VALUE(string_view, STRING) - FMT_MAKE_VALUE_(CStringRef, string.value, CSTRING, value.c_str()) + FMT_MAKE_VALUE_(cstring_view, string.value, CSTRING, value.c_str()) #define FMT_MAKE_WSTR_VALUE(Type, TYPE) \ value(typename wchar_helper::supported value) { \ @@ -2111,7 +2111,7 @@ class basic_context : */ class system_error : public std::runtime_error { private: - void init(int err_code, CStringRef format_str, args args); + void init(int err_code, cstring_view format_str, args args); protected: int error_code_; @@ -2138,7 +2138,7 @@ class system_error : public std::runtime_error { \endrst */ template - system_error(int error_code, CStringRef message, const Args & ... args) + system_error(int error_code, cstring_view message, const Args & ... args) : std::runtime_error("") { init(error_code, message, make_args(args...)); } @@ -2799,7 +2799,7 @@ FMT_API void report_system_error(int error_code, /** A Windows error. */ class windows_error : public system_error { private: - FMT_API void init(int error_code, CStringRef format_str, args args); + FMT_API void init(int error_code, cstring_view format_str, args args); public: /** @@ -2831,7 +2831,7 @@ class windows_error : public system_error { \endrst */ template - windows_error(int error_code, CStringRef message, const Args & ... args) { + windows_error(int error_code, cstring_view message, const Args & ... args) { init(error_code, message, make_args(args...)); } }; @@ -2845,7 +2845,7 @@ FMT_API void report_windows_error(int error_code, enum Color { BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE }; -FMT_API void vprint_colored(Color c, CStringRef format, args args); +FMT_API void vprint_colored(Color c, cstring_view format, args args); /** Formats a string and prints it to stdout using ANSI escape sequences @@ -2854,36 +2854,36 @@ FMT_API void vprint_colored(Color c, CStringRef format, args args); print_colored(fmt::RED, "Elapsed time: {0:.2f} seconds", 1.23); */ template -inline void print_colored(Color c, CStringRef format_str, +inline void print_colored(Color c, cstring_view format_str, const Args & ... args) { vprint_colored(c, format_str, make_args(args...)); } template -void vformat_to(basic_buffer &buffer, BasicCStringRef format_str, +void vformat_to(basic_buffer &buffer, basic_cstring_view format_str, basic_args args); -inline void vformat_to(buffer &buf, CStringRef format_str, args args) { +inline void vformat_to(buffer &buf, cstring_view format_str, args args) { vformat_to>(buf, format_str, args); } -inline void vformat_to(wbuffer &buf, WCStringRef format_str, wargs args) { +inline void vformat_to(wbuffer &buf, wcstring_view format_str, wargs args) { vformat_to>(buf, format_str, args); } template -inline void format_to(buffer &buf, CStringRef format_str, +inline void format_to(buffer &buf, cstring_view format_str, const Args & ... args) { vformat_to(buf, format_str, make_args(args...)); } template -inline void format_to(wbuffer &buf, WCStringRef format_str, +inline void format_to(wbuffer &buf, wcstring_view format_str, const Args & ... args) { vformat_to(buf, format_str, make_args(args...)); } -inline std::string vformat(CStringRef format_str, args args) { +inline std::string vformat(cstring_view format_str, args args) { memory_buffer buffer; vformat_to(buffer, format_str, args); return to_string(buffer); @@ -2899,22 +2899,22 @@ inline std::string vformat(CStringRef format_str, args args) { \endrst */ template -inline std::string format(CStringRef format_str, const Args & ... args) { +inline std::string format(cstring_view format_str, const Args & ... args) { return vformat(format_str, make_args(args...)); } -inline std::wstring vformat(WCStringRef format_str, wargs args) { +inline std::wstring vformat(wcstring_view format_str, wargs args) { wmemory_buffer buffer; vformat_to(buffer, format_str, args); return to_string(buffer); } template -inline std::wstring format(WCStringRef format_str, const Args & ... args) { +inline std::wstring format(wcstring_view format_str, const Args & ... args) { return vformat(format_str, make_args(args...)); } -FMT_API void vprint(std::FILE *f, CStringRef format_str, args args); +FMT_API void vprint(std::FILE *f, cstring_view format_str, args args); /** \rst @@ -2926,11 +2926,12 @@ FMT_API void vprint(std::FILE *f, CStringRef format_str, args args); \endrst */ template -inline void print(std::FILE *f, CStringRef format_str, const Args & ... args) { +inline void print(std::FILE *f, cstring_view format_str, + const Args & ... args) { vprint(f, format_str, make_args(args...)); } -FMT_API void vprint(CStringRef format_str, args args); +FMT_API void vprint(cstring_view format_str, args args); /** \rst @@ -2942,7 +2943,7 @@ FMT_API void vprint(CStringRef format_str, args args); \endrst */ template -inline void print(CStringRef format_str, const Args & ... args) { +inline void print(cstring_view format_str, const Args & ... args) { vprint(format_str, make_args(args...)); } @@ -3383,7 +3384,7 @@ void do_format_arg(basic_buffer &buffer, basic_arg arg, /** Formats arguments and writes the output to the buffer. */ template -void vformat_to(basic_buffer &buffer, BasicCStringRef format_str, +void vformat_to(basic_buffer &buffer, basic_cstring_view format_str, basic_args args) { basic_context ctx(format_str.c_str(), args); const Char *&s = ctx.ptr(); diff --git a/fmt/ostream.cc b/fmt/ostream.cc index 34c0bc99..b6696b16 100644 --- a/fmt/ostream.cc +++ b/fmt/ostream.cc @@ -27,7 +27,7 @@ FMT_FUNC void write(std::ostream &os, buffer &buf) { } } -FMT_FUNC void vprint(std::ostream &os, CStringRef format_str, args args) { +FMT_FUNC void vprint(std::ostream &os, cstring_view format_str, args args) { memory_buffer buffer; vformat_to(buffer, format_str, args); internal::write(os, buffer); diff --git a/fmt/ostream.h b/fmt/ostream.h index 59ccc83e..39606c7e 100644 --- a/fmt/ostream.h +++ b/fmt/ostream.h @@ -90,7 +90,7 @@ void format_value(basic_buffer &buf, const T &value, buf, internal::make_arg< basic_context >(str), ctx); } -FMT_API void vprint(std::ostream &os, CStringRef format_str, args args); +FMT_API void vprint(std::ostream &os, cstring_view format_str, args args); /** \rst @@ -102,7 +102,7 @@ FMT_API void vprint(std::ostream &os, CStringRef format_str, args args); \endrst */ template -inline void print(std::ostream &os, CStringRef format_str, +inline void print(std::ostream &os, cstring_view format_str, const Args & ... args) { vprint(os, format_str, make_args(args...)); } diff --git a/fmt/posix.cc b/fmt/posix.cc index f8ce6b9e..1e5aca9d 100644 --- a/fmt/posix.cc +++ b/fmt/posix.cc @@ -69,7 +69,7 @@ fmt::BufferedFile::~BufferedFile() FMT_NOEXCEPT { } fmt::BufferedFile::BufferedFile( - fmt::CStringRef filename, fmt::CStringRef mode) { + fmt::cstring_view filename, fmt::cstring_view mode) { FMT_RETRY_VAL(file_, FMT_SYSTEM(fopen(filename.c_str(), mode.c_str())), 0); if (!file_) throw system_error(errno, "cannot open file {}", filename); @@ -94,7 +94,7 @@ int fmt::BufferedFile::fileno() const { return fd; } -fmt::File::File(fmt::CStringRef path, int oflag) { +fmt::File::File(fmt::cstring_view path, int oflag) { int mode = S_IRUSR | S_IWUSR; #if defined(_WIN32) && !defined(__MINGW32__) fd_ = -1; diff --git a/fmt/posix.h b/fmt/posix.h index 03cbc664..39fa8d26 100644 --- a/fmt/posix.h +++ b/fmt/posix.h @@ -154,7 +154,7 @@ public: #endif // Opens a file. - BufferedFile(CStringRef filename, CStringRef mode); + BufferedFile(cstring_view filename, cstring_view mode); // Closes the file. void close(); @@ -166,12 +166,12 @@ public: // of MinGW that define fileno as a macro. int (fileno)() const; - void vprint(CStringRef format_str, const args &args) { + void vprint(cstring_view format_str, const args &args) { fmt::vprint(file_, format_str, args); } template - inline void print(CStringRef format_str, const Args & ... args) { + inline void print(cstring_view format_str, const Args & ... args) { vprint(format_str, make_args(args...)); } }; @@ -201,7 +201,7 @@ class File { File() FMT_NOEXCEPT : fd_(-1) {} // Opens a file and constructs a File object representing this file. - File(CStringRef path, int oflag); + File(cstring_view path, int oflag); #if !FMT_USE_RVALUE_REFERENCES // Emulate a move constructor and a move assignment operator if rvalue diff --git a/fmt/printf.h b/fmt/printf.h index 88a5450c..0c37ea00 100644 --- a/fmt/printf.h +++ b/fmt/printf.h @@ -327,7 +327,7 @@ class printf_context : appropriate lifetimes. \endrst */ - explicit printf_context(BasicCStringRef format_str, + explicit printf_context(basic_cstring_view format_str, basic_args args) : Base(format_str.c_str(), args) {} @@ -514,14 +514,14 @@ void format_value(basic_buffer &buf, const T &value, } template -void printf(basic_buffer &buf, BasicCStringRef format, +void printf(basic_buffer &buf, basic_cstring_view format, basic_args> args) { printf_context(format, args).format(buf); } typedef basic_args> printf_args; -inline std::string vsprintf(CStringRef format, printf_args args) { +inline std::string vsprintf(cstring_view format, printf_args args) { memory_buffer buffer; printf(buffer, format, args); return to_string(buffer); @@ -537,24 +537,24 @@ inline std::string vsprintf(CStringRef format, printf_args args) { \endrst */ template -inline std::string sprintf(CStringRef format_str, const Args & ... args) { +inline std::string sprintf(cstring_view format_str, const Args & ... args) { return vsprintf(format_str, make_args>(args...)); } inline std::wstring vsprintf( - WCStringRef format, basic_args> args) { + wcstring_view format, basic_args> args) { wmemory_buffer buffer; printf(buffer, format, args); return to_string(buffer); } template -inline std::wstring sprintf(WCStringRef format_str, const Args & ... args) { +inline std::wstring sprintf(wcstring_view format_str, const Args & ... args) { auto vargs = make_args>(args...); return vsprintf(format_str, vargs); } -FMT_API int vfprintf(std::FILE *f, CStringRef format, printf_args args); +FMT_API int vfprintf(std::FILE *f, cstring_view format, printf_args args); /** \rst @@ -566,12 +566,12 @@ FMT_API int vfprintf(std::FILE *f, CStringRef format, printf_args args); \endrst */ template -inline int fprintf(std::FILE *f, CStringRef format_str, const Args & ... args) { +inline int fprintf(std::FILE *f, cstring_view format_str, const Args & ... args) { auto vargs = make_args>(args...); return vfprintf(f, format_str, vargs); } -inline int vprintf(CStringRef format, printf_args args) { +inline int vprintf(cstring_view format, printf_args args) { return vfprintf(stdout, format, args); } @@ -585,11 +585,11 @@ inline int vprintf(CStringRef format, printf_args args) { \endrst */ template -inline int printf(CStringRef format_str, const Args & ... args) { +inline int printf(cstring_view format_str, const Args & ... args) { return vprintf(format_str, make_args>(args...)); } -inline int vfprintf(std::ostream &os, CStringRef format_str, printf_args args) { +inline int vfprintf(std::ostream &os, cstring_view format_str, printf_args args) { memory_buffer buffer; printf(buffer, format_str, args); internal::write(os, buffer); @@ -606,7 +606,7 @@ inline int vfprintf(std::ostream &os, CStringRef format_str, printf_args args) { \endrst */ template -inline int fprintf(std::ostream &os, CStringRef format_str, +inline int fprintf(std::ostream &os, cstring_view format_str, const Args & ... args) { auto vargs = make_args>(args...); return vfprintf(os, format_str, vargs); diff --git a/test/custom-formatter-test.cc b/test/custom-formatter-test.cc index 3e226d71..0e976791 100644 --- a/test/custom-formatter-test.cc +++ b/test/custom-formatter-test.cc @@ -45,7 +45,7 @@ class CustomPrintfArgFormatter : public printf_arg_formatter { } }; -std::string custom_vformat(fmt::CStringRef format_str, fmt::args args) { +std::string custom_vformat(fmt::cstring_view format_str, fmt::args args) { fmt::memory_buffer buffer; // Pass custom argument formatter as a template arg to vwrite. fmt::vformat_to(buffer, format_str, args); diff --git a/test/format-test.cc b/test/format-test.cc index b5414d81..7906d96a 100644 --- a/test/format-test.cc +++ b/test/format-test.cc @@ -28,7 +28,6 @@ #include #include #include -#include #include #include #include @@ -58,7 +57,7 @@ using fmt::basic_writer; using fmt::format; using fmt::format_error; using fmt::string_view; -using fmt::CStringRef; +using fmt::cstring_view; using fmt::memory_buffer; using fmt::wmemory_buffer; using fmt::fill; @@ -146,9 +145,9 @@ TEST(StringViewTest, ConvertToString) { EXPECT_EQ("abc", s); } -TEST(CStringRefTest, Ctor) { - EXPECT_STREQ("abc", CStringRef("abc").c_str()); - EXPECT_STREQ("defg", CStringRef(std::string("defg")).c_str()); +TEST(CStringViewTest, Ctor) { + EXPECT_STREQ("abc", cstring_view("abc").c_str()); + EXPECT_STREQ("defg", cstring_view(std::string("defg")).c_str()); } #if FMT_USE_TYPE_TRAITS @@ -465,7 +464,7 @@ TEST(FormatterTest, ArgErrors) { template struct TestFormat { template - static std::string format(fmt::CStringRef format_str, const Args & ... args) { + static std::string format(fmt::cstring_view format_str, const Args & ... args) { return TestFormat::format(format_str, N - 1, args...); } }; @@ -473,7 +472,7 @@ struct TestFormat { template <> struct TestFormat<0> { template - static std::string format(fmt::CStringRef format_str, const Args & ... args) { + static std::string format(fmt::cstring_view format_str, const Args & ... args) { return fmt::format(format_str, args...); } }; @@ -1230,12 +1229,12 @@ TEST(FormatterTest, FormatString) { EXPECT_EQ("test", format("{0}", std::string("test"))); } -TEST(FormatterTest, FormatStringRef) { +TEST(FormatterTest, FormatStringView) { EXPECT_EQ("test", format("{0}", string_view("test"))); } -TEST(FormatterTest, FormatCStringRef) { - EXPECT_EQ("test", format("{0}", CStringRef("test"))); +TEST(FormatterTest, FormatCStringView) { + EXPECT_EQ("test", format("{0}", cstring_view("test"))); } void format_value(fmt::buffer &buf, const Date &d, fmt::context &) { @@ -1513,7 +1512,7 @@ class MockArgFormatter : public fmt::internal::arg_formatter_base { void operator()(fmt::internal::custom_value) {} }; -void custom_vformat(fmt::CStringRef format_str, fmt::args args) { +void custom_vformat(fmt::cstring_view format_str, fmt::args args) { fmt::memory_buffer buffer; fmt::vformat_to(buffer, format_str, args); } diff --git a/test/posix-mock-test.cc b/test/posix-mock-test.cc index f4722b79..f960b60f 100644 --- a/test/posix-mock-test.cc +++ b/test/posix-mock-test.cc @@ -213,7 +213,7 @@ int (test::fileno)(FILE *stream) { # define EXPECT_EQ_POSIX(expected, actual) #endif -void write_file(fmt::CStringRef filename, fmt::string_view content) { +void write_file(fmt::cstring_view filename, fmt::string_view content) { fmt::BufferedFile f(filename, "w"); f.print("{}", content); } From 586d63636ae57213d6cb2c7cef62eceafba2e623 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Wed, 12 Jul 2017 00:26:54 -0400 Subject: [PATCH 106/340] Implement more efficient handling of large number of format arguments --- fmt/format.h | 37 +++++++++++++++---------------------- 1 file changed, 15 insertions(+), 22 deletions(-) diff --git a/fmt/format.h b/fmt/format.h index 4ee87c8b..d552abfc 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -1534,7 +1534,7 @@ template <> constexpr uint64_t make_type() { return 0; } // Maximum number of arguments with packed types. -enum { MAX_PACKED_ARGS = 16 }; +enum { MAX_PACKED_ARGS = 15 }; template inline typename std::enable_if>::type @@ -1567,7 +1567,9 @@ class arg_store { Array data_; public: - static const uint64_t TYPES = internal::make_type(); + static const uint64_t TYPES = + NUM_ARGS <= internal::MAX_PACKED_ARGS ? + internal::make_type() : -NUM_ARGS; arg_store(const Args &... args) : data_(Array{{internal::make_arg(args)...}}) {} @@ -1619,27 +1621,18 @@ class basic_args { void set_data(const format_arg *args) { args_ = args; } format_arg get(size_type index) const { + int64_t signed_types = static_cast(types_); + if (signed_types < 0) { + uint64_t num_args = -signed_types; + return index < num_args ? args_[index] : format_arg(); + } + if (index > internal::MAX_PACKED_ARGS) + return format_arg(); format_arg arg; - bool use_values = type(internal::MAX_PACKED_ARGS - 1) == internal::NONE; - if (index < internal::MAX_PACKED_ARGS) { - typename internal::Type arg_type = type(index); - internal::value &val = arg.value_; - if (arg_type != internal::NONE) - val = use_values ? values_[index] : args_[index].value_; - arg.type_ = arg_type; - return arg; - } - if (use_values) { - // The index is greater than the number of arguments that can be stored - // in values, so return a "none" argument. - arg.type_ = internal::NONE; - return arg; - } - for (unsigned i = internal::MAX_PACKED_ARGS; i <= index; ++i) { - if (args_[i].type_ == internal::NONE) - return args_[i]; - } - return args_[index]; + arg.type_ = type(index); + internal::value &val = arg.value_; + val = values_[index]; + return arg; } public: From 07123e8ff3aa97a8dc68590f84a219eb876ffb0e Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Wed, 12 Jul 2017 13:13:36 -0400 Subject: [PATCH 107/340] Use Ubuntu Trusty on Travis for a new CMake --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 3264544f..73c08b6e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,5 @@ language: cpp +dist: trusty sudo: required # the doc target uses sudo to install dependencies os: From 4193485b433ac494829609c7dfb63aa83f30b23f Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Wed, 12 Jul 2017 13:15:06 -0400 Subject: [PATCH 108/340] Remove test files --- build/test/test | 1 - build/test/test-file | 1 - 2 files changed, 2 deletions(-) delete mode 100644 build/test/test delete mode 100644 build/test/test-file diff --git a/build/test/test b/build/test/test deleted file mode 100644 index 50a6f636..00000000 --- a/build/test/test +++ /dev/null @@ -1 +0,0 @@ -there must be something here \ No newline at end of file diff --git a/build/test/test-file b/build/test/test-file deleted file mode 100644 index 2810a093..00000000 --- a/build/test/test-file +++ /dev/null @@ -1 +0,0 @@ -Don't panic! \ No newline at end of file From 8f4b918c5bfc539402b774d6e51d5bb0b8874d21 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Wed, 12 Jul 2017 13:24:51 -0400 Subject: [PATCH 109/340] Check argument index --- fmt/format.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/fmt/format.h b/fmt/format.h index d552abfc..b2a8995e 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -1626,10 +1626,12 @@ class basic_args { uint64_t num_args = -signed_types; return index < num_args ? args_[index] : format_arg(); } - if (index > internal::MAX_PACKED_ARGS) - return format_arg(); format_arg arg; + if (index > internal::MAX_PACKED_ARGS) + return arg; arg.type_ = type(index); + if (arg.type_ == internal::NONE) + return arg; internal::value &val = arg.value_; val = values_[index]; return arg; From 9ea183aaba76c739b31ad694e0883b05aafd44b5 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Thu, 13 Jul 2017 18:27:45 -0400 Subject: [PATCH 110/340] Fix MSVC build --- fmt/format.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fmt/format.h b/fmt/format.h index b2a8995e..24dcedf8 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -1569,7 +1569,7 @@ class arg_store { public: static const uint64_t TYPES = NUM_ARGS <= internal::MAX_PACKED_ARGS ? - internal::make_type() : -NUM_ARGS; + internal::make_type() : -static_cast(NUM_ARGS); arg_store(const Args &... args) : data_(Array{{internal::make_arg(args)...}}) {} From 361911dd18663291ad78629bf1f71d25250b1b70 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Thu, 13 Jul 2017 19:06:20 -0400 Subject: [PATCH 111/340] Use preinstalled version of cmake on travis --- .travis.yml | 7 ------- 1 file changed, 7 deletions(-) diff --git a/.travis.yml b/.travis.yml index 73c08b6e..56a704c5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -22,12 +22,5 @@ matrix: - os: osx env: BUILD=Doc -addons: - apt: - sources: - - kubuntu-backports # cmake 2.8.12 - packages: - - cmake - script: - support/travis-build.py From d16582a03873e4825e4f24ea826a36ca06276c8b Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sat, 15 Jul 2017 09:46:18 -0400 Subject: [PATCH 112/340] Move printf-related code to printf.cc --- fmt/CMakeLists.txt | 2 +- fmt/format.cc | 16 ---------------- fmt/printf.cc | 20 ++++++++++++++++++++ test/format-impl-test.cc | 1 + 4 files changed, 22 insertions(+), 17 deletions(-) create mode 100644 fmt/printf.cc diff --git a/fmt/CMakeLists.txt b/fmt/CMakeLists.txt index 5a96c412..c6502a3d 100644 --- a/fmt/CMakeLists.txt +++ b/fmt/CMakeLists.txt @@ -1,6 +1,6 @@ # Define the fmt library, its includes and the needed defines. # format.cc is added to FMT_HEADERS for the header-only configuration. -set(FMT_HEADERS format.h format.cc ostream.h ostream.cc printf.h +set(FMT_HEADERS format.h format.cc ostream.h ostream.cc printf.h printf.cc string.h time.h) if (HAVE_OPEN) set(FMT_HEADERS ${FMT_HEADERS} posix.h) diff --git a/fmt/format.cc b/fmt/format.cc index f8cd4c54..1647664f 100644 --- a/fmt/format.cc +++ b/fmt/format.cc @@ -26,7 +26,6 @@ */ #include "fmt/format.h" -#include "fmt/printf.h" #include @@ -438,17 +437,6 @@ FMT_FUNC void vprint_colored(Color c, cstring_view format, args args) { std::fputs(RESET_COLOR, stdout); } -template -void printf(basic_writer &w, basic_cstring_view format, args args); - -FMT_FUNC int vfprintf(std::FILE *f, cstring_view format, printf_args args) { - memory_buffer buffer; - printf(buffer, format, args); - std::size_t size = buffer.size(); - return std::fwrite( - buffer.data(), 1, size, f) < size ? -1 : static_cast(size); -} - #ifndef FMT_HEADER_ONLY template struct internal::basic_data; @@ -459,8 +447,6 @@ template void basic_fixed_buffer::grow(std::size_t); template void internal::arg_map::init(const args &args); -template void printf_context::format(buffer &); - template int internal::char_traits::format_float( char *buffer, std::size_t size, const char *format, unsigned width, int precision, double value); @@ -477,8 +463,6 @@ template void basic_fixed_buffer::grow(std::size_t); template void internal::arg_map::init(const wargs &args); -template void printf_context::format(wbuffer &); - template int internal::char_traits::format_float( wchar_t *buffer, std::size_t size, const wchar_t *format, unsigned width, int precision, double value); diff --git a/fmt/printf.cc b/fmt/printf.cc new file mode 100644 index 00000000..13e4ed82 --- /dev/null +++ b/fmt/printf.cc @@ -0,0 +1,20 @@ +#include "fmt/printf.h" + +namespace fmt { + +template +void printf(basic_writer &w, basic_cstring_view format, args args); + +FMT_FUNC int vfprintf(std::FILE *f, cstring_view format, printf_args args) { + memory_buffer buffer; + printf(buffer, format, args); + std::size_t size = buffer.size(); + return std::fwrite( + buffer.data(), 1, size, f) < size ? -1 : static_cast(size); +} + +#ifndef FMT_HEADER_ONLY +template void printf_context::format(buffer &); +template void printf_context::format(wbuffer &); +#endif +} diff --git a/test/format-impl-test.cc b/test/format-impl-test.cc index fbe6d4f7..637f6225 100644 --- a/test/format-impl-test.cc +++ b/test/format-impl-test.cc @@ -30,6 +30,7 @@ // Include format.cc instead of format.h to test implementation-specific stuff. #include "fmt/format.cc" +#include "fmt/printf.cc" #include #include From a8d6f309c8d69b499814aa5009d32c59e0ab8d4b Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Mon, 17 Jul 2017 06:26:22 -0700 Subject: [PATCH 113/340] Minor optimizations --- fmt/format.h | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/fmt/format.h b/fmt/format.h index 24dcedf8..71b49e2c 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -2261,7 +2261,7 @@ class basic_writer { // Writes a formatted integer. template - void write_int(T value, Spec spec); + void write_int(T value, const Spec& spec); // Formats a floating-point number (double or long double). template @@ -2537,7 +2537,7 @@ typename basic_writer::CharPtr basic_writer::prepare_int_buffer( template template -void basic_writer::write_int(T value, Spec spec) { +void basic_writer::write_int(T value, const Spec& spec) { unsigned prefix_size = 0; typedef typename internal::int_traits::main_type UnsignedType; UnsignedType abs_value = static_cast(value); @@ -3227,10 +3227,11 @@ inline typename basic_context::format_arg template inline typename basic_context::format_arg basic_context::parse_arg_id() { + format_arg arg; const Char *&s = this->ptr(); if (!internal::is_name_start(*s)) { const char *error = 0; - format_arg arg = *s < '0' || *s > '9' ? + arg = *s < '0' || *s > '9' ? this->next_arg(error) : get_arg(internal::parse_nonnegative_int(s), error); if (error) { @@ -3245,7 +3246,7 @@ inline typename basic_context::format_arg c = *++s; } while (internal::is_name_start(c) || ('0' <= c && c <= '9')); const char *error = 0; - format_arg arg = get_arg(basic_string_view(start, s - start), error); + arg = get_arg(basic_string_view(start, s - start), error); if (error) FMT_THROW(format_error(error)); return arg; @@ -3253,7 +3254,7 @@ inline typename basic_context::format_arg // Formats a single argument. template -void do_format_arg(basic_buffer &buffer, basic_arg arg, +void do_format_arg(basic_buffer &buffer, const basic_arg& arg, Context &ctx) { const Char *&s = ctx.ptr(); basic_format_specs spec; From 2f4f49fd60cc5b04ad56aabc291a13c59e76de0d Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Tue, 18 Jul 2017 19:40:48 -0700 Subject: [PATCH 114/340] Switch from cstring_view to string_view --- fmt/format.cc | 10 +- fmt/format.h | 340 ++++++++++++++++++++-------------- fmt/ostream.cc | 2 +- fmt/ostream.h | 4 +- fmt/posix.cc | 4 +- fmt/posix.h | 52 +++++- fmt/printf.cc | 4 +- fmt/printf.h | 135 +++++++------- fmt/time.h | 16 +- test/custom-formatter-test.cc | 2 +- test/format-test.cc | 20 +- 11 files changed, 344 insertions(+), 245 deletions(-) diff --git a/fmt/format.cc b/fmt/format.cc index 1647664f..339138f8 100644 --- a/fmt/format.cc +++ b/fmt/format.cc @@ -213,7 +213,7 @@ void report_error(FormatFunc func, int error_code, } // namespace FMT_FUNC void system_error::init( - int err_code, cstring_view format_str, args args) { + int err_code, string_view format_str, args args) { error_code_ = err_code; memory_buffer buffer; format_system_error(buffer, err_code, vformat(format_str, args)); @@ -337,7 +337,7 @@ FMT_FUNC int internal::utf16_to_utf8::convert(wstring_view s) { } FMT_FUNC void windows_error::init( - int err_code, cstring_view format_str, args args) { + int err_code, string_view format_str, args args) { error_code_ = err_code; memory_buffer buffer; internal::format_windows_error(buffer, err_code, vformat(format_str, args)); @@ -419,17 +419,17 @@ FMT_FUNC void report_windows_error( } #endif -FMT_FUNC void vprint(std::FILE *f, cstring_view format_str, args args) { +FMT_FUNC void vprint(std::FILE *f, string_view format_str, args args) { memory_buffer buffer; vformat_to(buffer, format_str, args); std::fwrite(buffer.data(), 1, buffer.size(), f); } -FMT_FUNC void vprint(cstring_view format_str, args args) { +FMT_FUNC void vprint(string_view format_str, args args) { vprint(stdout, format_str, args); } -FMT_FUNC void vprint_colored(Color c, cstring_view format, args args) { +FMT_FUNC void vprint_colored(Color c, string_view format, args args) { char escape[] = "\x1b[30m"; escape[3] = static_cast('0' + c); std::fputs(escape, stdout); diff --git a/fmt/format.h b/fmt/format.h index 71b49e2c..9ee8d820 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -474,59 +474,15 @@ class basic_string_view { typedef basic_string_view string_view; typedef basic_string_view wstring_view; -/** - \rst - A reference to a null-terminated string. It can be constructed from a C - string or ``std::string``. - - You can use one of the following typedefs for common character types: - - +---------------+-----------------------------+ - | Type | Definition | - +===============+=============================+ - | cstring_view | basic_cstring_view | - +---------------+-----------------------------+ - | wcstring_view | basic_cstring_view | - +---------------+-----------------------------+ - - This class is most useful as a parameter type to allow passing - different types of strings to a function, for example:: - - template - std::string format(cstring_view format_str, const Args & ... args); - - format("{}", 42); - format(std::string("{}"), 42); - \endrst - */ -template -class basic_cstring_view { - private: - const Char *data_; - - public: - /** Constructs a string reference object from a C string. */ - basic_cstring_view(const Char *s) : data_(s) {} - - /** - \rst - Constructs a string reference from an ``std::string`` object. - \endrst - */ - basic_cstring_view(const std::basic_string &s) : data_(s.c_str()) {} - - /** Returns the pointer to a C string. */ - const Char *c_str() const { return data_; } -}; - -typedef basic_cstring_view cstring_view; -typedef basic_cstring_view wcstring_view; - /** A formatting error such as invalid format string. */ class format_error : public std::runtime_error { public: - explicit format_error(cstring_view message) - : std::runtime_error(message.c_str()) {} + explicit format_error(const char *message) + : std::runtime_error(message) {} + + explicit format_error(const std::string &message) + : std::runtime_error(message) {} + ~format_error() throw(); }; @@ -1197,7 +1153,6 @@ template <> constexpr Type gettype() { return CSTRING; } template <> constexpr Type gettype() { return CSTRING; } template <> constexpr Type gettype() { return STRING; } template <> constexpr Type gettype() { return STRING; } -template <> constexpr Type gettype() { return CSTRING; } template <> constexpr Type gettype() { return TSTRING; } template <> constexpr Type gettype() { return TSTRING; } template <> constexpr Type gettype() { return TSTRING; } @@ -1335,7 +1290,6 @@ class value { FMT_MAKE_VALUE(const unsigned char *, ustring.value, CSTRING) FMT_MAKE_STR_VALUE(const std::string &, STRING) FMT_MAKE_STR_VALUE(string_view, STRING) - FMT_MAKE_VALUE_(cstring_view, string.value, CSTRING, value.c_str()) #define FMT_MAKE_WSTR_VALUE(Type, TYPE) \ value(typename wchar_helper::supported value) { \ @@ -1978,18 +1932,112 @@ class arg_formatter_base { } }; -template -class context_base { +template +class null_terminating_iterator; + +template +const Char *pointer_from(null_terminating_iterator it); + +// An iterator that produces a null terminator on *end. +template +class null_terminating_iterator { + public: + typedef std::ptrdiff_t difference_type; + + null_terminating_iterator() : ptr_(0), end_(0) {} + + null_terminating_iterator(const Char *ptr, const Char *end) + : ptr_(ptr), end_(end) {} + + Char operator*() const { + return ptr_ != end_ ? *ptr_ : 0; + } + + null_terminating_iterator operator++() { + ++ptr_; + return *this; + } + + null_terminating_iterator operator++(int) { + null_terminating_iterator result(*this); + ++ptr_; + return result; + } + + null_terminating_iterator operator--() { + --ptr_; + return *this; + } + + null_terminating_iterator operator+(difference_type n) { + return null_terminating_iterator(ptr_ + n, end_); + } + + null_terminating_iterator operator+=(difference_type n) { + ptr_ += n; + return *this; + } + + difference_type operator-(null_terminating_iterator other) const { + return ptr_ - other.ptr_; + } + + bool operator!=(null_terminating_iterator other) const { + return ptr_ != other.ptr_; + } + + bool operator>=(null_terminating_iterator other) const { + return ptr_ >= other.ptr_; + } + + friend const Char *pointer_from(null_terminating_iterator it); + private: const Char *ptr_; + const Char *end_; +}; + +template < + typename T, + typename Char, + typename std::enable_if< + std::is_same>::value, int>::type = 0> +null_terminating_iterator to_iterator(basic_string_view v) { + const Char *s = v.data(); + return null_terminating_iterator(s, s + v.size()); +} + +template < + typename T, + typename Char, + typename std::enable_if::value, int>::type = 0> +const Char *to_iterator(const basic_string_view v) { + return v.data(); +} + +template +const T *pointer_from(const T *p) { return p; } + +template +const Char *pointer_from(null_terminating_iterator it) { + return it.ptr_; +} + +template +class context_base { + public: + typedef null_terminating_iterator iterator; + + private: + iterator pos_; basic_args args_; int next_arg_index_; protected: typedef basic_arg format_arg; - context_base(const Char *format_str, basic_args args) - : ptr_(format_str), args_(args), next_arg_index_(0) {} + context_base(basic_string_view format_str, basic_args args) + : pos_(to_iterator(format_str)), args_(args), next_arg_index_(0) {} ~context_base() {} basic_args args() const { return args_; } @@ -2027,8 +2075,8 @@ class context_base { } public: - // Returns a pointer to the current position in the format string. - const Char *&ptr() { return ptr_; } + // Returns an iterator to the current position in the format string. + iterator &pos() { return pos_; } }; } // namespace internal @@ -2091,13 +2139,14 @@ class basic_context : stored in the object so make sure they have appropriate lifetimes. \endrst */ - basic_context(const Char *format_str, basic_args args) + basic_context( + basic_string_view format_str, basic_args args) : Base(format_str, args) {} // Parses argument id and returns corresponding argument. format_arg parse_arg_id(); - using Base::ptr; + using Base::pos; }; /** @@ -2106,7 +2155,7 @@ class basic_context : */ class system_error : public std::runtime_error { private: - void init(int err_code, cstring_view format_str, args args); + void init(int err_code, string_view format_str, args args); protected: int error_code_; @@ -2133,7 +2182,7 @@ class system_error : public std::runtime_error { \endrst */ template - system_error(int error_code, cstring_view message, const Args & ... args) + system_error(int error_code, string_view message, const Args & ... args) : std::runtime_error("") { init(error_code, message, make_args(args...)); } @@ -2392,7 +2441,7 @@ class basic_writer { Writes *value* to the buffer. \endrst */ - void write(fmt::basic_string_view value) { + void write(basic_string_view value) { const Char *str = value.data(); buffer_.append(str, str + value.size()); } @@ -2794,7 +2843,7 @@ FMT_API void report_system_error(int error_code, /** A Windows error. */ class windows_error : public system_error { private: - FMT_API void init(int error_code, cstring_view format_str, args args); + FMT_API void init(int error_code, string_view format_str, args args); public: /** @@ -2826,7 +2875,7 @@ class windows_error : public system_error { \endrst */ template - windows_error(int error_code, cstring_view message, const Args & ... args) { + windows_error(int error_code, string_view message, const Args & ... args) { init(error_code, message, make_args(args...)); } }; @@ -2840,7 +2889,7 @@ FMT_API void report_windows_error(int error_code, enum Color { BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE }; -FMT_API void vprint_colored(Color c, cstring_view format, args args); +FMT_API void vprint_colored(Color c, string_view format, args args); /** Formats a string and prints it to stdout using ANSI escape sequences @@ -2849,36 +2898,36 @@ FMT_API void vprint_colored(Color c, cstring_view format, args args); print_colored(fmt::RED, "Elapsed time: {0:.2f} seconds", 1.23); */ template -inline void print_colored(Color c, cstring_view format_str, +inline void print_colored(Color c, string_view format_str, const Args & ... args) { vprint_colored(c, format_str, make_args(args...)); } template -void vformat_to(basic_buffer &buffer, basic_cstring_view format_str, +void vformat_to(basic_buffer &buffer, basic_string_view format_str, basic_args args); -inline void vformat_to(buffer &buf, cstring_view format_str, args args) { +inline void vformat_to(buffer &buf, string_view format_str, args args) { vformat_to>(buf, format_str, args); } -inline void vformat_to(wbuffer &buf, wcstring_view format_str, wargs args) { +inline void vformat_to(wbuffer &buf, wstring_view format_str, wargs args) { vformat_to>(buf, format_str, args); } template -inline void format_to(buffer &buf, cstring_view format_str, +inline void format_to(buffer &buf, string_view format_str, const Args & ... args) { vformat_to(buf, format_str, make_args(args...)); } template -inline void format_to(wbuffer &buf, wcstring_view format_str, +inline void format_to(wbuffer &buf, wstring_view format_str, const Args & ... args) { vformat_to(buf, format_str, make_args(args...)); } -inline std::string vformat(cstring_view format_str, args args) { +inline std::string vformat(string_view format_str, args args) { memory_buffer buffer; vformat_to(buffer, format_str, args); return to_string(buffer); @@ -2894,22 +2943,22 @@ inline std::string vformat(cstring_view format_str, args args) { \endrst */ template -inline std::string format(cstring_view format_str, const Args & ... args) { +inline std::string format(string_view format_str, const Args & ... args) { return vformat(format_str, make_args(args...)); } -inline std::wstring vformat(wcstring_view format_str, wargs args) { +inline std::wstring vformat(wstring_view format_str, wargs args) { wmemory_buffer buffer; vformat_to(buffer, format_str, args); return to_string(buffer); } template -inline std::wstring format(wcstring_view format_str, const Args & ... args) { +inline std::wstring format(wstring_view format_str, const Args & ... args) { return vformat(format_str, make_args(args...)); } -FMT_API void vprint(std::FILE *f, cstring_view format_str, args args); +FMT_API void vprint(std::FILE *f, string_view format_str, args args); /** \rst @@ -2921,12 +2970,12 @@ FMT_API void vprint(std::FILE *f, cstring_view format_str, args args); \endrst */ template -inline void print(std::FILE *f, cstring_view format_str, +inline void print(std::FILE *f, string_view format_str, const Args & ... args) { vprint(f, format_str, make_args(args...)); } -FMT_API void vprint(cstring_view format_str, args args); +FMT_API void vprint(string_view format_str, args args); /** \rst @@ -2938,7 +2987,7 @@ FMT_API void vprint(cstring_view format_str, args args); \endrst */ template -inline void print(cstring_view format_str, const Args & ... args) { +inline void print(string_view format_str, const Args & ... args) { vprint(format_str, make_args(args...)); } @@ -3092,21 +3141,22 @@ inline bool is_name_start(Char c) { return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || '_' == c; } -// Parses an unsigned integer advancing s to the end of the parsed input. -// This function assumes that the first character of s is a digit. -template -unsigned parse_nonnegative_int(const Char *&s) { - assert('0' <= *s && *s <= '9'); +// Parses an unsigned integer advancing it to the end of the parsed input. +// This function assumes that the first character of it is a digit and a +// presence of a non-digit character at the end. +template +unsigned parse_nonnegative_int(Iterator &it) { + assert('0' <= *it && *it <= '9'); unsigned value = 0; do { - unsigned new_value = value * 10 + (*s++ - '0'); + unsigned new_value = value * 10 + (*it++ - '0'); // Check if value wrapped around. if (new_value < value) { value = (std::numeric_limits::max)(); break; } value = new_value; - } while ('0' <= *s && *s <= '9'); + } while ('0' <= *it && *it <= '9'); // Convert to unsigned to prevent a warning. unsigned max_int = (std::numeric_limits::max)(); if (value > max_int) @@ -3138,15 +3188,15 @@ struct is_unsigned { } }; -template -void check_sign(const Char *&s, const basic_arg &arg) { - char sign = static_cast(*s); +template +void check_sign(Iterator &it, const basic_arg &arg) { + char sign = static_cast(*it); require_numeric_argument(arg, sign); if (visit(is_unsigned(), arg)) { FMT_THROW(format_error(fmt::format( "format specifier '{}' requires signed argument", sign))); } - ++s; + ++it; } template @@ -3228,25 +3278,26 @@ template inline typename basic_context::format_arg basic_context::parse_arg_id() { format_arg arg; - const Char *&s = this->ptr(); - if (!internal::is_name_start(*s)) { + auto &it = this->pos(); + if (!internal::is_name_start(*it)) { const char *error = 0; - arg = *s < '0' || *s > '9' ? + arg = *it < '0' || *it > '9' ? this->next_arg(error) : - get_arg(internal::parse_nonnegative_int(s), error); + get_arg(internal::parse_nonnegative_int(it), error); if (error) { FMT_THROW(format_error( - *s != '}' && *s != ':' ? "invalid format string" : error)); + *it != '}' && *it != ':' ? "invalid format string" : error)); } return arg; } - const Char *start = s; + auto start = it; Char c; do { - c = *++s; + c = *++it; } while (internal::is_name_start(c) || ('0' <= c && c <= '9')); const char *error = 0; - arg = get_arg(basic_string_view(start, s - start), error); + arg = get_arg(basic_string_view( + internal::pointer_from(start), it - start), error); if (error) FMT_THROW(format_error(error)); return arg; @@ -3256,15 +3307,15 @@ inline typename basic_context::format_arg template void do_format_arg(basic_buffer &buffer, const basic_arg& arg, Context &ctx) { - const Char *&s = ctx.ptr(); + auto &it = ctx.pos(); basic_format_specs spec; - if (*s == ':') { + if (*it == ':') { if (visit(internal::custom_formatter(buffer, ctx), arg)) return; - ++s; + ++it; // Parse fill and alignment. - if (Char c = *s) { - const Char *p = s + 1; + if (Char c = *it) { + auto p = it + 1; spec.align_ = ALIGN_DEFAULT; do { switch (*p) { @@ -3282,57 +3333,57 @@ void do_format_arg(basic_buffer &buffer, const basic_arg& arg, break; } if (spec.align_ != ALIGN_DEFAULT) { - if (p != s) { + if (p != it) { if (c == '}') break; if (c == '{') FMT_THROW(format_error("invalid fill character '{'")); - s += 2; + it += 2; spec.fill_ = c; - } else ++s; + } else ++it; if (spec.align_ == ALIGN_NUMERIC) internal::require_numeric_argument(arg, '='); break; } - } while (--p >= s); + } while (--p >= it); } // Parse sign. - switch (*s) { + switch (*it) { case '+': - internal::check_sign(s, arg); + internal::check_sign(it, arg); spec.flags_ |= SIGN_FLAG | PLUS_FLAG; break; case '-': - internal::check_sign(s, arg); + internal::check_sign(it, arg); spec.flags_ |= MINUS_FLAG; break; case ' ': - internal::check_sign(s, arg); + internal::check_sign(it, arg); spec.flags_ |= SIGN_FLAG; break; } - if (*s == '#') { + if (*it == '#') { internal::require_numeric_argument(arg, '#'); spec.flags_ |= HASH_FLAG; - ++s; + ++it; } // Parse zero flag. - if (*s == '0') { + if (*it == '0') { internal::require_numeric_argument(arg, '0'); spec.align_ = ALIGN_NUMERIC; spec.fill_ = '0'; - ++s; + ++it; } // Parse width. - if ('0' <= *s && *s <= '9') { - spec.width_ = internal::parse_nonnegative_int(s); - } else if (*s == '{') { - ++s; + if ('0' <= *it && *it <= '9') { + spec.width_ = internal::parse_nonnegative_int(it); + } else if (*it == '{') { + ++it; auto width_arg = ctx.parse_arg_id(); - if (*s++ != '}') + if (*it++ != '}') FMT_THROW(format_error("invalid format string")); ulong_long width = visit(internal::width_handler(), width_arg); if (width > (std::numeric_limits::max)()) @@ -3341,15 +3392,15 @@ void do_format_arg(basic_buffer &buffer, const basic_arg& arg, } // Parse precision. - if (*s == '.') { - ++s; + if (*it == '.') { + ++it; spec.precision_ = 0; - if ('0' <= *s && *s <= '9') { - spec.precision_ = internal::parse_nonnegative_int(s); - } else if (*s == '{') { - ++s; + if ('0' <= *it && *it <= '9') { + spec.precision_ = internal::parse_nonnegative_int(it); + } else if (*it == '{') { + ++it; auto precision_arg = ctx.parse_arg_id(); - if (*s++ != '}') + if (*it++ != '}') FMT_THROW(format_error("invalid format string")); ulong_long precision = visit(internal::precision_handler(), precision_arg); @@ -3367,11 +3418,11 @@ void do_format_arg(basic_buffer &buffer, const basic_arg& arg, } // Parse type. - if (*s != '}' && *s) - spec.type_ = static_cast(*s++); + if (*it != '}' && *it) + spec.type_ = static_cast(*it++); } - if (*s != '}') + if (*it != '}') FMT_THROW(format_error("missing '}' in format string")); // Format argument. @@ -3380,28 +3431,29 @@ void do_format_arg(basic_buffer &buffer, const basic_arg& arg, /** Formats arguments and writes the output to the buffer. */ template -void vformat_to(basic_buffer &buffer, basic_cstring_view format_str, +void vformat_to(basic_buffer &buffer, basic_string_view format_str, basic_args args) { - basic_context ctx(format_str.c_str(), args); - const Char *&s = ctx.ptr(); - const Char *start = s; - while (*s) { - Char c = *s++; + basic_context ctx(format_str, args); + auto &it = ctx.pos(); + auto start = it; + using internal::pointer_from; + while (*it) { + Char c = *it++; if (c != '{' && c != '}') continue; - if (*s == c) { - buffer.append(start, s); - start = ++s; + if (*it == c) { + buffer.append(pointer_from(start), pointer_from(it)); + start = ++it; continue; } if (c == '}') FMT_THROW(format_error("unmatched '}' in format string")); - buffer.append(start, s - 1); + buffer.append(pointer_from(start), pointer_from(it) - 1); do_format_arg(buffer, ctx.parse_arg_id(), ctx); - if (*s != '}') + if (*it != '}') FMT_THROW(format_error(fmt::format("unknown format specifier"))); - start = ++s; + start = ++it; } - buffer.append(start, s); + buffer.append(pointer_from(start), pointer_from(it)); } } // namespace fmt diff --git a/fmt/ostream.cc b/fmt/ostream.cc index b6696b16..8fb717bd 100644 --- a/fmt/ostream.cc +++ b/fmt/ostream.cc @@ -27,7 +27,7 @@ FMT_FUNC void write(std::ostream &os, buffer &buf) { } } -FMT_FUNC void vprint(std::ostream &os, cstring_view format_str, args args) { +FMT_FUNC void vprint(std::ostream &os, string_view format_str, args args) { memory_buffer buffer; vformat_to(buffer, format_str, args); internal::write(os, buffer); diff --git a/fmt/ostream.h b/fmt/ostream.h index 39606c7e..5a011f5a 100644 --- a/fmt/ostream.h +++ b/fmt/ostream.h @@ -90,7 +90,7 @@ void format_value(basic_buffer &buf, const T &value, buf, internal::make_arg< basic_context >(str), ctx); } -FMT_API void vprint(std::ostream &os, cstring_view format_str, args args); +FMT_API void vprint(std::ostream &os, string_view format_str, args args); /** \rst @@ -102,7 +102,7 @@ FMT_API void vprint(std::ostream &os, cstring_view format_str, args args); \endrst */ template -inline void print(std::ostream &os, cstring_view format_str, +inline void print(std::ostream &os, string_view format_str, const Args & ... args) { vprint(os, format_str, make_args(args...)); } diff --git a/fmt/posix.cc b/fmt/posix.cc index 1e5aca9d..5c37de6a 100644 --- a/fmt/posix.cc +++ b/fmt/posix.cc @@ -72,7 +72,7 @@ fmt::BufferedFile::BufferedFile( fmt::cstring_view filename, fmt::cstring_view mode) { FMT_RETRY_VAL(file_, FMT_SYSTEM(fopen(filename.c_str(), mode.c_str())), 0); if (!file_) - throw system_error(errno, "cannot open file {}", filename); + throw system_error(errno, "cannot open file {}", filename.c_str()); } void fmt::BufferedFile::close() { @@ -103,7 +103,7 @@ fmt::File::File(fmt::cstring_view path, int oflag) { FMT_RETRY(fd_, FMT_POSIX_CALL(open(path.c_str(), oflag, mode))); #endif if (fd_ == -1) - throw system_error(errno, "cannot open file {}", path); + throw system_error(errno, "cannot open file {}", path.c_str()); } fmt::File::~File() FMT_NOEXCEPT { diff --git a/fmt/posix.h b/fmt/posix.h index 39fa8d26..c0cb2b62 100644 --- a/fmt/posix.h +++ b/fmt/posix.h @@ -66,6 +66,54 @@ namespace fmt { +/** + \rst + A reference to a null-terminated string. It can be constructed from a C + string or ``std::string``. + + You can use one of the following typedefs for common character types: + + +---------------+-----------------------------+ + | Type | Definition | + +===============+=============================+ + | cstring_view | basic_cstring_view | + +---------------+-----------------------------+ + | wcstring_view | basic_cstring_view | + +---------------+-----------------------------+ + + This class is most useful as a parameter type to allow passing + different types of strings to a function, for example:: + + template + std::string format(cstring_view format_str, const Args & ... args); + + format("{}", 42); + format(std::string("{}"), 42); + \endrst + */ +template +class basic_cstring_view { + private: + const Char *data_; + + public: + /** Constructs a string reference object from a C string. */ + basic_cstring_view(const Char *s) : data_(s) {} + + /** + \rst + Constructs a string reference from an ``std::string`` object. + \endrst + */ + basic_cstring_view(const std::basic_string &s) : data_(s.c_str()) {} + + /** Returns the pointer to a C string. */ + const Char *c_str() const { return data_; } +}; + +typedef basic_cstring_view cstring_view; +typedef basic_cstring_view wcstring_view; + // An error code. class ErrorCode { private: @@ -166,12 +214,12 @@ public: // of MinGW that define fileno as a macro. int (fileno)() const; - void vprint(cstring_view format_str, const args &args) { + void vprint(string_view format_str, const args &args) { fmt::vprint(file_, format_str, args); } template - inline void print(cstring_view format_str, const Args & ... args) { + inline void print(string_view format_str, const Args & ... args) { vprint(format_str, make_args(args...)); } }; diff --git a/fmt/printf.cc b/fmt/printf.cc index 13e4ed82..53d4c0b9 100644 --- a/fmt/printf.cc +++ b/fmt/printf.cc @@ -3,9 +3,9 @@ namespace fmt { template -void printf(basic_writer &w, basic_cstring_view format, args args); +void printf(basic_writer &w, basic_string_view format, args args); -FMT_FUNC int vfprintf(std::FILE *f, cstring_view format, printf_args args) { +FMT_FUNC int vfprintf(std::FILE *f, string_view format, printf_args args) { memory_buffer buffer; printf(buffer, format, args); std::size_t size = buffer.size(); diff --git a/fmt/printf.h b/fmt/printf.h index 0c37ea00..7bb27a89 100644 --- a/fmt/printf.h +++ b/fmt/printf.h @@ -307,17 +307,18 @@ class printf_context : typedef internal::context_base Base; typedef typename Base::format_arg format_arg; typedef basic_format_specs format_specs; + typedef typename Base::iterator iterator; - void parse_flags(format_specs &spec, const Char *&s); + void parse_flags(format_specs &spec, iterator &it); // Returns the argument with specified index or, if arg_index is equal // to the maximum unsigned value, the next argument. format_arg get_arg( - const Char *s, + iterator it, unsigned arg_index = (std::numeric_limits::max)()); // Parses argument index, flags and width and returns the argument index. - unsigned parse_header(const Char *&s, format_specs &spec); + unsigned parse_header(iterator &it, format_specs &spec); public: /** @@ -327,18 +328,18 @@ class printf_context : appropriate lifetimes. \endrst */ - explicit printf_context(basic_cstring_view format_str, + explicit printf_context(basic_string_view format_str, basic_args args) - : Base(format_str.c_str(), args) {} + : Base(format_str, args) {} /** Formats stored arguments and writes the output to the buffer. */ FMT_API void format(basic_buffer &buffer); }; template -void printf_context::parse_flags(format_specs &spec, const Char *&s) { +void printf_context::parse_flags(format_specs &spec, iterator &it) { for (;;) { - switch (*s++) { + switch (*it++) { case '-': spec.align_ = ALIGN_LEFT; break; @@ -355,7 +356,7 @@ void printf_context::parse_flags(format_specs &spec, const Char *&s) { spec.flags_ |= HASH_FLAG; break; default: - --s; + --it; return; } } @@ -363,27 +364,27 @@ void printf_context::parse_flags(format_specs &spec, const Char *&s) { template typename printf_context::format_arg printf_context::get_arg( - const Char *s, unsigned arg_index) { - (void)s; + iterator it, unsigned arg_index) { + (void)it; const char *error = 0; format_arg arg = arg_index == std::numeric_limits::max() ? this->next_arg(error) : Base::get_arg(arg_index - 1, error); if (error) - FMT_THROW(format_error(!*s ? "invalid format string" : error)); + FMT_THROW(format_error(!*it ? "invalid format string" : error)); return arg; } template unsigned printf_context::parse_header( - const Char *&s, format_specs &spec) { + iterator &it, format_specs &spec) { unsigned arg_index = std::numeric_limits::max(); - Char c = *s; + Char c = *it; if (c >= '0' && c <= '9') { // Parse an argument index (if followed by '$') or a width possibly // preceded with '0' flag(s). - unsigned value = internal::parse_nonnegative_int(s); - if (*s == '$') { // value is an argument index - ++s; + unsigned value = internal::parse_nonnegative_int(it); + if (*it == '$') { // value is an argument index + ++it; arg_index = value; } else { if (c == '0') @@ -396,49 +397,51 @@ unsigned printf_context::parse_header( } } } - parse_flags(spec, s); + parse_flags(spec, it); // Parse width. - if (*s >= '0' && *s <= '9') { - spec.width_ = internal::parse_nonnegative_int(s); - } else if (*s == '*') { - ++s; - spec.width_ = visit(internal::PrintfWidthHandler(spec), get_arg(s)); + if (*it >= '0' && *it <= '9') { + spec.width_ = internal::parse_nonnegative_int(it); + } else if (*it == '*') { + ++it; + spec.width_ = visit(internal::PrintfWidthHandler(spec), get_arg(it)); } return arg_index; } template void printf_context::format(basic_buffer &buffer) { - const Char *start = this->ptr(); - const Char *s = start; - while (*s) { - Char c = *s++; + auto start = this->pos(); + auto it = start; + using internal::pointer_from; + while (*it) { + Char c = *it++; if (c != '%') continue; - if (*s == c) { - buffer.append(start, s); - start = ++s; + if (*it == c) { + buffer.append(pointer_from(start), pointer_from(it)); + start = ++it; continue; } - buffer.append(start, s - 1); + buffer.append(pointer_from(start), pointer_from(it) - 1); format_specs spec; spec.align_ = ALIGN_RIGHT; // Parse argument index, flags and width. - unsigned arg_index = parse_header(s, spec); + unsigned arg_index = parse_header(it, spec); // Parse precision. - if (*s == '.') { - ++s; - if ('0' <= *s && *s <= '9') { - spec.precision_ = static_cast(internal::parse_nonnegative_int(s)); - } else if (*s == '*') { - ++s; - spec.precision_ = visit(internal::PrintfPrecisionHandler(), get_arg(s)); + if (*it == '.') { + ++it; + if ('0' <= *it && *it <= '9') { + spec.precision_ = static_cast(internal::parse_nonnegative_int(it)); + } else if (*it == '*') { + ++it; + spec.precision_ = + visit(internal::PrintfPrecisionHandler(), get_arg(it)); } } - format_arg arg = get_arg(s, arg_index); + format_arg arg = get_arg(it, arg_index); if (spec.flag(HASH_FLAG) && visit(internal::IsZeroInt(), arg)) spec.flags_ &= ~internal::to_unsigned(HASH_FLAG); if (spec.fill_ == '0') { @@ -450,41 +453,41 @@ void printf_context::format(basic_buffer &buffer) { // Parse length and convert the argument to the required type. using internal::convert_arg; - switch (*s++) { + switch (*it++) { case 'h': - if (*s == 'h') - convert_arg(arg, *++s); + if (*it == 'h') + convert_arg(arg, *++it); else - convert_arg(arg, *s); + convert_arg(arg, *it); break; case 'l': - if (*s == 'l') - convert_arg(arg, *++s); + if (*it == 'l') + convert_arg(arg, *++it); else - convert_arg(arg, *s); + convert_arg(arg, *it); break; case 'j': - convert_arg(arg, *s); + convert_arg(arg, *it); break; case 'z': - convert_arg(arg, *s); + convert_arg(arg, *it); break; case 't': - convert_arg(arg, *s); + convert_arg(arg, *it); break; case 'L': // printf produces garbage when 'L' is omitted for long double, no // need to do the same. break; default: - --s; - convert_arg(arg, *s); + --it; + convert_arg(arg, *it); } // Parse type. - if (!*s) + if (!*it) FMT_THROW(format_error("invalid format string")); - spec.type_ = static_cast(*s++); + spec.type_ = static_cast(*it++); if (arg.is_integral()) { // Normalize type. switch (spec.type_) { @@ -498,12 +501,12 @@ void printf_context::format(basic_buffer &buffer) { } } - start = s; + start = it; // Format argument. visit(AF(buffer, spec), arg); } - buffer.append(start, s); + buffer.append(pointer_from(start), pointer_from(it)); } // Formats a value. @@ -514,14 +517,14 @@ void format_value(basic_buffer &buf, const T &value, } template -void printf(basic_buffer &buf, basic_cstring_view format, +void printf(basic_buffer &buf, basic_string_view format, basic_args> args) { printf_context(format, args).format(buf); } typedef basic_args> printf_args; -inline std::string vsprintf(cstring_view format, printf_args args) { +inline std::string vsprintf(string_view format, printf_args args) { memory_buffer buffer; printf(buffer, format, args); return to_string(buffer); @@ -537,24 +540,24 @@ inline std::string vsprintf(cstring_view format, printf_args args) { \endrst */ template -inline std::string sprintf(cstring_view format_str, const Args & ... args) { +inline std::string sprintf(string_view format_str, const Args & ... args) { return vsprintf(format_str, make_args>(args...)); } inline std::wstring vsprintf( - wcstring_view format, basic_args> args) { + wstring_view format, basic_args> args) { wmemory_buffer buffer; printf(buffer, format, args); return to_string(buffer); } template -inline std::wstring sprintf(wcstring_view format_str, const Args & ... args) { +inline std::wstring sprintf(wstring_view format_str, const Args & ... args) { auto vargs = make_args>(args...); return vsprintf(format_str, vargs); } -FMT_API int vfprintf(std::FILE *f, cstring_view format, printf_args args); +FMT_API int vfprintf(std::FILE *f, string_view format, printf_args args); /** \rst @@ -566,12 +569,12 @@ FMT_API int vfprintf(std::FILE *f, cstring_view format, printf_args args); \endrst */ template -inline int fprintf(std::FILE *f, cstring_view format_str, const Args & ... args) { +inline int fprintf(std::FILE *f, string_view format_str, const Args & ... args) { auto vargs = make_args>(args...); return vfprintf(f, format_str, vargs); } -inline int vprintf(cstring_view format, printf_args args) { +inline int vprintf(string_view format, printf_args args) { return vfprintf(stdout, format, args); } @@ -585,11 +588,11 @@ inline int vprintf(cstring_view format, printf_args args) { \endrst */ template -inline int printf(cstring_view format_str, const Args & ... args) { +inline int printf(string_view format_str, const Args & ... args) { return vprintf(format_str, make_args>(args...)); } -inline int vfprintf(std::ostream &os, cstring_view format_str, printf_args args) { +inline int vfprintf(std::ostream &os, string_view format_str, printf_args args) { memory_buffer buffer; printf(buffer, format_str, args); internal::write(os, buffer); @@ -606,7 +609,7 @@ inline int vfprintf(std::ostream &os, cstring_view format_str, printf_args args) \endrst */ template -inline int fprintf(std::ostream &os, cstring_view format_str, +inline int fprintf(std::ostream &os, string_view format_str, const Args & ... args) { auto vargs = make_args>(args...); return vfprintf(os, format_str, vargs); diff --git a/fmt/time.h b/fmt/time.h index c4700fbc..02d84c8d 100644 --- a/fmt/time.h +++ b/fmt/time.h @@ -16,17 +16,19 @@ namespace fmt { void format_value(buffer &buf, const std::tm &tm, context &ctx) { - const char *&s = ctx.ptr(); - if (*s == ':') - ++s; - const char *end = s; + auto &it = ctx.pos(); + if (*it == ':') + ++it; + auto end = it; while (*end && *end != '}') ++end; if (*end != '}') FMT_THROW(format_error("missing '}' in format string")); memory_buffer format; - format.append(s, end + 1); - format[format.size() - 1] = '\0'; + format.reserve(end - it + 1); + using internal::pointer_from; + format.append(pointer_from(it), pointer_from(end)); + format.push_back('\0'); std::size_t start = buf.size(); for (;;) { std::size_t size = buf.capacity() - start; @@ -45,7 +47,7 @@ void format_value(buffer &buf, const std::tm &tm, context &ctx) { const std::size_t MIN_GROWTH = 10; buf.reserve(buf.capacity() + (size > MIN_GROWTH ? size : MIN_GROWTH)); } - s = end; + it = end; } } diff --git a/test/custom-formatter-test.cc b/test/custom-formatter-test.cc index 0e976791..e189fa4d 100644 --- a/test/custom-formatter-test.cc +++ b/test/custom-formatter-test.cc @@ -45,7 +45,7 @@ class CustomPrintfArgFormatter : public printf_arg_formatter { } }; -std::string custom_vformat(fmt::cstring_view format_str, fmt::args args) { +std::string custom_vformat(fmt::string_view format_str, fmt::args args) { fmt::memory_buffer buffer; // Pass custom argument formatter as a template arg to vwrite. fmt::vformat_to(buffer, format_str, args); diff --git a/test/format-test.cc b/test/format-test.cc index 7906d96a..49611eb8 100644 --- a/test/format-test.cc +++ b/test/format-test.cc @@ -57,7 +57,6 @@ using fmt::basic_writer; using fmt::format; using fmt::format_error; using fmt::string_view; -using fmt::cstring_view; using fmt::memory_buffer; using fmt::wmemory_buffer; using fmt::fill; @@ -145,11 +144,6 @@ TEST(StringViewTest, ConvertToString) { EXPECT_EQ("abc", s); } -TEST(CStringViewTest, Ctor) { - EXPECT_STREQ("abc", cstring_view("abc").c_str()); - EXPECT_STREQ("defg", cstring_view(std::string("defg")).c_str()); -} - #if FMT_USE_TYPE_TRAITS TEST(WriterTest, NotCopyConstructible) { EXPECT_FALSE(std::is_copy_constructible >::value); @@ -464,7 +458,7 @@ TEST(FormatterTest, ArgErrors) { template struct TestFormat { template - static std::string format(fmt::cstring_view format_str, const Args & ... args) { + static std::string format(fmt::string_view format_str, const Args & ... args) { return TestFormat::format(format_str, N - 1, args...); } }; @@ -472,7 +466,7 @@ struct TestFormat { template <> struct TestFormat<0> { template - static std::string format(fmt::cstring_view format_str, const Args & ... args) { + static std::string format(fmt::string_view format_str, const Args & ... args) { return fmt::format(format_str, args...); } }; @@ -1233,10 +1227,6 @@ TEST(FormatterTest, FormatStringView) { EXPECT_EQ("test", format("{0}", string_view("test"))); } -TEST(FormatterTest, FormatCStringView) { - EXPECT_EQ("test", format("{0}", cstring_view("test"))); -} - void format_value(fmt::buffer &buf, const Date &d, fmt::context &) { fmt::format_to(buf, "{}-{}-{}", d.year(), d.month(), d.day()); } @@ -1512,7 +1502,7 @@ class MockArgFormatter : public fmt::internal::arg_formatter_base { void operator()(fmt::internal::custom_value) {} }; -void custom_vformat(fmt::cstring_view format_str, fmt::args args) { +void custom_vformat(fmt::string_view format_str, fmt::args args) { fmt::memory_buffer buffer; fmt::vformat_to(buffer, format_str, args); } @@ -1526,3 +1516,7 @@ void custom_format(const char *format_str, const Args & ... args) { TEST(FormatTest, CustomArgFormatter) { custom_format("{}", 42); } + +TEST(FormatTest, NonNullTerminatedFormatString) { + EXPECT_EQ("42", format(string_view("{}foo", 2), 42)); +} From eefdb379f9bc441a08109d12d3f812e51ba7ceeb Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sun, 23 Jul 2017 20:15:52 -0700 Subject: [PATCH 115/340] Fix an unused argument warning --- fmt/format.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fmt/format.h b/fmt/format.h index 9ee8d820..96f9d3c7 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -1840,7 +1840,7 @@ class arg_formatter_base { typename enable_if< !std::is_same::value || !std::is_same::value>::type - write_str(basic_string_view value) { + write_str(basic_string_view ) { // Do nothing. } From da439f28388971fc77da435a9a3cd761a94fee23 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sun, 23 Jul 2017 20:21:11 -0700 Subject: [PATCH 116/340] Suppress warning about missing noreturn attribute (#549) Suppress warning about missing noreturn attribute Adding `[[noreturn]]` to `report_unknown_type` suppresses the Clang/GCC `-Wmissing-noreturn` warning: Clang outputs: .../fmt/fmt/format.cc:294:74: warning: function 'report_unknown_type' could be declared with attribute 'noreturn' [-Wmissing-noreturn] ...code, const char *type) { ^ GCC outputs: .../fmt/fmt/format.cc:294:74: warning: function might be candidate for attribute 'noreturn' [-Wsuggest-attribute=noreturn] ...code, const char *type) { ^ Cherry-picked d16c4d. --- fmt/format.h | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/fmt/format.h b/fmt/format.h index 96f9d3c7..85f396b9 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -137,6 +137,15 @@ typedef __int64 intmax_t; # define FMT_HAS_CPP_ATTRIBUTE(x) 0 #endif +// Use the compiler's attribute noreturn. +#if defined(__MINGW32__) || defined(__MINGW64__) +# define FMT_NORETURN __attribute__((noreturn)) +#elif FMT_HAS_CPP_ATTRIBUTE(noreturn) +# define FMT_NORETURN [[noreturn]] +#else +# define FMT_NORETURN +#endif + #ifndef FMT_USE_RVALUE_REFERENCES // Don't use rvalue references when compiling with clang and an old libstdc++ // as the latter doesn't provide std::move. @@ -855,7 +864,7 @@ struct int_traits { std::numeric_limits::digits <= 32, uint32_t, uint64_t>::type main_type; }; -FMT_API void report_unknown_type(char code, const char *type); +FMT_API FMT_NORETURN void report_unknown_type(char code, const char *type); // Static data is placed in this class template to allow header-only // configuration. From 9f7957c0731dc2e1c3e4670e7f5b19bff74cfc09 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Wed, 26 Jul 2017 08:37:46 -0700 Subject: [PATCH 117/340] Separate argument parsing and formatting --- fmt/format.h | 266 ++++++++++++++++++++++++++------------------------ fmt/ostream.h | 2 +- 2 files changed, 140 insertions(+), 128 deletions(-) diff --git a/fmt/format.h b/fmt/format.h index 85f396b9..27d087ee 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -3268,6 +3268,144 @@ struct precision_handler { return 0; } }; + + +// Parses standard format specifiers. +template +basic_format_specs + parse_format_specs(const basic_arg& arg, Context &ctx) { + typedef typename Context::char_type Char; + basic_format_specs spec; + // Parse fill and alignment. + auto &it = ctx.pos(); + if (Char c = *it) { + auto p = it + 1; + spec.align_ = ALIGN_DEFAULT; + do { + switch (*p) { + case '<': + spec.align_ = ALIGN_LEFT; + break; + case '>': + spec.align_ = ALIGN_RIGHT; + break; + case '=': + spec.align_ = ALIGN_NUMERIC; + break; + case '^': + spec.align_ = ALIGN_CENTER; + break; + } + if (spec.align_ != ALIGN_DEFAULT) { + if (p != it) { + if (c == '}') break; + if (c == '{') + FMT_THROW(format_error("invalid fill character '{'")); + it += 2; + spec.fill_ = c; + } else ++it; + if (spec.align_ == ALIGN_NUMERIC) + internal::require_numeric_argument(arg, '='); + break; + } + } while (--p >= it); + } + + // Parse sign. + switch (*it) { + case '+': + internal::check_sign(it, arg); + spec.flags_ |= SIGN_FLAG | PLUS_FLAG; + break; + case '-': + internal::check_sign(it, arg); + spec.flags_ |= MINUS_FLAG; + break; + case ' ': + internal::check_sign(it, arg); + spec.flags_ |= SIGN_FLAG; + break; + } + + if (*it == '#') { + internal::require_numeric_argument(arg, '#'); + spec.flags_ |= HASH_FLAG; + ++it; + } + + // Parse zero flag. + if (*it == '0') { + internal::require_numeric_argument(arg, '0'); + spec.align_ = ALIGN_NUMERIC; + spec.fill_ = '0'; + ++it; + } + + // Parse width. + if ('0' <= *it && *it <= '9') { + spec.width_ = internal::parse_nonnegative_int(it); + } else if (*it == '{') { + ++it; + auto width_arg = ctx.parse_arg_id(); + if (*it++ != '}') + FMT_THROW(format_error("invalid format string")); + ulong_long width = visit(internal::width_handler(), width_arg); + if (width > (std::numeric_limits::max)()) + FMT_THROW(format_error("number is too big")); + spec.width_ = static_cast(width); + } + + // Parse precision. + if (*it == '.') { + ++it; + spec.precision_ = 0; + if ('0' <= *it && *it <= '9') { + spec.precision_ = internal::parse_nonnegative_int(it); + } else if (*it == '{') { + ++it; + auto precision_arg = ctx.parse_arg_id(); + if (*it++ != '}') + FMT_THROW(format_error("invalid format string")); + ulong_long precision = + visit(internal::precision_handler(), precision_arg); + if (precision > (std::numeric_limits::max)()) + FMT_THROW(format_error("number is too big")); + spec.precision_ = static_cast(precision); + } else { + FMT_THROW(format_error("missing precision specifier")); + } + if (arg.is_integral() || arg.is_pointer()) { + FMT_THROW(format_error( + fmt::format("precision not allowed in {} format specifier", + arg.is_pointer() ? "pointer" : "integer"))); + } + } + + // Parse type. + if (*it != '}' && *it) + spec.type_ = static_cast(*it++); + return spec; +} + +// Formats a single argument. +template +void do_format_arg(basic_buffer &buffer, const basic_arg& arg, + Context &ctx) { + auto &it = ctx.pos(); + basic_format_specs spec; + if (*it == ':') { + if (visit(internal::custom_formatter(buffer, ctx), arg)) + return; + ++it; + spec = internal::parse_format_specs(arg, ctx); + } + + if (*it != '}') + FMT_THROW(format_error("missing '}' in format string")); + + // Format argument. + visit(ArgFormatter(buffer, ctx, spec), arg); +} } // namespace internal template @@ -3312,132 +3450,6 @@ inline typename basic_context::format_arg return arg; } -// Formats a single argument. -template -void do_format_arg(basic_buffer &buffer, const basic_arg& arg, - Context &ctx) { - auto &it = ctx.pos(); - basic_format_specs spec; - if (*it == ':') { - if (visit(internal::custom_formatter(buffer, ctx), arg)) - return; - ++it; - // Parse fill and alignment. - if (Char c = *it) { - auto p = it + 1; - spec.align_ = ALIGN_DEFAULT; - do { - switch (*p) { - case '<': - spec.align_ = ALIGN_LEFT; - break; - case '>': - spec.align_ = ALIGN_RIGHT; - break; - case '=': - spec.align_ = ALIGN_NUMERIC; - break; - case '^': - spec.align_ = ALIGN_CENTER; - break; - } - if (spec.align_ != ALIGN_DEFAULT) { - if (p != it) { - if (c == '}') break; - if (c == '{') - FMT_THROW(format_error("invalid fill character '{'")); - it += 2; - spec.fill_ = c; - } else ++it; - if (spec.align_ == ALIGN_NUMERIC) - internal::require_numeric_argument(arg, '='); - break; - } - } while (--p >= it); - } - - // Parse sign. - switch (*it) { - case '+': - internal::check_sign(it, arg); - spec.flags_ |= SIGN_FLAG | PLUS_FLAG; - break; - case '-': - internal::check_sign(it, arg); - spec.flags_ |= MINUS_FLAG; - break; - case ' ': - internal::check_sign(it, arg); - spec.flags_ |= SIGN_FLAG; - break; - } - - if (*it == '#') { - internal::require_numeric_argument(arg, '#'); - spec.flags_ |= HASH_FLAG; - ++it; - } - - // Parse zero flag. - if (*it == '0') { - internal::require_numeric_argument(arg, '0'); - spec.align_ = ALIGN_NUMERIC; - spec.fill_ = '0'; - ++it; - } - - // Parse width. - if ('0' <= *it && *it <= '9') { - spec.width_ = internal::parse_nonnegative_int(it); - } else if (*it == '{') { - ++it; - auto width_arg = ctx.parse_arg_id(); - if (*it++ != '}') - FMT_THROW(format_error("invalid format string")); - ulong_long width = visit(internal::width_handler(), width_arg); - if (width > (std::numeric_limits::max)()) - FMT_THROW(format_error("number is too big")); - spec.width_ = static_cast(width); - } - - // Parse precision. - if (*it == '.') { - ++it; - spec.precision_ = 0; - if ('0' <= *it && *it <= '9') { - spec.precision_ = internal::parse_nonnegative_int(it); - } else if (*it == '{') { - ++it; - auto precision_arg = ctx.parse_arg_id(); - if (*it++ != '}') - FMT_THROW(format_error("invalid format string")); - ulong_long precision = - visit(internal::precision_handler(), precision_arg); - if (precision > (std::numeric_limits::max)()) - FMT_THROW(format_error("number is too big")); - spec.precision_ = static_cast(precision); - } else { - FMT_THROW(format_error("missing precision specifier")); - } - if (arg.is_integral() || arg.is_pointer()) { - FMT_THROW(format_error( - fmt::format("precision not allowed in {} format specifier", - arg.is_pointer() ? "pointer" : "integer"))); - } - } - - // Parse type. - if (*it != '}' && *it) - spec.type_ = static_cast(*it++); - } - - if (*it != '}') - FMT_THROW(format_error("missing '}' in format string")); - - // Format argument. - visit(ArgFormatter(buffer, ctx, spec), arg); -} - /** Formats arguments and writes the output to the buffer. */ template void vformat_to(basic_buffer &buffer, basic_string_view format_str, @@ -3457,7 +3469,7 @@ void vformat_to(basic_buffer &buffer, basic_string_view format_str, if (c == '}') FMT_THROW(format_error("unmatched '}' in format string")); buffer.append(pointer_from(start), pointer_from(it) - 1); - do_format_arg(buffer, ctx.parse_arg_id(), ctx); + internal::do_format_arg(buffer, ctx.parse_arg_id(), ctx); if (*it != '}') FMT_THROW(format_error(fmt::format("unknown format specifier"))); start = ++it; diff --git a/fmt/ostream.h b/fmt/ostream.h index 5a011f5a..3780b360 100644 --- a/fmt/ostream.h +++ b/fmt/ostream.h @@ -86,7 +86,7 @@ void format_value(basic_buffer &buf, const T &value, basic_memory_buffer buffer; internal::format_value(buffer, value); basic_string_view str(buffer.data(), buffer.size()); - do_format_arg< arg_formatter >( + internal::do_format_arg< arg_formatter >( buf, internal::make_arg< basic_context >(str), ctx); } From 873c8451ed8c53a976d7c7b05d328480e3a5d688 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Wed, 26 Jul 2017 08:42:57 -0700 Subject: [PATCH 118/340] Remove system_header pragma --- fmt/format.h | 8 -------- 1 file changed, 8 deletions(-) diff --git a/fmt/format.h b/fmt/format.h index 27d087ee..18e93199 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -3135,14 +3135,6 @@ void arg(wstring_view, const internal::named_arg&) FMT_DELETED_OR_UNDEFINED; } -#if FMT_GCC_VERSION -// Use the system_header pragma to suppress warnings about variadic macros -// because suppressing -Wvariadic-macros with the diagnostic pragma doesn't -// work. It is used at the end because we want to suppress as little warnings -// as possible. -# pragma GCC system_header -#endif - namespace fmt { namespace internal { template From 7bd776e7db41d18056a2d526efb117bd51420d7a Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Wed, 26 Jul 2017 08:48:59 -0700 Subject: [PATCH 119/340] Explain why null_terminating_iterator is used --- fmt/format.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/fmt/format.h b/fmt/format.h index 18e93199..8990d295 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -1947,7 +1947,9 @@ class null_terminating_iterator; template const Char *pointer_from(null_terminating_iterator it); -// An iterator that produces a null terminator on *end. +// An iterator that produces a null terminator on *end. This simplifies parsing +// and allows comparing the performance of processing a null-terminated string +// vs string_view. template class null_terminating_iterator { public: From 45911770c5cdd65979743fc17aeb9a8f17b19d93 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sat, 29 Jul 2017 07:50:16 -0700 Subject: [PATCH 120/340] Separate parsing and formatting in extension API --- fmt/format.h | 102 ++++++++++++++++++++++++-------------------- test/format-test.cc | 6 ++- 2 files changed, 59 insertions(+), 49 deletions(-) diff --git a/fmt/format.h b/fmt/format.h index 8990d295..7a8972ff 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -495,6 +495,10 @@ class format_error : public std::runtime_error { ~format_error() throw(); }; +// A formatter for objects of type T. +template +class formatter; + namespace internal { // make_unsigned::type gives an unsigned type corresponding to integer @@ -1099,6 +1103,16 @@ enum Type { CSTRING, STRING, TSTRING, POINTER, CUSTOM }; +inline bool is_integral(Type type) { + FMT_ASSERT(type != internal::NAMED_ARG, "invalid argument type"); + return type > internal::NONE && type <= internal::LAST_INTEGER_TYPE; +} + +inline bool is_numeric(Type type) { + FMT_ASSERT(type != internal::NAMED_ARG, "invalid argument type"); + return type > internal::NONE && type <= internal::LAST_NUMERIC_TYPE; +} + template struct string_value { const Char *value; @@ -1375,19 +1389,11 @@ class basic_arg { explicit operator bool() const noexcept { return type_ != internal::NONE; } - bool is_integral() const { - FMT_ASSERT(type_ != internal::NAMED_ARG, "invalid argument type"); - return type_ > internal::NONE && type_ <= internal::LAST_INTEGER_TYPE; - } + internal::Type type() const { return type_; } - bool is_numeric() const { - FMT_ASSERT(type_ != internal::NAMED_ARG, "invalid argument type"); - return type_ > internal::NONE && type_ <= internal::LAST_NUMERIC_TYPE; - } - - bool is_pointer() const { - return type_ == internal::POINTER; - } + bool is_integral() const { return internal::is_integral(type_); } + bool is_numeric() const { return internal::is_numeric(type_); } + bool is_pointer() const { return type_ == internal::POINTER; } }; /** @@ -3167,35 +3173,18 @@ unsigned parse_nonnegative_int(Iterator &it) { return value; } -template -inline void require_numeric_argument( - const basic_arg &arg, char spec) { - if (!arg.is_numeric()) { +inline void require_numeric_argument(Type type, char spec) { + if (!is_numeric(type)) { FMT_THROW(fmt::format_error( fmt::format("format specifier '{}' requires numeric argument", spec))); } } -// An argument visitor that checks if argument is unsigned. -struct is_unsigned { - template - typename std::enable_if::value, bool>::type - operator()(T value) { - return true; - } - - template - typename std::enable_if::value, bool>::type - operator()(T value) { - return false; - } -}; - -template -void check_sign(Iterator &it, const basic_arg &arg) { +template +void check_sign(Iterator &it, Type type) { char sign = static_cast(*it); - require_numeric_argument(arg, sign); - if (visit(is_unsigned(), arg)) { + require_numeric_argument(type, sign); + if (is_integral(type) && type != INT && type != LONG_LONG && type != CHAR) { FMT_THROW(format_error(fmt::format( "format specifier '{}' requires signed argument", sign))); } @@ -3263,11 +3252,10 @@ struct precision_handler { } }; - // Parses standard format specifiers. template basic_format_specs - parse_format_specs(const basic_arg& arg, Context &ctx) { + parse_format_specs(Type arg_type, Context &ctx) { typedef typename Context::char_type Char; basic_format_specs spec; // Parse fill and alignment. @@ -3299,7 +3287,7 @@ basic_format_specs spec.fill_ = c; } else ++it; if (spec.align_ == ALIGN_NUMERIC) - internal::require_numeric_argument(arg, '='); + internal::require_numeric_argument(arg_type, '='); break; } } while (--p >= it); @@ -3308,28 +3296,28 @@ basic_format_specs // Parse sign. switch (*it) { case '+': - internal::check_sign(it, arg); + internal::check_sign(it, arg_type); spec.flags_ |= SIGN_FLAG | PLUS_FLAG; break; case '-': - internal::check_sign(it, arg); + internal::check_sign(it, arg_type); spec.flags_ |= MINUS_FLAG; break; case ' ': - internal::check_sign(it, arg); + internal::check_sign(it, arg_type); spec.flags_ |= SIGN_FLAG; break; } if (*it == '#') { - internal::require_numeric_argument(arg, '#'); + internal::require_numeric_argument(arg_type, '#'); spec.flags_ |= HASH_FLAG; ++it; } // Parse zero flag. if (*it == '0') { - internal::require_numeric_argument(arg, '0'); + internal::require_numeric_argument(arg_type, '0'); spec.align_ = ALIGN_NUMERIC; spec.fill_ = '0'; ++it; @@ -3368,10 +3356,10 @@ basic_format_specs } else { FMT_THROW(format_error("missing precision specifier")); } - if (arg.is_integral() || arg.is_pointer()) { + if (is_integral(arg_type) || arg_type == POINTER) { FMT_THROW(format_error( fmt::format("precision not allowed in {} format specifier", - arg.is_pointer() ? "pointer" : "integer"))); + arg_type == POINTER ? "pointer" : "integer"))); } } @@ -3383,7 +3371,7 @@ basic_format_specs // Formats a single argument. template -void do_format_arg(basic_buffer &buffer, const basic_arg& arg, +void do_format_arg(basic_buffer &buffer, const basic_arg &arg, Context &ctx) { auto &it = ctx.pos(); basic_format_specs spec; @@ -3391,7 +3379,7 @@ void do_format_arg(basic_buffer &buffer, const basic_arg& arg, if (visit(internal::custom_formatter(buffer, ctx), arg)) return; ++it; - spec = internal::parse_format_specs(arg, ctx); + spec = internal::parse_format_specs(arg.type(), ctx); } if (*it != '}') @@ -3402,6 +3390,26 @@ void do_format_arg(basic_buffer &buffer, const basic_arg& arg, } } // namespace internal +template +class formatter { + public: + explicit formatter(basic_context &ctx) { + auto &it = ctx.pos(); + if (*it == ':') { + ++it; + specs_ = parse_format_specs(internal::gettype(), ctx); + } + } + + void format(basic_buffer &buf, const T &val, basic_context &ctx) { + visit(arg_formatter(buf, ctx, specs_), + internal::make_arg>(val)); + } + + private: + basic_format_specs specs_; +}; + template inline typename basic_context::format_arg basic_context::get_arg( diff --git a/test/format-test.cc b/test/format-test.cc index 49611eb8..fc438430 100644 --- a/test/format-test.cc +++ b/test/format-test.cc @@ -1240,12 +1240,14 @@ TEST(FormatterTest, FormatCustom) { class Answer {}; template -void format_value(fmt::basic_buffer &buf, Answer, fmt::context &) { - fmt::format_to(buf, "{}", 42); +void format_value(fmt::basic_buffer &buf, Answer, fmt::context &ctx) { + fmt::formatter f(ctx); + f.format(buf, 42, ctx); } TEST(FormatterTest, CustomFormat) { EXPECT_EQ("42", format("{0}", Answer())); + EXPECT_EQ("0042", format("{:04}", Answer())); } TEST(FormatterTest, WideFormatString) { From 1102d465087913e07cbbb1b83279d897022c37a4 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sun, 30 Jul 2017 08:37:26 -0700 Subject: [PATCH 121/340] Make format spec parsing context-independent --- fmt/format.h | 290 ++++++++++++++++++++++++++++++-------------- fmt/printf.h | 10 +- test/format-test.cc | 3 +- 3 files changed, 205 insertions(+), 98 deletions(-) diff --git a/fmt/format.h b/fmt/format.h index 7a8972ff..d7dbf00c 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -1694,7 +1694,7 @@ struct empty_spec {}; struct AlignSpec : empty_spec { unsigned width_; // Fill is always wchar_t and cast to char if necessary to avoid having - // two specialization of WidthSpec and its subclasses. + // two specialization of AlignSpec and its subclasses. wchar_t fill_; alignment align_; @@ -1959,6 +1959,7 @@ const Char *pointer_from(null_terminating_iterator it); template class null_terminating_iterator { public: + typedef Char value_type; typedef std::ptrdiff_t difference_type; null_terminating_iterator() : ptr_(0), end_(0) {} @@ -2062,7 +2063,7 @@ class context_base { // Returns the argument with specified index. format_arg do_get_arg(unsigned arg_index, const char *&error) { format_arg arg = args_[arg_index]; - if (!arg) + if (!arg && !error) error = "argument index out of range"; return arg; } @@ -2074,12 +2075,12 @@ class context_base { this->do_get_arg(arg_index, error) : format_arg(); } - // Returns the next argument. - format_arg next_arg(const char *&error) { + // Returns the next argument index. + unsigned next_arg_index(const char *&error) { if (next_arg_index_ >= 0) - return this->do_get_arg(internal::to_unsigned(next_arg_index_++), error); + return internal::to_unsigned(next_arg_index_++); error = "cannot switch from manual to automatic argument indexing"; - return format_arg(); + return 0; } bool check_no_auto_index(const char *&error) { @@ -2145,10 +2146,6 @@ class basic_context : typedef typename Base::format_arg format_arg; using Base::get_arg; - // Checks if manual indexing is used and returns the argument with - // specified name. - format_arg get_arg(basic_string_view name, const char *&error); - public: /** \rst @@ -2160,8 +2157,26 @@ class basic_context : basic_string_view format_str, basic_args args) : Base(format_str, args) {} - // Parses argument id and returns corresponding argument. - format_arg parse_arg_id(); + format_arg next_arg() { + const char *error = 0; + format_arg arg = this->do_get_arg(this->next_arg_index(error), error); + if (error) + FMT_THROW(format_error(error)); + return arg; + } + + format_arg get_arg(unsigned arg_index) { + const char *error = 0; + this->check_no_auto_index(error); + format_arg arg = this->do_get_arg(arg_index, error); + if (error) + FMT_THROW(format_error(error)); + return arg; + } + + // Checks if manual indexing is used and returns the argument with + // specified name. + format_arg get_arg(basic_string_view name); using Base::pos; }; @@ -3252,42 +3267,129 @@ struct precision_handler { } }; -// Parses standard format specifiers. template -basic_format_specs - parse_format_specs(Type arg_type, Context &ctx) { - typedef typename Context::char_type Char; - basic_format_specs spec; +class specs_handler { + public: + typedef typename Context::char_type char_type; + + specs_handler(basic_format_specs &specs, Context &ctx) + : specs_(specs), context_(ctx) {} + + void on_align(alignment align) { specs_.align_ = align; } + void on_fill(char_type fill) { specs_.fill_ = fill; } + void on_plus() { specs_.flags_ |= SIGN_FLAG | PLUS_FLAG; } + void on_minus() { specs_.flags_ |= MINUS_FLAG; } + void on_space() { specs_.flags_ |= SIGN_FLAG; } + void on_hash() { specs_.flags_ |= HASH_FLAG; } + + void on_zero() { + specs_.align_ = ALIGN_NUMERIC; + specs_.fill_ = '0'; + } + + void on_width(unsigned width) { specs_.width_ = width; } + + template + void on_dynamic_width(Id arg_id) { + auto width_arg = get_arg(arg_id); + ulong_long width = visit(internal::width_handler(), width_arg); + if (width > (std::numeric_limits::max)()) + FMT_THROW(format_error("number is too big")); + specs_.width_ = static_cast(width); + } + + void on_precision(unsigned precision) { specs_.precision_ = precision; } + + template + void on_dynamic_precision(Id arg_id) { + auto precision_arg = get_arg(arg_id); + ulong_long precision = visit(internal::precision_handler(), precision_arg); + if (precision > (std::numeric_limits::max)()) + FMT_THROW(format_error("number is too big")); + specs_.precision_ = static_cast(precision); + } + + void on_type(char type) { specs_.type_ = type; } + + private: + basic_arg get_arg(monostate) { + return context_.next_arg(); + } + + basic_arg get_arg(unsigned index) { + return context_.get_arg(index); + } + + basic_arg get_arg(basic_string_view name) { + return context_.get_arg(name); + } + + basic_format_specs &specs_; + Context &context_; +}; + +template +Iterator parse_arg_id(Iterator it, Handler handler) { + typedef typename Iterator::value_type char_type; + char_type c = *it; + if (c == '}' || c == ':') { + handler(); + return it; + } + if (c >= '0' && c <= '9') { + unsigned index = parse_nonnegative_int(it); + if (*it != '}' && *it != ':') { + FMT_THROW(format_error("invalid format string")); + } + handler(index); + return it; + } + if (!is_name_start(c)) { + FMT_THROW(format_error("invalid format string")); + } + auto start = it; + do { + c = *++it; + } while (is_name_start(c) || ('0' <= c && c <= '9')); + handler(basic_string_view(pointer_from(start), it - start)); + return it; +} + +// Parses standard format specifiers and sends notifications about parsed +// components to handler. +template +Iterator parse_format_specs(Iterator it, Type arg_type, Handler &handler) { + typedef typename Iterator::value_type char_type; // Parse fill and alignment. - auto &it = ctx.pos(); - if (Char c = *it) { + if (char_type c = *it) { auto p = it + 1; - spec.align_ = ALIGN_DEFAULT; + alignment align = ALIGN_DEFAULT; do { switch (*p) { case '<': - spec.align_ = ALIGN_LEFT; + align = ALIGN_LEFT; break; case '>': - spec.align_ = ALIGN_RIGHT; + align = ALIGN_RIGHT; break; case '=': - spec.align_ = ALIGN_NUMERIC; + align = ALIGN_NUMERIC; break; case '^': - spec.align_ = ALIGN_CENTER; + align = ALIGN_CENTER; break; } - if (spec.align_ != ALIGN_DEFAULT) { + if (align != ALIGN_DEFAULT) { + handler.on_align(align); if (p != it) { if (c == '}') break; if (c == '{') FMT_THROW(format_error("invalid fill character '{'")); it += 2; - spec.fill_ = c; + handler.on_fill(c); } else ++it; - if (spec.align_ == ALIGN_NUMERIC) - internal::require_numeric_argument(arg_type, '='); + if (align == ALIGN_NUMERIC) + require_numeric_argument(arg_type, '='); break; } } while (--p >= it); @@ -3296,63 +3398,72 @@ basic_format_specs // Parse sign. switch (*it) { case '+': - internal::check_sign(it, arg_type); - spec.flags_ |= SIGN_FLAG | PLUS_FLAG; + check_sign(it, arg_type); + handler.on_plus(); break; case '-': - internal::check_sign(it, arg_type); - spec.flags_ |= MINUS_FLAG; + check_sign(it, arg_type); + handler.on_minus(); break; case ' ': - internal::check_sign(it, arg_type); - spec.flags_ |= SIGN_FLAG; + check_sign(it, arg_type); + handler.on_space(); break; } if (*it == '#') { - internal::require_numeric_argument(arg_type, '#'); - spec.flags_ |= HASH_FLAG; + require_numeric_argument(arg_type, '#'); + handler.on_hash(); ++it; } // Parse zero flag. if (*it == '0') { - internal::require_numeric_argument(arg_type, '0'); - spec.align_ = ALIGN_NUMERIC; - spec.fill_ = '0'; + require_numeric_argument(arg_type, '0'); + handler.on_zero(); ++it; } // Parse width. if ('0' <= *it && *it <= '9') { - spec.width_ = internal::parse_nonnegative_int(it); + handler.on_width(parse_nonnegative_int(it)); } else if (*it == '{') { - ++it; - auto width_arg = ctx.parse_arg_id(); + struct width_handler { + explicit width_handler(Handler &h) : handler(h) {} + + void operator()() { handler.on_dynamic_width(monostate()); } + void operator()(unsigned id) { handler.on_dynamic_width(id); } + void operator()(basic_string_view id) { + handler.on_dynamic_width(id); + } + + Handler &handler; + }; + it = parse_arg_id(it + 1, width_handler(handler)); if (*it++ != '}') FMT_THROW(format_error("invalid format string")); - ulong_long width = visit(internal::width_handler(), width_arg); - if (width > (std::numeric_limits::max)()) - FMT_THROW(format_error("number is too big")); - spec.width_ = static_cast(width); } // Parse precision. if (*it == '.') { ++it; - spec.precision_ = 0; if ('0' <= *it && *it <= '9') { - spec.precision_ = internal::parse_nonnegative_int(it); + handler.on_precision(parse_nonnegative_int(it)); } else if (*it == '{') { - ++it; - auto precision_arg = ctx.parse_arg_id(); + struct precision_handler { + explicit precision_handler(Handler &h) : handler(h) {} + + void operator()() { handler.on_dynamic_precision(monostate()); } + void operator()(unsigned id) { handler.on_dynamic_precision(id); } + void operator()(basic_string_view id) { + handler.on_dynamic_precision(id); + } + + Handler &handler; + }; + it = parse_arg_id(it + 1, precision_handler(handler)); if (*it++ != '}') FMT_THROW(format_error("invalid format string")); - ulong_long precision = - visit(internal::precision_handler(), precision_arg); - if (precision > (std::numeric_limits::max)()) - FMT_THROW(format_error("number is too big")); - spec.precision_ = static_cast(precision); } else { FMT_THROW(format_error("missing precision specifier")); } @@ -3365,8 +3476,8 @@ basic_format_specs // Parse type. if (*it != '}' && *it) - spec.type_ = static_cast(*it++); - return spec; + handler.on_type(static_cast(*it++)); + return it; } // Formats a single argument. @@ -3374,19 +3485,19 @@ template void do_format_arg(basic_buffer &buffer, const basic_arg &arg, Context &ctx) { auto &it = ctx.pos(); - basic_format_specs spec; + basic_format_specs specs; if (*it == ':') { - if (visit(internal::custom_formatter(buffer, ctx), arg)) + if (visit(custom_formatter(buffer, ctx), arg)) return; - ++it; - spec = internal::parse_format_specs(arg.type(), ctx); + specs_handler handler(specs, ctx); + it = parse_format_specs(it + 1, arg.type(), handler); } if (*it != '}') FMT_THROW(format_error("missing '}' in format string")); // Format argument. - visit(ArgFormatter(buffer, ctx, spec), arg); + visit(ArgFormatter(buffer, ctx, specs), arg); } } // namespace internal @@ -3397,7 +3508,8 @@ class formatter { auto &it = ctx.pos(); if (*it == ':') { ++it; - specs_ = parse_format_specs(internal::gettype(), ctx); + internal::specs_handler> handler(specs_, ctx); + it = parse_format_specs(it, internal::gettype(), handler); } } @@ -3412,44 +3524,17 @@ class formatter { template inline typename basic_context::format_arg - basic_context::get_arg( - basic_string_view name, const char *&error) { + basic_context::get_arg(basic_string_view name) { + const char *error = 0; if (this->check_no_auto_index(error)) { map_.init(this->args()); if (const format_arg *arg = map_.find(name)) return *arg; error = "argument not found"; } - return format_arg(); -} - -template -inline typename basic_context::format_arg - basic_context::parse_arg_id() { - format_arg arg; - auto &it = this->pos(); - if (!internal::is_name_start(*it)) { - const char *error = 0; - arg = *it < '0' || *it > '9' ? - this->next_arg(error) : - get_arg(internal::parse_nonnegative_int(it), error); - if (error) { - FMT_THROW(format_error( - *it != '}' && *it != ':' ? "invalid format string" : error)); - } - return arg; - } - auto start = it; - Char c; - do { - c = *++it; - } while (internal::is_name_start(c) || ('0' <= c && c <= '9')); - const char *error = 0; - arg = get_arg(basic_string_view( - internal::pointer_from(start), it - start), error); if (error) FMT_THROW(format_error(error)); - return arg; + return format_arg(); } /** Formats arguments and writes the output to the buffer. */ @@ -3471,7 +3556,24 @@ void vformat_to(basic_buffer &buffer, basic_string_view format_str, if (c == '}') FMT_THROW(format_error("unmatched '}' in format string")); buffer.append(pointer_from(start), pointer_from(it) - 1); - internal::do_format_arg(buffer, ctx.parse_arg_id(), ctx); + + basic_arg arg; + struct id_handler { + explicit id_handler(Context &ctx, basic_arg &arg) + : context(ctx), arg(arg) {} + + void operator()() { arg = context.next_arg(); } + void operator()(unsigned id) { arg = context.get_arg(id); } + void operator()(basic_string_view id) { + arg = context.get_arg(id); + } + + Context &context; + basic_arg &arg; + } handler(ctx, arg); + + it = parse_arg_id(it, handler); + internal::do_format_arg(buffer, arg, ctx); if (*it != '}') FMT_THROW(format_error(fmt::format("unknown format specifier"))); start = ++it; diff --git a/fmt/printf.h b/fmt/printf.h index 7bb27a89..c44ac414 100644 --- a/fmt/printf.h +++ b/fmt/printf.h @@ -367,8 +367,14 @@ typename printf_context::format_arg printf_context::get_arg( iterator it, unsigned arg_index) { (void)it; const char *error = 0; - format_arg arg = arg_index == std::numeric_limits::max() ? - this->next_arg(error) : Base::get_arg(arg_index - 1, error); + format_arg arg; + if (arg_index == std::numeric_limits::max()) { + arg_index = this->next_arg_index(error); + if (!error) + arg = this->do_get_arg(arg_index, error); + } else { + arg = Base::get_arg(arg_index - 1, error); + } if (error) FMT_THROW(format_error(!*it ? "invalid format string" : error)); return arg; diff --git a/test/format-test.cc b/test/format-test.cc index fc438430..25b36423 100644 --- a/test/format-test.cc +++ b/test/format-test.cc @@ -1239,8 +1239,7 @@ TEST(FormatterTest, FormatCustom) { class Answer {}; -template -void format_value(fmt::basic_buffer &buf, Answer, fmt::context &ctx) { +void format_value(fmt::buffer &buf, Answer, fmt::context &ctx) { fmt::formatter f(ctx); f.format(buf, 42, ctx); } From 5e0562ab51f1d5fd75ed7e38aa47524bb23b4df4 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sun, 13 Aug 2017 13:09:02 -0700 Subject: [PATCH 122/340] Separate parsing and formatting --- fmt/format.h | 476 +++++++++++++++++++++------------- fmt/ostream.h | 30 ++- fmt/printf.cc | 4 +- fmt/printf.h | 53 ++-- fmt/time.h | 72 ++--- test/custom-formatter-test.cc | 4 +- test/format-test.cc | 24 +- test/ostream-test.cc | 2 +- test/util-test.cc | 54 ++-- 9 files changed, 449 insertions(+), 270 deletions(-) diff --git a/fmt/format.h b/fmt/format.h index d7dbf00c..907911fe 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -451,6 +451,11 @@ class basic_string_view { /** Returns the string size. */ std::size_t size() const { return size_; } + void remove_prefix(size_t n) { + data_ += n; + size_ -= n; + } + // Lexicographically compare this string reference to other. int compare(basic_string_view other) const { std::size_t size = size_ < other.size_ ? size_ : other.size_; @@ -483,6 +488,9 @@ class basic_string_view { typedef basic_string_view string_view; typedef basic_string_view wstring_view; +template +inline const Char *begin(basic_string_view s) { return s.data(); } + /** A formatting error such as invalid format string. */ class format_error : public std::runtime_error { public: @@ -496,8 +504,8 @@ class format_error : public std::runtime_error { }; // A formatter for objects of type T. -template -class formatter; +template +struct formatter; namespace internal { @@ -847,6 +855,109 @@ struct conditional { typedef T type; }; template struct conditional { typedef F type; }; +template +class null_terminating_iterator; + +template +const Char *pointer_from(null_terminating_iterator it); + +// An iterator that produces a null terminator on *end. This simplifies parsing +// and allows comparing the performance of processing a null-terminated string +// vs string_view. +template +class null_terminating_iterator { + public: + typedef Char value_type; + typedef std::ptrdiff_t difference_type; + + null_terminating_iterator() : ptr_(0), end_(0) {} + + null_terminating_iterator(const Char *ptr, const Char *end) + : ptr_(ptr), end_(end) {} + + explicit null_terminating_iterator(basic_string_view s) + : ptr_(s.data()), end_(s.data() + s.size()) {} + + null_terminating_iterator &operator=(const Char *ptr) { + assert(ptr <= end_); + ptr_ = ptr; + return *this; + } + + Char operator*() const { + return ptr_ != end_ ? *ptr_ : 0; + } + + null_terminating_iterator operator++() { + ++ptr_; + return *this; + } + + null_terminating_iterator operator++(int) { + null_terminating_iterator result(*this); + ++ptr_; + return result; + } + + null_terminating_iterator operator--() { + --ptr_; + return *this; + } + + null_terminating_iterator operator+(difference_type n) { + return null_terminating_iterator(ptr_ + n, end_); + } + + null_terminating_iterator operator+=(difference_type n) { + ptr_ += n; + return *this; + } + + difference_type operator-(null_terminating_iterator other) const { + return ptr_ - other.ptr_; + } + + bool operator!=(null_terminating_iterator other) const { + return ptr_ != other.ptr_; + } + + bool operator>=(null_terminating_iterator other) const { + return ptr_ >= other.ptr_; + } + + friend const Char *pointer_from(null_terminating_iterator it); + + private: + const Char *ptr_; + const Char *end_; +}; + +template < + typename T, + typename Char, + typename std::enable_if< + std::is_same>::value, int>::type = 0> +null_terminating_iterator to_iterator(basic_string_view v) { + const Char *s = v.data(); + return null_terminating_iterator(s, s + v.size()); +} + +template < + typename T, + typename Char, + typename std::enable_if::value, int>::type = 0> +const Char *to_iterator(basic_string_view v) { + return v.data(); +} + +template +const T *pointer_from(const T *p) { return p; } + +template +const Char *pointer_from(null_terminating_iterator it) { + return it.ptr_; +} + // Returns true if value is negative, false otherwise. // Same as (value < 0) but doesn't produce warnings if T is an unsigned type. template @@ -1122,7 +1233,8 @@ struct string_value { template struct custom_value { typedef void (*FormatFunc)( - basic_buffer &buffer, const void *arg, void *ctx); + basic_buffer &buffer, const void *arg, + basic_string_view& format, void *ctx); const void *value; FormatFunc format; @@ -1243,9 +1355,16 @@ class value { // Formats an argument of a custom type, such as a user-defined class. template static void format_custom_arg( - basic_buffer &buffer, const void *arg, void *context) { - format_value(buffer, *static_cast(arg), - *static_cast(context)); + basic_buffer &buffer, const void *arg, + basic_string_view &format, void *context) { + Context &ctx = *static_cast(context); + // Get the formatter type through the context to allow different contexts + // have different extension points, e.g. `formatter` for `format` and + // `printf_formatter` for `printf`. + typename Context::template formatter_type f; + auto it = f.parse(format); + format.remove_prefix(it - begin(format)); + f.format(buffer, *static_cast(arg), ctx); } public: @@ -1475,14 +1594,6 @@ basic_arg make_arg(const T &value) { typedef int FMT_CONCAT_(Assert, __LINE__)[(cond) ? 1 : -1] FMT_UNUSED #endif -template -void format_value(basic_buffer &, const T &, Formatter &, const Char *) { - FMT_STATIC_ASSERT(sizeof(T) < 0, - "Cannot format argument. To enable the use of ostream " - "operator<< include fmt/ostream.h. Otherwise provide " - "an overload of format_value."); -} - template struct named_arg : basic_arg { typedef typename Context::char_type Char; @@ -1947,115 +2058,17 @@ class arg_formatter_base { } }; -template -class null_terminating_iterator; - -template -const Char *pointer_from(null_terminating_iterator it); - -// An iterator that produces a null terminator on *end. This simplifies parsing -// and allows comparing the performance of processing a null-terminated string -// vs string_view. -template -class null_terminating_iterator { - public: - typedef Char value_type; - typedef std::ptrdiff_t difference_type; - - null_terminating_iterator() : ptr_(0), end_(0) {} - - null_terminating_iterator(const Char *ptr, const Char *end) - : ptr_(ptr), end_(end) {} - - Char operator*() const { - return ptr_ != end_ ? *ptr_ : 0; - } - - null_terminating_iterator operator++() { - ++ptr_; - return *this; - } - - null_terminating_iterator operator++(int) { - null_terminating_iterator result(*this); - ++ptr_; - return result; - } - - null_terminating_iterator operator--() { - --ptr_; - return *this; - } - - null_terminating_iterator operator+(difference_type n) { - return null_terminating_iterator(ptr_ + n, end_); - } - - null_terminating_iterator operator+=(difference_type n) { - ptr_ += n; - return *this; - } - - difference_type operator-(null_terminating_iterator other) const { - return ptr_ - other.ptr_; - } - - bool operator!=(null_terminating_iterator other) const { - return ptr_ != other.ptr_; - } - - bool operator>=(null_terminating_iterator other) const { - return ptr_ >= other.ptr_; - } - - friend const Char *pointer_from(null_terminating_iterator it); - - private: - const Char *ptr_; - const Char *end_; -}; - -template < - typename T, - typename Char, - typename std::enable_if< - std::is_same>::value, int>::type = 0> -null_terminating_iterator to_iterator(basic_string_view v) { - const Char *s = v.data(); - return null_terminating_iterator(s, s + v.size()); -} - -template < - typename T, - typename Char, - typename std::enable_if::value, int>::type = 0> -const Char *to_iterator(const basic_string_view v) { - return v.data(); -} - -template -const T *pointer_from(const T *p) { return p; } - -template -const Char *pointer_from(null_terminating_iterator it) { - return it.ptr_; -} - template class context_base { - public: - typedef null_terminating_iterator iterator; - private: - iterator pos_; basic_args args_; int next_arg_index_; protected: typedef basic_arg format_arg; - context_base(basic_string_view format_str, basic_args args) - : pos_(to_iterator(format_str)), args_(args), next_arg_index_(0) {} + explicit context_base(basic_args args) + : args_(args), next_arg_index_(0) {} ~context_base() {} basic_args args() const { return args_; } @@ -2091,10 +2104,6 @@ class context_base { next_arg_index_ = -1; return true; } - - public: - // Returns an iterator to the current position in the format string. - iterator &pos() { return pos_; } }; } // namespace internal @@ -2125,7 +2134,8 @@ class arg_formatter : public internal::arg_formatter_base { /** Formats an argument of a custom (user-defined) type. */ void operator()(internal::custom_value c) { - c.format(this->writer().buffer(), c.value, &ctx_); + basic_string_view format_str; + c.format(this->writer().buffer(), c.value, format_str, &ctx_); } }; @@ -2134,7 +2144,10 @@ class basic_context : public internal::context_base> { public: /** The character type for the output. */ - typedef Char char_type; + using char_type = Char; + + template + using formatter_type = formatter; private: internal::arg_map> map_; @@ -2153,9 +2166,7 @@ class basic_context : stored in the object so make sure they have appropriate lifetimes. \endrst */ - basic_context( - basic_string_view format_str, basic_args args) - : Base(format_str, args) {} + basic_context(basic_args args): Base(args) {} format_arg next_arg() { const char *error = 0; @@ -2177,8 +2188,6 @@ class basic_context : // Checks if manual indexing is used and returns the argument with // specified name. format_arg get_arg(basic_string_view name); - - using Base::pos; }; /** @@ -3210,14 +3219,16 @@ template class custom_formatter { private: basic_buffer &buffer_; + basic_string_view &format_; Context &ctx_; public: - custom_formatter(basic_buffer &buffer, Context &ctx) - : buffer_(buffer), ctx_(ctx) {} + custom_formatter(basic_buffer &buffer, basic_string_view &format, + Context &ctx) + : buffer_(buffer), format_(format), ctx_(ctx) {} bool operator()(internal::custom_value custom) { - custom.format(buffer_, custom.value, &ctx_); + custom.format(buffer_, custom.value, format_, &ctx_); return true; } @@ -3267,16 +3278,14 @@ struct precision_handler { } }; -template -class specs_handler { +template +class specs_handler_base { public: - typedef typename Context::char_type char_type; - - specs_handler(basic_format_specs &specs, Context &ctx) - : specs_(specs), context_(ctx) {} + explicit specs_handler_base(basic_format_specs &specs) + : specs_(specs) {} void on_align(alignment align) { specs_.align_ = align; } - void on_fill(char_type fill) { specs_.fill_ = fill; } + void on_fill(Char fill) { specs_.fill_ = fill; } void on_plus() { specs_.flags_ |= SIGN_FLAG | PLUS_FLAG; } void on_minus() { specs_.flags_ |= MINUS_FLAG; } void on_space() { specs_.flags_ |= SIGN_FLAG; } @@ -3288,46 +3297,107 @@ class specs_handler { } void on_width(unsigned width) { specs_.width_ = width; } + void on_precision(unsigned precision) { specs_.precision_ = precision; } + void on_type(char type) { specs_.type_ = type; } + + protected: + ~specs_handler_base() {} + + basic_format_specs &specs_; +}; + +template +inline void set_dynamic_spec(T &value, basic_arg arg) { + ulong_long big_value = visit(Handler(), arg); + if (big_value > (std::numeric_limits::max)()) + FMT_THROW(format_error("number is too big")); + value = static_cast(big_value); +} + +template +class specs_handler : public specs_handler_base { + public: + typedef typename Context::char_type char_type; + + specs_handler(basic_format_specs &specs, Context &ctx) + : specs_handler_base(specs), context_(ctx) {} template void on_dynamic_width(Id arg_id) { - auto width_arg = get_arg(arg_id); - ulong_long width = visit(internal::width_handler(), width_arg); - if (width > (std::numeric_limits::max)()) - FMT_THROW(format_error("number is too big")); - specs_.width_ = static_cast(width); + set_dynamic_spec( + this->specs_.width_, get_arg(arg_id)); } - void on_precision(unsigned precision) { specs_.precision_ = precision; } - template void on_dynamic_precision(Id arg_id) { - auto precision_arg = get_arg(arg_id); - ulong_long precision = visit(internal::precision_handler(), precision_arg); - if (precision > (std::numeric_limits::max)()) - FMT_THROW(format_error("number is too big")); - specs_.precision_ = static_cast(precision); + set_dynamic_spec( + this->specs_.precision_, get_arg(arg_id)); } - void on_type(char type) { specs_.type_ = type; } - private: basic_arg get_arg(monostate) { return context_.next_arg(); } - basic_arg get_arg(unsigned index) { - return context_.get_arg(index); + template + basic_arg get_arg(Id arg_id) { + return context_.get_arg(arg_id); } - basic_arg get_arg(basic_string_view name) { - return context_.get_arg(name); - } - - basic_format_specs &specs_; Context &context_; }; +// An argument reference. +template +struct arg_ref { + enum Kind { NONE, INDEX, NAME }; + + arg_ref() : kind(NONE) {} + explicit arg_ref(unsigned index) : kind(INDEX), index(index) {} + explicit arg_ref(basic_string_view name) : kind(NAME), name(name) {} + + Kind kind; + union { + unsigned index; + basic_string_view name; + }; +}; + +template +struct dynamic_format_specs : basic_format_specs { + arg_ref width_ref; + arg_ref precision_ref; +}; + +template +class dynamic_specs_handler : public specs_handler_base { + public: + explicit dynamic_specs_handler(dynamic_format_specs &specs) + : specs_handler_base(specs), specs_(specs) {} + + template + void on_dynamic_width(Id arg_id) { + set(specs_.width_ref, arg_id); + } + + template + void on_dynamic_precision(Id arg_id) { + set(specs_.precision_ref, arg_id); + } + + private: + template + void set(arg_ref &ref, Id arg_id) { + ref = arg_ref(arg_id); + } + + void set(arg_ref &ref, monostate) { + ref.kind = arg_ref::NONE; + } + + dynamic_format_specs &specs_; +}; + template Iterator parse_arg_id(Iterator it, Handler handler) { typedef typename Iterator::value_type char_type; @@ -3338,15 +3408,13 @@ Iterator parse_arg_id(Iterator it, Handler handler) { } if (c >= '0' && c <= '9') { unsigned index = parse_nonnegative_int(it); - if (*it != '}' && *it != ':') { + if (*it != '}' && *it != ':') FMT_THROW(format_error("invalid format string")); - } handler(index); return it; } - if (!is_name_start(c)) { + if (!is_name_start(c)) FMT_THROW(format_error("invalid format string")); - } auto start = it; do { c = *++it; @@ -3357,6 +3425,9 @@ Iterator parse_arg_id(Iterator it, Handler handler) { // Parses standard format specifiers and sends notifications about parsed // components to handler. +// it: an iterator pointing to the beginning of a null-terminated range of +// characters, possibly emulated via null_terminating_iterator, representing +// format specifiers. template Iterator parse_format_specs(Iterator it, Type arg_type, Handler &handler) { typedef typename Iterator::value_type char_type; @@ -3482,13 +3553,16 @@ Iterator parse_format_specs(Iterator it, Type arg_type, Handler &handler) { // Formats a single argument. template -void do_format_arg(basic_buffer &buffer, const basic_arg &arg, - Context &ctx) { - auto &it = ctx.pos(); +const Char *do_format_arg(basic_buffer &buffer, + const basic_arg &arg, + basic_string_view format, + Context &ctx) { + auto it = null_terminating_iterator(format); basic_format_specs specs; if (*it == ':') { - if (visit(custom_formatter(buffer, ctx), arg)) - return; + format.remove_prefix(1); + if (visit(custom_formatter(buffer, format, ctx), arg)) + return begin(format); specs_handler handler(specs, ctx); it = parse_format_specs(it + 1, arg.type(), handler); } @@ -3498,28 +3572,69 @@ void do_format_arg(basic_buffer &buffer, const basic_arg &arg, // Format argument. visit(ArgFormatter(buffer, ctx, specs), arg); + return pointer_from(it); } + +// Specifies whether to format enums. +template +struct format_enum : std::integral_constant::value> {}; } // namespace internal -template -class formatter { - public: - explicit formatter(basic_context &ctx) { - auto &it = ctx.pos(); - if (*it == ':') { - ++it; - internal::specs_handler> handler(specs_, ctx); - it = parse_format_specs(it, internal::gettype(), handler); - } +// Formatter of objects of type T. +template +struct formatter() != internal::CUSTOM>::type> { + + // Parses format specifiers stopping either at the end of the range or at the + // terminating '}'. + template + auto parse(Range format) -> decltype(begin(format)) { + auto it = internal::null_terminating_iterator(format); + internal::dynamic_specs_handler handler(specs_); + it = parse_format_specs(it, internal::gettype(), handler); + return pointer_from(it); } void format(basic_buffer &buf, const T &val, basic_context &ctx) { + handle_dynamic_spec( + specs_.width_, specs_.width_ref, ctx); + handle_dynamic_spec( + specs_.precision_, specs_.precision_ref, ctx); visit(arg_formatter(buf, ctx, specs_), internal::make_arg>(val)); } private: - basic_format_specs specs_; + using arg_ref = internal::arg_ref; + + template + static void handle_dynamic_spec( + Spec &value, arg_ref ref, basic_context &ctx) { + switch (ref.kind) { + case arg_ref::NONE: + // Do nothing. + break; + case arg_ref::INDEX: + internal::set_dynamic_spec(value, ctx.get_arg(ref.index)); + break; + case arg_ref::NAME: + internal::set_dynamic_spec(value, ctx.get_arg(ref.name)); + break; + // TODO: handle automatic numbering + } + } + + internal::dynamic_format_specs specs_; +}; + +template +struct formatter::value>::type> + : public formatter { + template + auto parse(Range format) -> decltype(begin(format)) { + return begin(format); + } }; template @@ -3541,9 +3656,9 @@ inline typename basic_context::format_arg template void vformat_to(basic_buffer &buffer, basic_string_view format_str, basic_args args) { - basic_context ctx(format_str, args); - auto &it = ctx.pos(); - auto start = it; + basic_context ctx(args); + auto start = internal::null_terminating_iterator(format_str); + auto it = start; using internal::pointer_from; while (*it) { Char c = *it++; @@ -3573,7 +3688,8 @@ void vformat_to(basic_buffer &buffer, basic_string_view format_str, } handler(ctx, arg); it = parse_arg_id(it, handler); - internal::do_format_arg(buffer, arg, ctx); + format_str.remove_prefix(pointer_from(it) - format_str.data()); + it = internal::do_format_arg(buffer, arg, format_str, ctx); if (*it != '}') FMT_THROW(format_error(fmt::format("unknown format specifier"))); start = ++it; diff --git a/fmt/ostream.h b/fmt/ostream.h index 3780b360..f52e03d5 100644 --- a/fmt/ostream.h +++ b/fmt/ostream.h @@ -77,18 +77,28 @@ void format_value(basic_buffer &buffer, const T &value) { output << value; buffer.resize(format_buf.size()); } + +// Disable builtin formatting of enums and use operator<< instead. +template +struct format_enum::value>::type> : std::false_type {}; } // namespace internal -// Formats a value. -template -void format_value(basic_buffer &buf, const T &value, - basic_context &ctx) { - basic_memory_buffer buffer; - internal::format_value(buffer, value); - basic_string_view str(buffer.data(), buffer.size()); - internal::do_format_arg< arg_formatter >( - buf, internal::make_arg< basic_context >(str), ctx); -} +// Formats an object of type T that has an overloaded ostream operator<<. +template +struct formatter() == internal::CUSTOM>::type> + : formatter, Char> { + + void format(basic_buffer &buf, const T &value, + basic_context &ctx) { + basic_memory_buffer buffer; + internal::format_value(buffer, value); + basic_string_view str(buffer.data(), buffer.size()); + formatter, Char>::format(buf, str, ctx); + } +}; FMT_API void vprint(std::ostream &os, string_view format_str, args args); diff --git a/fmt/printf.cc b/fmt/printf.cc index 53d4c0b9..c107c46b 100644 --- a/fmt/printf.cc +++ b/fmt/printf.cc @@ -14,7 +14,7 @@ FMT_FUNC int vfprintf(std::FILE *f, string_view format, printf_args args) { } #ifndef FMT_HEADER_ONLY -template void printf_context::format(buffer &); -template void printf_context::format(wbuffer &); +template void printf_context::format(string_view, buffer &); +template void printf_context::format(wstring_view, wbuffer &); #endif } diff --git a/fmt/printf.h b/fmt/printf.h index c44ac414..f02f8e41 100644 --- a/fmt/printf.h +++ b/fmt/printf.h @@ -286,28 +286,46 @@ class printf_arg_formatter : public internal::arg_formatter_base { /** Formats an argument of a custom (user-defined) type. */ void operator()(internal::custom_value c) { - const Char format_str[] = {'}', '\0'}; + const Char format_str_data[] = {'}', '\0'}; + basic_string_view format_str = format_str_data; auto args = basic_args>(); - basic_context ctx(format_str, args); - c.format(this->writer().buffer(), c.value, &ctx); + basic_context ctx(args); + c.format(this->writer().buffer(), c.value, format_str, &ctx); + } +}; + +template > +class printf_context; + +template +struct printf_formatter { + const Char *parse(basic_string_view s) { + return s.data(); + } + + void format(basic_buffer &buf, const T &value, printf_context &) { + internal::format_value(buf, value); } }; /** This template formats data and writes the output to a writer. */ -template > +template class printf_context : private internal::context_base< Char, printf_context> { public: /** The character type for the output. */ - typedef Char char_type; + using char_type = Char; + + template + using formatter_type = printf_formatter; private: typedef internal::context_base Base; typedef typename Base::format_arg format_arg; typedef basic_format_specs format_specs; - typedef typename Base::iterator iterator; + typedef internal::null_terminating_iterator iterator; void parse_flags(format_specs &spec, iterator &it); @@ -328,12 +346,11 @@ class printf_context : appropriate lifetimes. \endrst */ - explicit printf_context(basic_string_view format_str, - basic_args args) - : Base(format_str, args) {} + explicit printf_context(basic_args args): Base(args) {} /** Formats stored arguments and writes the output to the buffer. */ - FMT_API void format(basic_buffer &buffer); + FMT_API void format( + basic_string_view format_str, basic_buffer &buffer); }; template @@ -415,8 +432,9 @@ unsigned printf_context::parse_header( } template -void printf_context::format(basic_buffer &buffer) { - auto start = this->pos(); +void printf_context::format( + basic_string_view format_str, basic_buffer &buffer) { + auto start = iterator(format_str); auto it = start; using internal::pointer_from; while (*it) { @@ -515,17 +533,10 @@ void printf_context::format(basic_buffer &buffer) { buffer.append(pointer_from(start), pointer_from(it)); } -// Formats a value. -template -void format_value(basic_buffer &buf, const T &value, - printf_context& ctx) { - internal::format_value(buf, value); -} - template void printf(basic_buffer &buf, basic_string_view format, basic_args> args) { - printf_context(format, args).format(buf); + printf_context(args).format(format, buf); } typedef basic_args> printf_args; diff --git a/fmt/time.h b/fmt/time.h index 02d84c8d..648c60ef 100644 --- a/fmt/time.h +++ b/fmt/time.h @@ -15,40 +15,46 @@ namespace fmt { -void format_value(buffer &buf, const std::tm &tm, context &ctx) { - auto &it = ctx.pos(); - if (*it == ':') - ++it; - auto end = it; - while (*end && *end != '}') - ++end; - if (*end != '}') - FMT_THROW(format_error("missing '}' in format string")); - memory_buffer format; - format.reserve(end - it + 1); - using internal::pointer_from; - format.append(pointer_from(it), pointer_from(end)); - format.push_back('\0'); - std::size_t start = buf.size(); - for (;;) { - std::size_t size = buf.capacity() - start; - std::size_t count = std::strftime(&buf[start], size, &format[0], &tm); - if (count != 0) { - buf.resize(start + count); - break; - } - if (size >= format.size() * 256) { - // If the buffer is 256 times larger than the format string, assume - // that `strftime` gives an empty result. There doesn't seem to be a - // better way to distinguish the two cases: - // https://github.com/fmtlib/fmt/issues/367 - break; - } - const std::size_t MIN_GROWTH = 10; - buf.reserve(buf.capacity() + (size > MIN_GROWTH ? size : MIN_GROWTH)); +template <> +struct formatter { + template + auto parse(Range format) -> decltype(begin(format)) { + auto it = internal::null_terminating_iterator(format); + if (*it == ':') + ++it; + auto end = it; + while (*end && *end != '}') + ++end; + tm_format.reserve(end - it + 1); + using internal::pointer_from; + tm_format.append(pointer_from(it), pointer_from(end)); + tm_format.push_back('\0'); + return pointer_from(end); } - it = end; -} + + void format(buffer &buf, const std::tm &tm, context &ctx) { + std::size_t start = buf.size(); + for (;;) { + std::size_t size = buf.capacity() - start; + std::size_t count = std::strftime(&buf[start], size, &tm_format[0], &tm); + if (count != 0) { + buf.resize(start + count); + break; + } + if (size >= tm_format.size() * 256) { + // If the buffer is 256 times larger than the format string, assume + // that `strftime` gives an empty result. There doesn't seem to be a + // better way to distinguish the two cases: + // https://github.com/fmtlib/fmt/issues/367 + break; + } + const std::size_t MIN_GROWTH = 10; + buf.reserve(buf.capacity() + (size > MIN_GROWTH ? size : MIN_GROWTH)); + } + } + + memory_buffer tm_format; +}; } #endif // FMT_TIME_H_ diff --git a/test/custom-formatter-test.cc b/test/custom-formatter-test.cc index e189fa4d..b84db61e 100644 --- a/test/custom-formatter-test.cc +++ b/test/custom-formatter-test.cc @@ -65,8 +65,8 @@ std::string custom_vsprintf( const char* format_str, fmt::basic_args args) { fmt::memory_buffer buffer; - CustomPrintfFormatter formatter(format_str, args); - formatter.format(buffer); + CustomPrintfFormatter formatter(args); + formatter.format(format_str, buffer); return std::string(buffer.data(), buffer.size()); } diff --git a/test/format-test.cc b/test/format-test.cc index 25b36423..88d30b72 100644 --- a/test/format-test.cc +++ b/test/format-test.cc @@ -1227,8 +1227,18 @@ TEST(FormatterTest, FormatStringView) { EXPECT_EQ("test", format("{0}", string_view("test"))); } -void format_value(fmt::buffer &buf, const Date &d, fmt::context &) { - fmt::format_to(buf, "{}-{}-{}", d.year(), d.month(), d.day()); +namespace fmt { +template <> +struct formatter { + template + auto parse(Range format) -> decltype(begin(format)) { + return begin(format); + } + + void format(buffer &buf, const Date &d, context &) { + format_to(buf, "{}-{}-{}", d.year(), d.month(), d.day()); + } +}; } TEST(FormatterTest, FormatCustom) { @@ -1239,9 +1249,13 @@ TEST(FormatterTest, FormatCustom) { class Answer {}; -void format_value(fmt::buffer &buf, Answer, fmt::context &ctx) { - fmt::formatter f(ctx); - f.format(buf, 42, ctx); +namespace fmt { +template <> +struct formatter : formatter { + void format(fmt::buffer &buf, Answer, fmt::context &ctx) { + formatter::format(buf, 42, ctx); + } +}; } TEST(FormatterTest, CustomFormat) { diff --git a/test/ostream-test.cc b/test/ostream-test.cc index c0bc4b0d..1b3119c3 100644 --- a/test/ostream-test.cc +++ b/test/ostream-test.cc @@ -65,7 +65,7 @@ struct TestArgFormatter : fmt::arg_formatter { TEST(OStreamTest, CustomArg) { fmt::memory_buffer buffer; - fmt::context ctx("}", fmt::args()); + fmt::context ctx((fmt::args())); fmt::format_specs spec; TestArgFormatter af(buffer, ctx, spec); visit(af, fmt::internal::make_arg(TestEnum())); diff --git a/test/util-test.cc b/test/util-test.cc index 1ca29817..6bae0439 100644 --- a/test/util-test.cc +++ b/test/util-test.cc @@ -66,19 +66,27 @@ namespace { struct Test {}; -template -void format_value(fmt::basic_buffer &b, Test, - fmt::basic_context &) { - const Char *test = "test"; - b.append(test, test + std::strlen(test)); -} - template basic_arg make_arg(const T &value) { return fmt::internal::make_arg(value); } } // namespace +namespace fmt { +template +struct formatter { + template + auto parse(Range format) -> decltype(begin(format)) { + return begin(format); + } + + void format(basic_buffer &b, Test, basic_context &) { + const Char *test = "test"; + b.append(test, test + std::strlen(test)); + } +}; +} + void CheckForwarding( MockAllocator &alloc, AllocatorRef< MockAllocator > &ref) { int mem; @@ -424,20 +432,33 @@ TEST(UtilTest, FormatArgs) { } struct CustomContext { - typedef char char_type; - bool called; -}; + using char_type = char; -void format_value(fmt::buffer &, const Test &, CustomContext &ctx) { - ctx.called = true; -} + template + struct formatter_type { + template + auto parse(Range range) -> decltype(begin(range)) { + return begin(range); + } + + void format(fmt::buffer &, const T &, CustomContext& ctx) { + ctx.called = true; + } + }; + + bool called; + + fmt::string_view format() { return ""; } + void advance_to(const char *) {} +}; TEST(UtilTest, MakeValueWithCustomFormatter) { ::Test t; fmt::internal::value arg(t); CustomContext ctx = {false}; fmt::memory_buffer buffer; - arg.custom.format(buffer, &t, &ctx); + fmt::string_view format_str; + arg.custom.format(buffer, &t, format_str, &ctx); EXPECT_TRUE(ctx.called); } @@ -581,8 +602,9 @@ TEST(UtilTest, CustomArg) { testing::Invoke([&](fmt::internal::custom_value custom) { EXPECT_EQ(&test, custom.value); fmt::memory_buffer buffer; - fmt::context ctx("}", fmt::args()); - custom.format(buffer, &test, &ctx); + fmt::context ctx((fmt::args())); + fmt::string_view format_str; + custom.format(buffer, &test, format_str, &ctx); EXPECT_EQ("test", std::string(buffer.data(), buffer.size())); return Visitor::Result(); })); From 70ef82a8e3fb4f9679a0a9bcb270b85584c188e4 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sun, 20 Aug 2017 10:02:08 -0700 Subject: [PATCH 123/340] Workaround a bug in MSVC --- fmt/format.h | 9 +++++++-- fmt/ostream.h | 3 +-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/fmt/format.h b/fmt/format.h index 907911fe..6c32ecc1 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -3575,6 +3575,12 @@ const Char *do_format_arg(basic_buffer &buffer, return pointer_from(it); } +// Specifies whether to format T using the standard formatter. +// It is not possible to use gettype in formatter specialization directly +// because of a bug in MSVC. +template +struct format_type : std::integral_constant() != CUSTOM> {}; + // Specifies whether to format enums. template struct format_enum : std::integral_constant::value> {}; @@ -3582,8 +3588,7 @@ struct format_enum : std::integral_constant::value> {}; // Formatter of objects of type T. template -struct formatter() != internal::CUSTOM>::type> { +struct formatter::value>::type> { // Parses format specifiers stopping either at the end of the range or at the // terminating '}'. diff --git a/fmt/ostream.h b/fmt/ostream.h index f52e03d5..e7e0b8e7 100644 --- a/fmt/ostream.h +++ b/fmt/ostream.h @@ -87,8 +87,7 @@ struct format_enum struct formatter() == internal::CUSTOM>::type> + typename std::enable_if::value>::type> : formatter, Char> { void format(basic_buffer &buf, const T &value, From 466386d5cd0154097a4fce73d41360a10bf6d38c Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Mon, 21 Aug 2017 06:41:03 -0700 Subject: [PATCH 124/340] Suppress a warning in gmock --- test/gmock/gmock.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/gmock/gmock.h b/test/gmock/gmock.h index 84f58cdd..8fd9c90c 100644 --- a/test/gmock/gmock.h +++ b/test/gmock/gmock.h @@ -825,8 +825,9 @@ template struct DecayArray { // crashes). template inline T Invalid() { + void *p = NULL; return const_cast::type&>( - *static_cast::type*>(NULL)); + *static_cast::type*>(p)); } template <> inline void Invalid() {} From 07f8ffc44f6de62f4fbdd2faf59244997c3bf2e0 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Mon, 21 Aug 2017 06:50:57 -0700 Subject: [PATCH 125/340] Suppress shadowing warnings --- fmt/format.cc | 4 ++++ fmt/format.h | 14 +++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/fmt/format.cc b/fmt/format.cc index 339138f8..266f8702 100644 --- a/fmt/format.cc +++ b/fmt/format.cc @@ -58,6 +58,10 @@ # define FMT_CATCH(x) if (false) #endif +// Disable the warning about declaration shadowing because it affects too +// many valid cases. +#pragma GCC diagnostic ignored "-Wshadow" + #ifdef _MSC_VER # pragma warning(push) # pragma warning(disable: 4127) // conditional expression is constant diff --git a/fmt/format.h b/fmt/format.h index 6c32ecc1..b2f3e56a 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -3766,6 +3766,13 @@ operator"" _a(const wchar_t *s, std::size_t) { return {s}; } } // namespace fmt #endif // FMT_USE_USER_DEFINED_LITERALS +#ifdef FMT_HEADER_ONLY +# define FMT_FUNC inline +# include "format.cc" +#else +# define FMT_FUNC +#endif + // Restore warnings. #if FMT_GCC_VERSION >= 406 # pragma GCC diagnostic pop @@ -3775,11 +3782,4 @@ operator"" _a(const wchar_t *s, std::size_t) { return {s}; } # pragma clang diagnostic pop #endif -#ifdef FMT_HEADER_ONLY -# define FMT_FUNC inline -# include "format.cc" -#else -# define FMT_FUNC -#endif - #endif // FMT_FORMAT_H_ From 016acebb5648bd55ffdd03733c456b6f97d4795b Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sat, 26 Aug 2017 09:09:43 -0700 Subject: [PATCH 126/340] Remove legacy code --- fmt/format.cc | 6 ++-- fmt/format.h | 73 +++++++++++++++------------------------- fmt/posix.cc | 6 ++-- fmt/posix.h | 2 +- fmt/printf.h | 4 +-- test/format-impl-test.cc | 7 ++-- test/posix-mock-test.cc | 2 +- test/printf-test.cc | 36 ++++++++++---------- test/util-test.cc | 6 ++-- 9 files changed, 60 insertions(+), 82 deletions(-) diff --git a/fmt/format.cc b/fmt/format.cc index 266f8702..e759084b 100644 --- a/fmt/format.cc +++ b/fmt/format.cc @@ -281,10 +281,8 @@ template const uint64_t internal::basic_data::POWERS_OF_10_64[] = { 0, FMT_POWERS_OF_10(1), - FMT_POWERS_OF_10(ulong_long(1000000000)), - // Multiply several constants instead of using a single long long constant - // to avoid warnings about C++98 not supporting long long. - ulong_long(1000000000) * ulong_long(1000000000) * 10 + FMT_POWERS_OF_10(1000000000ull), + 10000000000000000000ull }; FMT_FUNC void internal::report_unknown_type(char code, const char *type) { diff --git a/fmt/format.h b/fmt/format.h index b2f3e56a..1be263e5 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -41,6 +41,7 @@ #include #include #include +#include #ifdef _SECURE_SCL # define FMT_SECURE_SCL _SECURE_SCL @@ -52,20 +53,6 @@ # include #endif -#ifdef _MSC_VER -# define FMT_MSC_VER _MSC_VER -#else -# define FMT_MSC_VER 0 -#endif - -#if FMT_MSC_VER && FMT_MSC_VER <= 1500 -typedef unsigned __int32 uint32_t; -typedef unsigned __int64 uint64_t; -typedef __int64 intmax_t; -#else -#include -#endif - #if !defined(FMT_HEADER_ONLY) && defined(_WIN32) # ifdef FMT_EXPORT # define FMT_API __declspec(dllexport) @@ -79,14 +66,9 @@ typedef __int64 intmax_t; #ifdef __GNUC__ # define FMT_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) -# define FMT_GCC_EXTENSION __extension__ # if FMT_GCC_VERSION >= 406 # pragma GCC diagnostic push -// Disable the warning about "long long" which is sometimes reported even -// when using __extension__. -# pragma GCC diagnostic ignored "-Wlong-long" - // Disable the warning about declaration shadowing because it affects too // many valid cases. # pragma GCC diagnostic ignored "-Wshadow" @@ -99,8 +81,6 @@ typedef __int64 intmax_t; # if __cplusplus >= 201103L || defined __GXX_EXPERIMENTAL_CXX0X__ # define FMT_HAS_GXX_CXX11 1 # endif -#else -# define FMT_GCC_EXTENSION #endif #if defined(__INTEL_COMPILER) @@ -119,6 +99,12 @@ typedef __int64 intmax_t; # define FMT_GNUC_LIBSTD_VERSION (__GNUC_LIBSTD__ * 100 + __GNUC_LIBSTD_MINOR__) #endif +#ifdef _MSC_VER +# define FMT_MSC_VER _MSC_VER +#else +# define FMT_MSC_VER 0 +#endif + #ifdef __has_feature # define FMT_HAS_FEATURE(x) __has_feature(x) #else @@ -368,11 +354,6 @@ class numeric_limits : namespace fmt { -// Fix the warning about long long on older versions of GCC -// that don't support the diagnostic pragma. -FMT_GCC_EXTENSION typedef long long long_long; -FMT_GCC_EXTENSION typedef unsigned long long ulong_long; - #if FMT_USE_RVALUE_REFERENCES using std::move; #endif @@ -523,7 +504,7 @@ FMT_SPECIALIZE_MAKE_UNSIGNED(signed char, unsigned char); FMT_SPECIALIZE_MAKE_UNSIGNED(short, unsigned short); FMT_SPECIALIZE_MAKE_UNSIGNED(int, unsigned); FMT_SPECIALIZE_MAKE_UNSIGNED(long, unsigned long); -FMT_SPECIALIZE_MAKE_UNSIGNED(long_long, ulong_long); +FMT_SPECIALIZE_MAKE_UNSIGNED(long long, unsigned long long); // Casts nonnegative integer to unsigned. template @@ -1168,7 +1149,7 @@ typedef char no[2]; template T &get(); -yes &convert(fmt::ulong_long); +yes &convert(unsigned long long); no &convert(...); template @@ -1267,8 +1248,8 @@ template <> constexpr Type gettype() { return sizeof(unsigned long) == sizeof(unsigned) ? UINT : ULONG_LONG; } -template <> constexpr Type gettype() { return LONG_LONG; } -template <> constexpr Type gettype() { return ULONG_LONG; } +template <> constexpr Type gettype() { return LONG_LONG; } +template <> constexpr Type gettype() { return ULONG_LONG; } template <> constexpr Type gettype() { return DOUBLE; } template <> constexpr Type gettype() { return DOUBLE; } template <> constexpr Type gettype() { return LONG_DOUBLE; } @@ -1305,8 +1286,8 @@ class value { union { int int_value; unsigned uint_value; - long_long long_long_value; - ulong_long ulong_long_value; + long long long_long_value; + unsigned long long ulong_long_value; double double_value; long double long_double_value; const void *pointer; @@ -1401,8 +1382,8 @@ class value { this->ulong_long_value = value; } - FMT_MAKE_VALUE(long_long, long_long_value, LONG_LONG) - FMT_MAKE_VALUE(ulong_long, ulong_long_value, ULONG_LONG) + FMT_MAKE_VALUE(long long, long_long_value, LONG_LONG) + FMT_MAKE_VALUE(unsigned long long, ulong_long_value, ULONG_LONG) FMT_MAKE_VALUE(float, double_value, DOUBLE) FMT_MAKE_VALUE(double, double_value, DOUBLE) FMT_MAKE_VALUE(long double, long_double_value, LONG_DOUBLE) @@ -2437,7 +2418,7 @@ class basic_writer { void write(long value) { write_decimal(value); } - void write(long_long value) { + void write(long long value) { write_decimal(value); } @@ -3039,12 +3020,12 @@ class FormatInt { private: // Buffer should be large enough to hold all digits (digits10 + 1), // a sign and a null character. - enum {BUFFER_SIZE = std::numeric_limits::digits10 + 3}; + enum {BUFFER_SIZE = std::numeric_limits::digits10 + 3}; mutable char buffer_[BUFFER_SIZE]; char *str_; // Formats value in reverse and returns the number of digits. - char *format_decimal(ulong_long value) { + char *format_decimal(unsigned long long value) { char *buffer_end = buffer_ + BUFFER_SIZE - 1; while (value >= 100) { // Integer division is slow so do it for a group of two digits instead @@ -3065,8 +3046,8 @@ class FormatInt { return buffer_end; } - void FormatSigned(long_long value) { - ulong_long abs_value = static_cast(value); + void FormatSigned(long long value) { + unsigned long long abs_value = static_cast(value); bool negative = value < 0; if (negative) abs_value = 0 - abs_value; @@ -3078,10 +3059,10 @@ class FormatInt { public: explicit FormatInt(int value) { FormatSigned(value); } explicit FormatInt(long value) { FormatSigned(value); } - explicit FormatInt(long_long value) { FormatSigned(value); } + explicit FormatInt(long long value) { FormatSigned(value); } explicit FormatInt(unsigned value) : str_(format_decimal(value)) {} explicit FormatInt(unsigned long value) : str_(format_decimal(value)) {} - explicit FormatInt(ulong_long value) : str_(format_decimal(value)) {} + explicit FormatInt(unsigned long long value) : str_(format_decimal(value)) {} /** Returns the number of characters written to the output buffer. */ std::size_t size() const { @@ -3246,7 +3227,7 @@ struct is_integer { struct width_handler { template - typename std::enable_if::value, ulong_long>::type + typename std::enable_if::value, unsigned long long>::type operator()(T value) { if (is_negative(value)) FMT_THROW(format_error("negative width")); @@ -3254,7 +3235,7 @@ struct width_handler { } template - typename std::enable_if::value, ulong_long>::type + typename std::enable_if::value, unsigned long long>::type operator()(T value) { FMT_THROW(format_error("width is not integer")); return 0; @@ -3263,7 +3244,7 @@ struct width_handler { struct precision_handler { template - typename std::enable_if::value, ulong_long>::type + typename std::enable_if::value, unsigned long long>::type operator()(T value) { if (is_negative(value)) FMT_THROW(format_error("negative precision")); @@ -3271,7 +3252,7 @@ struct precision_handler { } template - typename std::enable_if::value, ulong_long>::type + typename std::enable_if::value, unsigned long long>::type operator()(T value) { FMT_THROW(format_error("precision is not integer")); return 0; @@ -3308,7 +3289,7 @@ class specs_handler_base { template inline void set_dynamic_spec(T &value, basic_arg arg) { - ulong_long big_value = visit(Handler(), arg); + unsigned long long big_value = visit(Handler(), arg); if (big_value > (std::numeric_limits::max)()) FMT_THROW(format_error("number is too big")); value = static_cast(big_value); diff --git a/fmt/posix.cc b/fmt/posix.cc index 5c37de6a..59e92539 100644 --- a/fmt/posix.cc +++ b/fmt/posix.cc @@ -124,7 +124,7 @@ void fmt::File::close() { throw system_error(errno, "cannot close file"); } -fmt::long_long fmt::File::size() const { +long long fmt::File::size() const { #ifdef _WIN32 // Use GetFileSize instead of GetFileSizeEx for the case when _WIN32_WINNT // is less than 0x0500 as is the case with some default MinGW builds. @@ -137,14 +137,14 @@ fmt::long_long fmt::File::size() const { if (error != NO_ERROR) throw windows_error(GetLastError(), "cannot get file size"); } - fmt::ulong_long long_size = size_upper; + unsigned long long long_size = size_upper; return (long_size << sizeof(DWORD) * CHAR_BIT) | size_lower; #else typedef struct stat Stat; Stat file_stat = Stat(); if (FMT_POSIX_CALL(fstat(fd_, &file_stat)) == -1) throw system_error(errno, "cannot get file attributes"); - FMT_STATIC_ASSERT(sizeof(fmt::long_long) >= sizeof(file_stat.st_size), + FMT_STATIC_ASSERT(sizeof(long long) >= sizeof(file_stat.st_size), "return type of File::size is not large enough"); return file_stat.st_size; #endif diff --git a/fmt/posix.h b/fmt/posix.h index c0cb2b62..90aba316 100644 --- a/fmt/posix.h +++ b/fmt/posix.h @@ -322,7 +322,7 @@ class File { // Returns the file size. The size has signed type for consistency with // stat::st_size. - long_long size() const; + long long size() const; // Attempts to read count bytes from the file into the specified buffer. std::size_t read(void *buffer, std::size_t count); diff --git a/fmt/printf.h b/fmt/printf.h index f02f8e41..272da034 100644 --- a/fmt/printf.h +++ b/fmt/printf.h @@ -119,7 +119,7 @@ class ArgConverter { // glibc's printf doesn't sign extend arguments of smaller types: // std::printf("%lld", -42); // prints "4294967254" // but we don't have to do the same because it's a UB. - arg_ = internal::make_arg(static_cast(value)); + arg_ = internal::make_arg(static_cast(value)); } else { arg_ = internal::make_arg( static_cast::type>(value)); @@ -486,7 +486,7 @@ void printf_context::format( break; case 'l': if (*it == 'l') - convert_arg(arg, *++it); + convert_arg(arg, *++it); else convert_arg(arg, *it); break; diff --git a/test/format-impl-test.cc b/test/format-impl-test.cc index 637f6225..11bdacc0 100644 --- a/test/format-impl-test.cc +++ b/test/format-impl-test.cc @@ -56,11 +56,10 @@ struct ValueExtractor { }; TEST(FormatTest, ArgConverter) { - fmt::long_long value = std::numeric_limits::max(); + long long value = std::numeric_limits::max(); auto arg = fmt::internal::make_arg(value); - visit(fmt::internal::ArgConverter< - fmt::long_long, fmt::context>(arg, 'd'), arg); - EXPECT_EQ(value, visit(ValueExtractor(), arg)); + visit(fmt::internal::ArgConverter(arg, 'd'), arg); + EXPECT_EQ(value, visit(ValueExtractor(), arg)); } TEST(FormatTest, FormatNegativeNaN) { diff --git a/test/posix-mock-test.cc b/test/posix-mock-test.cc index f960b60f..ece17e8d 100644 --- a/test/posix-mock-test.cc +++ b/test/posix-mock-test.cc @@ -277,7 +277,7 @@ TEST(FileTest, Size) { write_file("test", content); File f("test", File::RDONLY); EXPECT_GE(f.size(), 0); - EXPECT_EQ(content.size(), static_cast(f.size())); + EXPECT_EQ(content.size(), static_cast(f.size())); #ifdef _WIN32 fmt::memory_buffer message; fmt::internal::format_windows_error( diff --git a/test/printf-test.cc b/test/printf-test.cc index 312f714f..aeeac1f3 100644 --- a/test/printf-test.cc +++ b/test/printf-test.cc @@ -269,8 +269,8 @@ TEST(PrintfTest, DynamicPrecision) { "argument index out of range"); EXPECT_THROW_MSG(fmt::sprintf("%.*d", BIG_NUM, 42), format_error, "number is too big"); - if (sizeof(fmt::long_long) != sizeof(int)) { - fmt::long_long prec = static_cast(INT_MIN) - 1; + if (sizeof(long long) != sizeof(int)) { + long long prec = static_cast(INT_MIN) - 1; EXPECT_THROW_MSG(fmt::sprintf("%.*d", prec, 42), format_error, "number is too big"); } @@ -288,16 +288,16 @@ SPECIALIZE_MAKE_SIGNED(unsigned char, signed char); SPECIALIZE_MAKE_SIGNED(unsigned short, short); SPECIALIZE_MAKE_SIGNED(unsigned, int); SPECIALIZE_MAKE_SIGNED(unsigned long, long); -SPECIALIZE_MAKE_SIGNED(fmt::ulong_long, fmt::long_long); +SPECIALIZE_MAKE_SIGNED(unsigned long long, long long); // Test length format specifier ``length_spec``. template void TestLength(const char *length_spec, U value) { - fmt::long_long signed_value = 0; - fmt::ulong_long unsigned_value = 0; + long long signed_value = 0; + unsigned long long unsigned_value = 0; // Apply integer promotion to the argument. using std::numeric_limits; - fmt::ulong_long max = numeric_limits::max(); + unsigned long long max = numeric_limits::max(); using fmt::internal::const_check; if (const_check(max <= static_cast(numeric_limits::max()))) { signed_value = static_cast(value); @@ -308,7 +308,7 @@ void TestLength(const char *length_spec, U value) { } using fmt::internal::make_unsigned; if (sizeof(U) <= sizeof(int) && sizeof(int) < sizeof(T)) { - signed_value = static_cast(value); + signed_value = static_cast(value); unsigned_value = static_cast::type>(value); } else { signed_value = static_cast::type>(value); @@ -339,20 +339,20 @@ void TestLength(const char *length_spec) { TestLength(length_spec, -42); TestLength(length_spec, min); TestLength(length_spec, max); - TestLength(length_spec, fmt::long_long(min) - 1); - fmt::ulong_long long_long_max = std::numeric_limits::max(); - if (static_cast(max) < long_long_max) - TestLength(length_spec, fmt::long_long(max) + 1); + TestLength(length_spec, static_cast(min) - 1); + unsigned long long long_long_max = std::numeric_limits::max(); + if (static_cast(max) < long_long_max) + TestLength(length_spec, static_cast(max) + 1); TestLength(length_spec, std::numeric_limits::min()); TestLength(length_spec, std::numeric_limits::max()); TestLength(length_spec, std::numeric_limits::min()); TestLength(length_spec, std::numeric_limits::max()); TestLength(length_spec, std::numeric_limits::min()); TestLength(length_spec, std::numeric_limits::max()); - TestLength(length_spec, std::numeric_limits::min()); - TestLength(length_spec, std::numeric_limits::max()); - TestLength(length_spec, std::numeric_limits::min()); - TestLength(length_spec, std::numeric_limits::max()); + TestLength(length_spec, std::numeric_limits::min()); + TestLength(length_spec, std::numeric_limits::max()); + TestLength(length_spec, std::numeric_limits::min()); + TestLength(length_spec, std::numeric_limits::max()); } TEST(PrintfTest, Length) { @@ -363,8 +363,8 @@ TEST(PrintfTest, Length) { TestLength("h"); TestLength("l"); TestLength("l"); - TestLength("ll"); - TestLength("ll"); + TestLength("ll"); + TestLength("ll"); TestLength("j"); TestLength("z"); TestLength("t"); @@ -391,7 +391,7 @@ TEST(PrintfTest, Int) { TEST(PrintfTest, long_long) { // fmt::printf allows passing long long arguments to %d without length // specifiers. - fmt::long_long max = std::numeric_limits::max(); + long long max = std::numeric_limits::max(); EXPECT_PRINTF(fmt::format("{}", max), "%d", max); } diff --git a/test/util-test.cc b/test/util-test.cc index 6bae0439..b61d12f3 100644 --- a/test/util-test.cc +++ b/test/util-test.cc @@ -510,8 +510,8 @@ VISIT_TYPE(unsigned short, unsigned); VISIT_TYPE(long, int); VISIT_TYPE(unsigned long, unsigned); #else -VISIT_TYPE(long, fmt::long_long); -VISIT_TYPE(unsigned long, fmt::ulong_long); +VISIT_TYPE(long, long long); +VISIT_TYPE(unsigned long, unsigned long long); #endif VISIT_TYPE(float, double); @@ -533,7 +533,7 @@ class NumericArgTest : public testing::Test {}; typedef ::testing::Types< bool, signed char, unsigned char, signed, unsigned short, - int, unsigned, long, unsigned long, fmt::long_long, fmt::ulong_long, + int, unsigned, long, unsigned long, long long, unsigned long long, float, double, long double> Types; TYPED_TEST_CASE(NumericArgTest, Types); From a7320bdce9544280caad8ef28a87f2842f9889f6 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sat, 26 Aug 2017 09:19:03 -0700 Subject: [PATCH 127/340] Fix a warning --- fmt/format.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fmt/format.h b/fmt/format.h index 1be263e5..d4f8093b 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -3253,7 +3253,7 @@ struct precision_handler { template typename std::enable_if::value, unsigned long long>::type - operator()(T value) { + operator()(T) { FMT_THROW(format_error("precision is not integer")); return 0; } From 388061674af6abecef68ea0d7dbd90d9004960a8 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sat, 26 Aug 2017 09:23:00 -0700 Subject: [PATCH 128/340] Remove FMT_HAS_GXX_CXX11 --- fmt/format.h | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/fmt/format.h b/fmt/format.h index d4f8093b..06ccd1fc 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -76,10 +76,6 @@ // Disable the warning about implicit conversions that may change the sign of // an integer; silencing it otherwise would require many explicit casts. # pragma GCC diagnostic ignored "-Wsign-conversion" - -# endif -# if __cplusplus >= 201103L || defined __GXX_EXPERIMENTAL_CXX0X__ -# define FMT_HAS_GXX_CXX11 1 # endif #endif @@ -140,7 +136,7 @@ # else # define FMT_USE_RVALUE_REFERENCES \ (FMT_HAS_FEATURE(cxx_rvalue_references) || \ - (FMT_GCC_VERSION >= 403 && FMT_HAS_GXX_CXX11) || FMT_MSC_VER >= 1600) + FMT_GCC_VERSION >= 403 || FMT_MSC_VER >= 1600) # endif #endif @@ -175,8 +171,7 @@ #ifndef FMT_NOEXCEPT # if FMT_EXCEPTIONS # if FMT_USE_NOEXCEPT || FMT_HAS_FEATURE(cxx_noexcept) || \ - (FMT_GCC_VERSION >= 408 && FMT_HAS_GXX_CXX11) || \ - FMT_MSC_VER >= 1900 + FMT_GCC_VERSION >= 408 || FMT_MSC_VER >= 1900 # define FMT_NOEXCEPT noexcept # else # define FMT_NOEXCEPT throw() @@ -193,7 +188,7 @@ #endif #if FMT_USE_DELETED_FUNCTIONS || FMT_HAS_FEATURE(cxx_deleted_functions) || \ - (FMT_GCC_VERSION >= 404 && FMT_HAS_GXX_CXX11) || FMT_MSC_VER >= 1800 + FMT_GCC_VERSION >= 404 || FMT_MSC_VER >= 1800 # define FMT_DELETED_OR_UNDEFINED = delete # define FMT_DISALLOW_COPY_AND_ASSIGN(TypeName) \ TypeName(const TypeName&) = delete; \ @@ -213,7 +208,7 @@ # define FMT_USE_USER_DEFINED_LITERALS \ FMT_USE_RVALUE_REFERENCES && \ (FMT_HAS_FEATURE(cxx_user_literals) || \ - (FMT_GCC_VERSION >= 407 && FMT_HAS_GXX_CXX11) || FMT_MSC_VER >= 1900) && \ + FMT_GCC_VERSION >= 407 || FMT_MSC_VER >= 1900) && \ (!defined(FMT_ICC_VERSION) || FMT_ICC_VERSION >= 1500) #endif @@ -1567,7 +1562,7 @@ basic_arg make_arg(const T &value) { #endif #if FMT_USE_STATIC_ASSERT || FMT_HAS_FEATURE(cxx_static_assert) || \ - (FMT_GCC_VERSION >= 403 && FMT_HAS_GXX_CXX11) || _MSC_VER >= 1600 + FMT_GCC_VERSION >= 403 || _MSC_VER >= 1600 # define FMT_STATIC_ASSERT(cond, message) static_assert(cond, message) #else # define FMT_CONCAT_(a, b) FMT_CONCAT(a, b) From 64681739fd5972f259080b098d9bffef33e4b0b5 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sat, 26 Aug 2017 09:32:37 -0700 Subject: [PATCH 129/340] Fix a warning --- test/util-test.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/util-test.cc b/test/util-test.cc index b61d12f3..3adfe001 100644 --- a/test/util-test.cc +++ b/test/util-test.cc @@ -488,7 +488,7 @@ struct MockVisitor { Result operator()(T value) { return visit(value); } template - Result operator()(U value) { + Result operator()(U) { unexpected(); return Result(); } From 27ad6cee82008b8367ff7d8d461ab81853489d71 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sat, 26 Aug 2017 10:41:58 -0700 Subject: [PATCH 130/340] Use standard enable_if --- fmt/format.h | 21 ++++++++------------- test/util-test.cc | 19 ------------------- 2 files changed, 8 insertions(+), 32 deletions(-) diff --git a/fmt/format.h b/fmt/format.h index 06ccd1fc..e190d2e3 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -819,12 +819,6 @@ class char_traits : public basic_char_traits { const wchar_t *format, unsigned width, int precision, T value); }; -template -struct enable_if {}; - -template -struct enable_if { typedef T type; }; - template struct conditional { typedef T type; }; @@ -937,12 +931,12 @@ const Char *pointer_from(null_terminating_iterator it) { // Returns true if value is negative, false otherwise. // Same as (value < 0) but doesn't produce warnings if T is an unsigned type. template -inline typename enable_if::is_signed, bool>::type +inline typename std::enable_if::is_signed, bool>::type is_negative(T value) { return value < 0; } template -inline typename enable_if::is_signed, bool>::type +inline typename std::enable_if::is_signed, bool>::type is_negative(T) { return false; } @@ -1425,7 +1419,7 @@ class value { template value(const T &value, - typename enable_if::value, int>::type = 0) { + typename std::enable_if::value, int>::type = 0) { static_assert(internal::type() == internal::CUSTOM, "invalid type"); this->custom.value = &value; this->custom.format = &format_custom_arg; @@ -1433,7 +1427,7 @@ class value { template value(const T &value, - typename enable_if::value, int>::type = 0) { + typename std::enable_if::value, int>::type = 0) { static_assert(internal::type() == internal::INT, "invalid type"); this->int_value = value; } @@ -1931,7 +1925,7 @@ class arg_formatter_base { } template - typename enable_if< + typename std::enable_if< std::is_same::value && std::is_same::value>::type write_str(basic_string_view value) { @@ -1939,7 +1933,7 @@ class arg_formatter_base { } template - typename enable_if< + typename std::enable_if< !std::is_same::value || !std::is_same::value>::type write_str(basic_string_view ) { @@ -3564,7 +3558,8 @@ struct format_enum : std::integral_constant::value> {}; // Formatter of objects of type T. template -struct formatter::value>::type> { +struct formatter< + T, Char, typename std::enable_if::value>::type> { // Parses format specifiers stopping either at the end of the range or at the // terminating '}'. diff --git a/test/util-test.cc b/test/util-test.cc index 3adfe001..b63b9047 100644 --- a/test/util-test.cc +++ b/test/util-test.cc @@ -840,25 +840,6 @@ TEST(UtilTest, IsEnumConvertibleToInt) { } #endif -template -bool check_enable_if( - typename fmt::internal::enable_if::type *) { - return true; -} - -template -bool check_enable_if( - typename fmt::internal::enable_if::type *) { - return false; -} - -TEST(UtilTest, EnableIf) { - int i = 0; - EXPECT_TRUE(check_enable_if(&i)); - char c = 0; - EXPECT_FALSE(check_enable_if(&c)); -} - TEST(UtilTest, Conditional) { int i = 0; fmt::internal::conditional::type *pi = &i; From d4c504ae1c58d0c918c5c628119a63686000d31a Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sun, 27 Aug 2017 06:38:23 -0700 Subject: [PATCH 131/340] Fix a warning --- fmt/format.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fmt/format.h b/fmt/format.h index e190d2e3..58d297b6 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -3225,7 +3225,7 @@ struct width_handler { template typename std::enable_if::value, unsigned long long>::type - operator()(T value) { + operator()(T) { FMT_THROW(format_error("width is not integer")); return 0; } From be7d72ba0d4ac1334dcfd8877345d8da25fdd234 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sun, 27 Aug 2017 06:45:59 -0700 Subject: [PATCH 132/340] Fix expansion-to-defined warning --- fmt/format.h | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/fmt/format.h b/fmt/format.h index 58d297b6..c364cbaa 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -205,11 +205,14 @@ // makes the fmt::literals implementation easier. However, an explicit check // for variadic templates is added here just in case. // For Intel's compiler both it and the system gcc/msc must support UDLs. -# define FMT_USE_USER_DEFINED_LITERALS \ - FMT_USE_RVALUE_REFERENCES && \ +# if FMT_USE_RVALUE_REFERENCES && \ (FMT_HAS_FEATURE(cxx_user_literals) || \ - FMT_GCC_VERSION >= 407 || FMT_MSC_VER >= 1900) && \ + FMT_GCC_VERSION >= 407 || FMT_MSC_VER >= 1900) && \ (!defined(FMT_ICC_VERSION) || FMT_ICC_VERSION >= 1500) +# define FMT_USE_USER_DEFINED_LITERALS 1 +# else +# define FMT_USE_USER_DEFINED_LITERALS 0 +# endif #endif #ifndef FMT_ASSERT From 77c892c88e210c05339f8100a5c6be191965d4e5 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sun, 27 Aug 2017 08:16:46 -0700 Subject: [PATCH 133/340] Fix more warnings --- fmt/printf.h | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/fmt/printf.h b/fmt/printf.h index 272da034..f068b959 100644 --- a/fmt/printf.h +++ b/fmt/printf.h @@ -67,7 +67,7 @@ class IsZeroInt { template typename std::enable_if::value, bool>::type - operator()(T value) { return false; } + operator()(T) { return false; } }; template @@ -103,7 +103,6 @@ class ArgConverter { bool is_signed = type_ == 'd' || type_ == 'i'; typedef typename internal::conditional< is_same::value, U, T>::type TargetType; - typedef basic_context context; if (sizeof(TargetType) <= sizeof(int)) { // Extra casts are used to silence warnings. if (is_signed) { @@ -128,8 +127,7 @@ class ArgConverter { } template - typename std::enable_if::value>::type - operator()(U value) { + typename std::enable_if::value>::type operator()(U) { // No coversion needed for non-integral types. } }; @@ -197,7 +195,7 @@ class PrintfWidthHandler { template typename std::enable_if::value, unsigned>::type - operator()(T value) { + operator()(T) { FMT_THROW(format_error("width is not integer")); return 0; } From 20168147dd461c05a51d007c1f7747c30144edca Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sun, 27 Aug 2017 08:41:28 -0700 Subject: [PATCH 134/340] Add ptr, a helper function for pointer formatting --- fmt/format.h | 6 ++++++ test/format-test.cc | 4 ++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/fmt/format.h b/fmt/format.h index c364cbaa..3cc6d0c0 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -3675,6 +3675,12 @@ void vformat_to(basic_buffer &buffer, basic_string_view format_str, } buffer.append(pointer_from(start), pointer_from(it)); } + +// Casts ``p`` to ``const void*`` for pointer formatting. +// Example: +// auto s = format("{}", ptr(p)); +template +inline const void *ptr(const T *p) { return p; } } // namespace fmt #if FMT_USE_USER_DEFINED_LITERALS diff --git a/test/format-test.cc b/test/format-test.cc index 88d30b72..08dafb3b 100644 --- a/test/format-test.cc +++ b/test/format-test.cc @@ -1217,6 +1217,7 @@ TEST(FormatterTest, FormatPointer) { EXPECT_EQ("0x1234", format("{0:p}", reinterpret_cast(0x1234))); EXPECT_EQ("0x" + std::string(sizeof(void*) * CHAR_BIT / 4, 'f'), format("{0}", reinterpret_cast(~uintptr_t()))); + EXPECT_EQ("0x1234", format("{}", fmt::ptr(reinterpret_cast(0x1234)))); } TEST(FormatterTest, FormatString) { @@ -1504,8 +1505,7 @@ class MockArgFormatter : public fmt::internal::arg_formatter_base { public: typedef fmt::internal::arg_formatter_base Base; - MockArgFormatter(fmt::buffer &b, fmt::context &ctx, - fmt::format_specs &s) + MockArgFormatter(fmt::buffer &b, fmt::context &, fmt::format_specs &s) : fmt::internal::arg_formatter_base(b, s) { EXPECT_CALL(*this, call(42)); } From 47c84d7974c0f4eb3ff850b731e0360fca20c655 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sun, 27 Aug 2017 09:08:44 -0700 Subject: [PATCH 135/340] Move part of write API (spec factories) to a separate header --- fmt/CMakeLists.txt | 2 +- fmt/format.h | 35 -------------------------- fmt/write.h | 61 +++++++++++++++++++++++++++++++++++++++++++++ test/format-test.cc | 1 + 4 files changed, 63 insertions(+), 36 deletions(-) create mode 100644 fmt/write.h diff --git a/fmt/CMakeLists.txt b/fmt/CMakeLists.txt index c6502a3d..c2c7f0fe 100644 --- a/fmt/CMakeLists.txt +++ b/fmt/CMakeLists.txt @@ -1,7 +1,7 @@ # Define the fmt library, its includes and the needed defines. # format.cc is added to FMT_HEADERS for the header-only configuration. set(FMT_HEADERS format.h format.cc ostream.h ostream.cc printf.h printf.cc - string.h time.h) + string.h time.h write.h) if (HAVE_OPEN) set(FMT_HEADERS ${FMT_HEADERS} posix.h) set(FMT_SOURCES ${FMT_SOURCES} posix.cc) diff --git a/fmt/format.h b/fmt/format.h index 3cc6d0c0..d0c89812 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -1747,30 +1747,6 @@ class fill_spec : public format_spec { typedef format_spec width_spec; typedef format_spec type_spec; -class fill_spec_factory { - public: - constexpr fill_spec_factory() {} - - template - fill_spec operator=(Char value) const { - return fill_spec(value); - } -}; - -template -class format_spec_factory { - public: - constexpr format_spec_factory() {} - - FormatSpec operator=(typename FormatSpec::value_type value) const { - return FormatSpec(value); - } -}; - -constexpr fill_spec_factory fill; -constexpr format_spec_factory width; -constexpr format_spec_factory type; - // An empty format specifier. struct empty_spec {}; @@ -2225,17 +2201,6 @@ class system_error : public std::runtime_error { FMT_API void format_system_error(fmt::buffer &out, int error_code, fmt::string_view message) FMT_NOEXCEPT; -namespace internal { -// Named format specifier. -template -class named_format_spec { - public: - constexpr named_format_spec() {} -}; - -constexpr named_format_spec width; -} - /** \rst This template provides operations for formatting and writing data into a diff --git a/fmt/write.h b/fmt/write.h new file mode 100644 index 00000000..c6aec5a7 --- /dev/null +++ b/fmt/write.h @@ -0,0 +1,61 @@ +/* + Formatting library for C++ + + Copyright (c) 2012 - 2016, Victor Zverovich + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef FMT_WRITE_H_ +#define FMT_WRITE_H_ + +#include "fmt/format.h" + +namespace fmt { + +class fill_spec_factory { + public: + constexpr fill_spec_factory() {} + + template + fill_spec operator=(Char value) const { + return fill_spec(value); + } +}; + +template +class format_spec_factory { + public: + constexpr format_spec_factory() {} + + FormatSpec operator=(typename FormatSpec::value_type value) const { + return FormatSpec(value); + } +}; + +constexpr fill_spec_factory fill; +constexpr format_spec_factory width; +constexpr format_spec_factory type; + +} // namespace fmt + +#endif // FMT_WRITE_H_ diff --git a/test/format-test.cc b/test/format-test.cc index 08dafb3b..8ab7e46b 100644 --- a/test/format-test.cc +++ b/test/format-test.cc @@ -43,6 +43,7 @@ #define None 0 #include "fmt/format.h" +#include "fmt/write.h" #include "util.h" #include "mock-allocator.h" From f194a418f900cdad18e8bfde8027d17f6a339e00 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sun, 27 Aug 2017 09:16:50 -0700 Subject: [PATCH 136/340] Replace fmt::is_same with std::is_same --- fmt/printf.h | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/fmt/printf.h b/fmt/printf.h index f068b959..1c58df2b 100644 --- a/fmt/printf.h +++ b/fmt/printf.h @@ -70,16 +70,6 @@ class IsZeroInt { operator()(T) { return false; } }; -template -struct is_same { - enum { value = 0 }; -}; - -template -struct is_same { - enum { value = 1 }; -}; - template class ArgConverter { private: @@ -102,7 +92,7 @@ class ArgConverter { operator()(U value) { bool is_signed = type_ == 'd' || type_ == 'i'; typedef typename internal::conditional< - is_same::value, U, T>::type TargetType; + std::is_same::value, U, T>::type TargetType; if (sizeof(TargetType) <= sizeof(int)) { // Extra casts are used to silence warnings. if (is_signed) { From b0867f3fa04c3b5d750f31276f750ed6bb23241a Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sun, 27 Aug 2017 09:56:45 -0700 Subject: [PATCH 137/340] AlignSpec -> align_spec and fix a warning --- fmt/format.h | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/fmt/format.h b/fmt/format.h index d0c89812..bcecc337 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -1751,14 +1751,14 @@ typedef format_spec type_spec; struct empty_spec {}; // An alignment specifier. -struct AlignSpec : empty_spec { +struct align_spec : empty_spec { unsigned width_; // Fill is always wchar_t and cast to char if necessary to avoid having // two specialization of AlignSpec and its subclasses. wchar_t fill_; alignment align_; - AlignSpec(unsigned width, wchar_t fill, alignment align = ALIGN_DEFAULT) + align_spec(unsigned width, wchar_t fill, alignment align = ALIGN_DEFAULT) : width_(width), fill_(fill), align_(align) {} unsigned width() const { return width_; } @@ -1770,7 +1770,7 @@ struct AlignSpec : empty_spec { // Format specifiers. template -class basic_format_specs : public AlignSpec { +class basic_format_specs : public align_spec { private: template typename std::enable_if::value || @@ -1799,11 +1799,11 @@ class basic_format_specs : public AlignSpec { char type_; basic_format_specs(unsigned width = 0, char type = 0, wchar_t fill = ' ') - : AlignSpec(width, fill), flags_(0), precision_(-1), type_(type) {} + : align_spec(width, fill), flags_(0), precision_(-1), type_(type) {} template explicit basic_format_specs(FormatSpecs... specs) - : AlignSpec(0, ' '), flags_(0), precision_(-1), type_(0){ + : align_spec(0, ' '), flags_(0), precision_(-1), type_(0){ set(specs...); } @@ -2297,7 +2297,7 @@ class basic_writer { // Writes a formatted string. template - CharPtr write_str(const StrChar *s, std::size_t size, const AlignSpec &spec); + CharPtr write_str(const StrChar *s, std::size_t size, const align_spec &spec); template void write_str(basic_string_view str, const format_specs &spec); @@ -2444,7 +2444,7 @@ class basic_writer { template template typename basic_writer::CharPtr basic_writer::write_str( - const StrChar *s, std::size_t size, const AlignSpec &spec) { + const StrChar *s, std::size_t size, const align_spec &spec) { CharPtr out = CharPtr(); if (spec.width() > size) { out = grow_buffer(spec.width()); @@ -2515,7 +2515,7 @@ typename basic_writer::CharPtr basic_writer::prepare_int_buffer( --prefix_size; unsigned number_size = prefix_size + internal::to_unsigned(spec.precision()); - AlignSpec subspec(number_size, '0', ALIGN_NUMERIC); + align_spec subspec(number_size, '0', ALIGN_NUMERIC); if (number_size >= width) return prepare_int_buffer(num_digits, subspec, prefix, prefix_size); buffer_.reserve(width); @@ -3605,21 +3605,20 @@ void vformat_to(basic_buffer &buffer, basic_string_view format_str, auto it = start; using internal::pointer_from; while (*it) { - Char c = *it++; - if (c != '{' && c != '}') continue; - if (*it == c) { + Char ch = *it++; + if (ch != '{' && ch != '}') continue; + if (*it == ch) { buffer.append(pointer_from(start), pointer_from(it)); start = ++it; continue; } - if (c == '}') + if (ch == '}') FMT_THROW(format_error("unmatched '}' in format string")); buffer.append(pointer_from(start), pointer_from(it) - 1); basic_arg arg; struct id_handler { - explicit id_handler(Context &ctx, basic_arg &arg) - : context(ctx), arg(arg) {} + id_handler(Context &c, basic_arg &a): context(c), arg(a) {} void operator()() { arg = context.next_arg(); } void operator()(unsigned id) { arg = context.get_arg(id); } From 80505995d0c8a2fd5c5ad99a0aba8d6cebef81b3 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sun, 3 Sep 2017 08:28:30 -0700 Subject: [PATCH 138/340] Allow delayed type checking --- fmt/format.h | 263 ++++++++++++++++++++++++++++++++------------ test/format-test.cc | 39 +++++++ 2 files changed, 231 insertions(+), 71 deletions(-) diff --git a/fmt/format.h b/fmt/format.h index bcecc337..bd90e187 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -1796,7 +1796,7 @@ class basic_format_specs : public align_spec { public: unsigned flags_; int precision_; - char type_; + Char type_; basic_format_specs(unsigned width = 0, char type = 0, wchar_t fill = ' ') : align_spec(width, fill), flags_(0), precision_(-1), type_(type) {} @@ -1809,7 +1809,7 @@ class basic_format_specs : public align_spec { bool flag(unsigned f) const { return (flags_ & f) != 0; } int precision() const { return precision_; } - char type() const { return type_; } + Char type() const { return type_; } }; typedef basic_format_specs format_specs; @@ -3135,24 +3135,6 @@ unsigned parse_nonnegative_int(Iterator &it) { return value; } -inline void require_numeric_argument(Type type, char spec) { - if (!is_numeric(type)) { - FMT_THROW(fmt::format_error( - fmt::format("format specifier '{}' requires numeric argument", spec))); - } -} - -template -void check_sign(Iterator &it, Type type) { - char sign = static_cast(*it); - require_numeric_argument(type, sign); - if (is_integral(type) && type != INT && type != LONG_LONG && type != CHAR) { - FMT_THROW(format_error(fmt::format( - "format specifier '{}' requires signed argument", sign))); - } - ++it; -} - template class custom_formatter { private: @@ -3216,11 +3198,11 @@ struct precision_handler { } }; +// A format specifier handler that sets fields in basic_format_specs. template -class specs_handler_base { +class specs_setter { public: - explicit specs_handler_base(basic_format_specs &specs) - : specs_(specs) {} + explicit specs_setter(basic_format_specs &specs): specs_(specs) {} void on_align(alignment align) { specs_.align_ = align; } void on_fill(Char fill) { specs_.fill_ = fill; } @@ -3236,14 +3218,89 @@ class specs_handler_base { void on_width(unsigned width) { specs_.width_ = width; } void on_precision(unsigned precision) { specs_.precision_ = precision; } - void on_type(char type) { specs_.type_ = type; } + void end_precision() {} + + void on_type(Char type) { specs_.type_ = type; } protected: - ~specs_handler_base() {} + ~specs_setter() {} basic_format_specs &specs_; }; +// A format specifier handler that checks if specifiers are consistent with the +// argument type. +template +class specs_checker : public Handler { + public: + explicit specs_checker(const Handler& handler, Type arg_type) + : Handler(handler), arg_type_(arg_type) {} + + void on_align(alignment align) { + if (align == ALIGN_NUMERIC) + require_numeric_argument('='); + Handler::on_align(align); + } + + void on_plus() { + check_sign('+'); + Handler::on_plus(); + } + + void on_minus() { + check_sign('-'); + Handler::on_minus(); + } + + void on_space() { + check_sign(' '); + Handler::on_space(); + } + + void on_hash() { + require_numeric_argument('#'); + Handler::on_hash(); + } + + void on_zero() { + require_numeric_argument('0'); + Handler::on_zero(); + } + + void end_precision() { + if (is_integral(arg_type_) || arg_type_ == POINTER) { + report_error("precision not allowed in {} format specifier", + arg_type_ == POINTER ? "pointer" : "integer"); + } + } + + private: + template + static void report_error(string_view format_str, const Args &... args) { + FMT_THROW(format_error(format(format_str, args...))); + } + + template + void require_numeric_argument(Char spec) const { + if (!is_numeric(arg_type_)) { + report_error("format specifier '{}' requires numeric argument", + static_cast(spec)); + } + } + + template + void check_sign(Char sign) const { + require_numeric_argument(sign); + if (is_integral(arg_type_) && arg_type_ != INT && arg_type_ != LONG_LONG && + arg_type_ != CHAR) { + report_error("format specifier '{}' requires signed argument", + static_cast(sign)); + } + } + + Type arg_type_; +}; + template inline void set_dynamic_spec(T &value, basic_arg arg) { unsigned long long big_value = visit(Handler(), arg); @@ -3252,13 +3309,16 @@ inline void set_dynamic_spec(T &value, basic_arg arg) { value = static_cast(big_value); } +struct auto_id {}; + +// The standard format specifier handler with checking. template -class specs_handler : public specs_handler_base { +class specs_handler: public specs_setter { public: typedef typename Context::char_type char_type; specs_handler(basic_format_specs &specs, Context &ctx) - : specs_handler_base(specs), context_(ctx) {} + : specs_setter(specs), context_(ctx) {} template void on_dynamic_width(Id arg_id) { @@ -3273,7 +3333,7 @@ class specs_handler : public specs_handler_base { } private: - basic_arg get_arg(monostate) { + basic_arg get_arg(auto_id) { return context_.next_arg(); } @@ -3301,6 +3361,9 @@ struct arg_ref { }; }; +// Format specifiers with width and precision resolved at formatting rather +// than parsing time to allow re-using the same parsed specifiers with +// differents sets of arguments (precompilation of format strings). template struct dynamic_format_specs : basic_format_specs { arg_ref width_ref; @@ -3308,10 +3371,10 @@ struct dynamic_format_specs : basic_format_specs { }; template -class dynamic_specs_handler : public specs_handler_base { +class dynamic_specs_handler: public specs_setter { public: - explicit dynamic_specs_handler(dynamic_format_specs &specs) - : specs_handler_base(specs), specs_(specs) {} + dynamic_specs_handler(dynamic_format_specs &specs) + : specs_setter(specs), specs_(specs) {} template void on_dynamic_width(Id arg_id) { @@ -3329,7 +3392,7 @@ class dynamic_specs_handler : public specs_handler_base { ref = arg_ref(arg_id); } - void set(arg_ref &ref, monostate) { + void set(arg_ref &ref, auto_id) { ref.kind = arg_ref::NONE; } @@ -3367,7 +3430,7 @@ Iterator parse_arg_id(Iterator it, Handler handler) { // characters, possibly emulated via null_terminating_iterator, representing // format specifiers. template -Iterator parse_format_specs(Iterator it, Type arg_type, Handler &handler) { +Iterator parse_format_specs(Iterator it, Handler &handler) { typedef typename Iterator::value_type char_type; // Parse fill and alignment. if (char_type c = *it) { @@ -3397,8 +3460,6 @@ Iterator parse_format_specs(Iterator it, Type arg_type, Handler &handler) { it += 2; handler.on_fill(c); } else ++it; - if (align == ALIGN_NUMERIC) - require_numeric_argument(arg_type, '='); break; } } while (--p >= it); @@ -3407,28 +3468,26 @@ Iterator parse_format_specs(Iterator it, Type arg_type, Handler &handler) { // Parse sign. switch (*it) { case '+': - check_sign(it, arg_type); handler.on_plus(); + ++it; break; case '-': - check_sign(it, arg_type); handler.on_minus(); + ++it; break; case ' ': - check_sign(it, arg_type); handler.on_space(); + ++it; break; } if (*it == '#') { - require_numeric_argument(arg_type, '#'); handler.on_hash(); ++it; } // Parse zero flag. if (*it == '0') { - require_numeric_argument(arg_type, '0'); handler.on_zero(); ++it; } @@ -3440,7 +3499,7 @@ Iterator parse_format_specs(Iterator it, Type arg_type, Handler &handler) { struct width_handler { explicit width_handler(Handler &h) : handler(h) {} - void operator()() { handler.on_dynamic_width(monostate()); } + void operator()() { handler.on_dynamic_width(auto_id()); } void operator()(unsigned id) { handler.on_dynamic_width(id); } void operator()(basic_string_view id) { handler.on_dynamic_width(id); @@ -3462,7 +3521,7 @@ Iterator parse_format_specs(Iterator it, Type arg_type, Handler &handler) { struct precision_handler { explicit precision_handler(Handler &h) : handler(h) {} - void operator()() { handler.on_dynamic_precision(monostate()); } + void operator()() { handler.on_dynamic_precision(auto_id()); } void operator()(unsigned id) { handler.on_dynamic_precision(id); } void operator()(basic_string_view id) { handler.on_dynamic_precision(id); @@ -3476,16 +3535,12 @@ Iterator parse_format_specs(Iterator it, Type arg_type, Handler &handler) { } else { FMT_THROW(format_error("missing precision specifier")); } - if (is_integral(arg_type) || arg_type == POINTER) { - FMT_THROW(format_error( - fmt::format("precision not allowed in {} format specifier", - arg_type == POINTER ? "pointer" : "integer"))); - } + handler.end_precision(); } // Parse type. if (*it != '}' && *it) - handler.on_type(static_cast(*it++)); + handler.on_type(*it++); return it; } @@ -3501,8 +3556,9 @@ const Char *do_format_arg(basic_buffer &buffer, format.remove_prefix(1); if (visit(custom_formatter(buffer, format, ctx), arg)) return begin(format); - specs_handler handler(specs, ctx); - it = parse_format_specs(it + 1, arg.type(), handler); + specs_checker> + handler(specs_handler(specs, ctx), arg.type()); + it = parse_format_specs(it + 1, handler); } if (*it != '}') @@ -3522,6 +3578,23 @@ struct format_type : std::integral_constant() != CUSTOM> {}; // Specifies whether to format enums. template struct format_enum : std::integral_constant::value> {}; + +template +static void handle_dynamic_spec( + Spec &value, arg_ref ref, basic_context &ctx) { + switch (ref.kind) { + case arg_ref::NONE: + // Do nothing. + break; + case arg_ref::INDEX: + internal::set_dynamic_spec(value, ctx.get_arg(ref.index)); + break; + case arg_ref::NAME: + internal::set_dynamic_spec(value, ctx.get_arg(ref.name)); + break; + // TODO: handle automatic numbering + } +} } // namespace internal // Formatter of objects of type T. @@ -3534,15 +3607,17 @@ struct formatter< template auto parse(Range format) -> decltype(begin(format)) { auto it = internal::null_terminating_iterator(format); - internal::dynamic_specs_handler handler(specs_); - it = parse_format_specs(it, internal::gettype(), handler); + using handler_type = internal::dynamic_specs_handler; + internal::specs_checker + handler(handler_type(specs_), internal::gettype()); + it = parse_format_specs(it, handler); return pointer_from(it); } void format(basic_buffer &buf, const T &val, basic_context &ctx) { - handle_dynamic_spec( + internal::handle_dynamic_spec( specs_.width_, specs_.width_ref, ctx); - handle_dynamic_spec( + internal::handle_dynamic_spec( specs_.precision_, specs_.precision_ref, ctx); visit(arg_formatter(buf, ctx, specs_), internal::make_arg>(val)); @@ -3551,23 +3626,6 @@ struct formatter< private: using arg_ref = internal::arg_ref; - template - static void handle_dynamic_spec( - Spec &value, arg_ref ref, basic_context &ctx) { - switch (ref.kind) { - case arg_ref::NONE: - // Do nothing. - break; - case arg_ref::INDEX: - internal::set_dynamic_spec(value, ctx.get_arg(ref.index)); - break; - case arg_ref::NAME: - internal::set_dynamic_spec(value, ctx.get_arg(ref.name)); - break; - // TODO: handle automatic numbering - } - } - internal::dynamic_format_specs specs_; }; @@ -3581,6 +3639,69 @@ struct formatter; +// template <> +// struct formatter: dynamic_formatter<> { +// void format(buffer &buf, const variant &v, context &ctx) { +// visit([&](const auto &val) { format(buf, val, ctx); }, v); +// } +// }; +template +struct dynamic_formatter { + template + auto parse(Range format) -> decltype(begin(format)) { + auto it = internal::null_terminating_iterator(format); + // Checks are deferred to formatting time when the argument type is known. + internal::dynamic_specs_handler handler(specs_); + it = parse_format_specs(it, handler); + return pointer_from(it); + } + + template + void format(basic_buffer &buf, const T &val, basic_context &ctx) { + handle_specs(ctx); + struct null_handler { + void on_align(alignment) {} + void on_plus() {} + void on_minus() {} + void on_space() {} + void on_hash() {} + }; + internal::specs_checker + checker(null_handler(), internal::gettype()); + checker.on_align(specs_.align()); + if (specs_.flags_ == 0) { + // Do nothing. + } else if (specs_.flag(SIGN_FLAG)) { + if (specs_.flag(PLUS_FLAG)) + checker.on_plus(); + else + checker.on_space(); + } else if (specs_.flag(MINUS_FLAG)) { + checker.on_minus(); + } else if (specs_.flag(HASH_FLAG)) { + checker.on_hash(); + } + if (specs_.precision_ != -1) + checker.end_precision(); + visit(arg_formatter(buf, ctx, specs_), + internal::make_arg>(val)); + } + + private: + void handle_specs(basic_context &ctx) { + internal::handle_dynamic_spec( + specs_.width_, specs_.width_ref, ctx); + internal::handle_dynamic_spec( + specs_.precision_, specs_.precision_ref, ctx); + } + + internal::dynamic_format_specs specs_; +}; + template inline typename basic_context::format_arg basic_context::get_arg(basic_string_view name) { diff --git a/test/format-test.cc b/test/format-test.cc index 8ab7e46b..5a14950c 100644 --- a/test/format-test.cc +++ b/test/format-test.cc @@ -1536,3 +1536,42 @@ TEST(FormatTest, CustomArgFormatter) { TEST(FormatTest, NonNullTerminatedFormatString) { EXPECT_EQ("42", format(string_view("{}foo", 2), 42)); } + +struct variant { + enum {INT, STRING} type; + explicit variant(int) : type(INT) {} + explicit variant(const char *) : type(STRING) {} +}; + +namespace fmt { +template <> +struct formatter : dynamic_formatter<> { + void format(buffer& buf, variant value, context& ctx) { + if (value.type == variant::INT) + dynamic_formatter::format(buf, 42, ctx); + else + dynamic_formatter::format(buf, "foo", ctx); + } +}; +} + +TEST(FormatTest, DynamicFormatter) { + auto num = variant(42); + auto str = variant("foo"); + EXPECT_EQ("42", format("{:d}", num)); + EXPECT_EQ("foo", format("{:s}", str)); + EXPECT_THROW_MSG(format("{:=}", str), + format_error, "format specifier '=' requires numeric argument"); + EXPECT_THROW_MSG(format("{:+}", str), + format_error, "format specifier '+' requires numeric argument"); + EXPECT_THROW_MSG(format("{:-}", str), + format_error, "format specifier '-' requires numeric argument"); + EXPECT_THROW_MSG(format("{: }", str), + format_error, "format specifier ' ' requires numeric argument"); + EXPECT_THROW_MSG(format("{:#}", str), + format_error, "format specifier '#' requires numeric argument"); + EXPECT_THROW_MSG(format("{:0}", str), + format_error, "format specifier '=' requires numeric argument"); + EXPECT_THROW_MSG(format("{:.2}", num), + format_error, "precision not allowed in integer format specifier"); +} From 8a2bc0ab1b337dfc6988891145a9c66c67b3a370 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Mon, 4 Sep 2017 11:10:08 -0700 Subject: [PATCH 139/340] Add nullptr support --- fmt/format.h | 2 ++ test/format-test.cc | 1 + 2 files changed, 3 insertions(+) diff --git a/fmt/format.h b/fmt/format.h index bd90e187..0be4cd70 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -1267,6 +1267,7 @@ template <> constexpr Type gettype() { return TSTRING; } template <> constexpr Type gettype() { return TSTRING; } template <> constexpr Type gettype() { return POINTER; } template <> constexpr Type gettype() { return POINTER; } +template <> constexpr Type gettype() { return POINTER; } template constexpr Type type() { return gettype::type>(); } @@ -1419,6 +1420,7 @@ class value { FMT_MAKE_VALUE(void *, pointer, POINTER) FMT_MAKE_VALUE(const void *, pointer, POINTER) + value(std::nullptr_t) { pointer = nullptr; } template value(const T &value, diff --git a/test/format-test.cc b/test/format-test.cc index 5a14950c..85dac3dc 100644 --- a/test/format-test.cc +++ b/test/format-test.cc @@ -1219,6 +1219,7 @@ TEST(FormatterTest, FormatPointer) { EXPECT_EQ("0x" + std::string(sizeof(void*) * CHAR_BIT / 4, 'f'), format("{0}", reinterpret_cast(~uintptr_t()))); EXPECT_EQ("0x1234", format("{}", fmt::ptr(reinterpret_cast(0x1234)))); + EXPECT_EQ("0x0", format("{}", nullptr)); } TEST(FormatterTest, FormatString) { From 0fbd8465611e7dcd3b9572efe1e13e082c9d3f35 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Mon, 4 Sep 2017 11:41:15 -0700 Subject: [PATCH 140/340] Replace fmt::internal::make_unsigned with std::make_unsigned --- fmt/format.h | 20 ++------------------ fmt/ostream.cc | 2 +- fmt/printf.h | 12 ++++++++++-- test/ostream-test.cc | 2 +- test/printf-test.cc | 6 +++--- 5 files changed, 17 insertions(+), 25 deletions(-) diff --git a/fmt/format.h b/fmt/format.h index 0be4cd70..6616d27a 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -488,27 +488,11 @@ struct formatter; namespace internal { -// make_unsigned::type gives an unsigned type corresponding to integer -// type T. -template -struct make_unsigned { typedef T type; }; - -#define FMT_SPECIALIZE_MAKE_UNSIGNED(T, U) \ - template <> \ - struct make_unsigned { typedef U type; } - -FMT_SPECIALIZE_MAKE_UNSIGNED(char, unsigned char); -FMT_SPECIALIZE_MAKE_UNSIGNED(signed char, unsigned char); -FMT_SPECIALIZE_MAKE_UNSIGNED(short, unsigned short); -FMT_SPECIALIZE_MAKE_UNSIGNED(int, unsigned); -FMT_SPECIALIZE_MAKE_UNSIGNED(long, unsigned long); -FMT_SPECIALIZE_MAKE_UNSIGNED(long long, unsigned long long); - // Casts nonnegative integer to unsigned. template -inline typename make_unsigned::type to_unsigned(Int value) { +inline typename std::make_unsigned::type to_unsigned(Int value) { FMT_ASSERT(value >= 0, "negative value"); - return static_cast::type>(value); + return static_cast::type>(value); } // The number of characters to store in the basic_memory_buffer object itself diff --git a/fmt/ostream.cc b/fmt/ostream.cc index 8fb717bd..d7bbb912 100644 --- a/fmt/ostream.cc +++ b/fmt/ostream.cc @@ -14,7 +14,7 @@ namespace fmt { namespace internal { FMT_FUNC void write(std::ostream &os, buffer &buf) { const char *data = buf.data(); - typedef internal::make_unsigned::type UnsignedStreamSize; + typedef std::make_unsigned::type UnsignedStreamSize; UnsignedStreamSize size = buf.size(); UnsignedStreamSize max_size = internal::to_unsigned((std::numeric_limits::max)()); diff --git a/fmt/printf.h b/fmt/printf.h index 1c58df2b..7e6b06cd 100644 --- a/fmt/printf.h +++ b/fmt/printf.h @@ -70,6 +70,14 @@ class IsZeroInt { operator()(T) { return false; } }; +template +struct make_unsigned_or_bool : std::make_unsigned {}; + +template <> +struct make_unsigned_or_bool { + using type = bool; +}; + template class ArgConverter { private: @@ -99,7 +107,7 @@ class ArgConverter { arg_ = internal::make_arg( static_cast(static_cast(value))); } else { - typedef typename internal::make_unsigned::type Unsigned; + typedef typename make_unsigned_or_bool::type Unsigned; arg_ = internal::make_arg( static_cast(static_cast(value))); } @@ -111,7 +119,7 @@ class ArgConverter { arg_ = internal::make_arg(static_cast(value)); } else { arg_ = internal::make_arg( - static_cast::type>(value)); + static_cast::type>(value)); } } } diff --git a/test/ostream-test.cc b/test/ostream-test.cc index 1b3119c3..b5deb6ad 100644 --- a/test/ostream-test.cc +++ b/test/ostream-test.cc @@ -155,7 +155,7 @@ TEST(OStreamTest, WriteToOStreamMaxSize) { const char *data = 0; std::size_t size = max_size; do { - typedef fmt::internal::make_unsigned::type UStreamSize; + typedef std::make_unsigned::type UStreamSize; UStreamSize n = std::min( size, fmt::internal::to_unsigned(max_streamsize)); EXPECT_CALL(streambuf, xsputn(data, static_cast(n))) diff --git a/test/printf-test.cc b/test/printf-test.cc index aeeac1f3..c2d9e3d1 100644 --- a/test/printf-test.cc +++ b/test/printf-test.cc @@ -306,13 +306,13 @@ void TestLength(const char *length_spec, U value) { signed_value = static_cast(value); unsigned_value = static_cast(value); } - using fmt::internal::make_unsigned; if (sizeof(U) <= sizeof(int) && sizeof(int) < sizeof(T)) { signed_value = static_cast(value); - unsigned_value = static_cast::type>(value); + unsigned_value = + static_cast::type>(value); } else { signed_value = static_cast::type>(value); - unsigned_value = static_cast::type>(value); + unsigned_value = static_cast::type>(value); } std::ostringstream os; os << signed_value; From 44a26e5e21298cc62f58acdb7168cdb097c26514 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Mon, 4 Sep 2017 11:58:14 -0700 Subject: [PATCH 141/340] CharPtr -> pointer_type and move to writer --- fmt/format.h | 64 +++++++++++++++++++++++++--------------------------- fmt/printf.h | 4 ++-- 2 files changed, 33 insertions(+), 35 deletions(-) diff --git a/fmt/format.h b/fmt/format.h index 6616d27a..6ef31e9c 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -769,11 +769,6 @@ namespace internal { template class basic_char_traits { public: -#if FMT_SECURE_SCL - typedef stdext::checked_array_iterator CharPtr; -#else - typedef Char *CharPtr; -#endif static Char cast(int value) { return static_cast(value); } }; @@ -1950,9 +1945,9 @@ class arg_formatter_base { } if (spec_.align_ == ALIGN_NUMERIC || spec_.flags_ != 0) FMT_THROW(format_error("invalid format specifier for char")); - typedef typename basic_writer::CharPtr CharPtr; + typedef typename basic_writer::pointer_type pointer_type; Char fill = internal::char_traits::cast(spec_.fill()); - CharPtr out = CharPtr(); + pointer_type out = pointer_type(); const unsigned CHAR_WIDTH = 1; if (spec_.width_ > CHAR_WIDTH) { out = writer_.grow_buffer(spec_.width_); @@ -2216,23 +2211,23 @@ class basic_writer { FMT_DISALLOW_COPY_AND_ASSIGN(basic_writer); - typedef typename internal::char_traits::CharPtr CharPtr; - #if FMT_SECURE_SCL + typedef stdext::checked_array_iterator pointer_type; // Returns pointer value. - static Char *get(CharPtr p) { return p.base(); } + static Char *get(pointer_type p) { return p.base(); } #else + typedef Char *pointer_type; static Char *get(Char *p) { return p; } #endif // Fills the padding around the content and returns the pointer to the // content area. - static CharPtr fill_padding(CharPtr buffer, + static pointer_type fill_padding(pointer_type buffer, unsigned total_size, std::size_t content_size, wchar_t fill); // Grows the buffer by n characters and returns a pointer to the newly // allocated area. - CharPtr grow_buffer(std::size_t n) { + pointer_type grow_buffer(std::size_t n) { std::size_t size = buffer_.size(); buffer_.resize(size + n); return internal::make_ptr(&buffer_[size], n); @@ -2261,16 +2256,16 @@ class basic_writer { } // Prepare a buffer for integer formatting. - CharPtr prepare_int_buffer(unsigned num_digits, + pointer_type prepare_int_buffer(unsigned num_digits, const empty_spec &, const char *prefix, unsigned prefix_size) { unsigned size = prefix_size + num_digits; - CharPtr p = grow_buffer(size); + pointer_type p = grow_buffer(size); std::uninitialized_copy(prefix, prefix + prefix_size, p); return p + size - 1; } template - CharPtr prepare_int_buffer(unsigned num_digits, + pointer_type prepare_int_buffer(unsigned num_digits, const Spec &spec, const char *prefix, unsigned prefix_size); // Writes a formatted integer. @@ -2283,7 +2278,8 @@ class basic_writer { // Writes a formatted string. template - CharPtr write_str(const StrChar *s, std::size_t size, const align_spec &spec); + pointer_type write_str( + const StrChar *s, std::size_t size, const align_spec &spec); template void write_str(basic_string_view str, const format_specs &spec); @@ -2429,9 +2425,9 @@ class basic_writer { template template -typename basic_writer::CharPtr basic_writer::write_str( +typename basic_writer::pointer_type basic_writer::write_str( const StrChar *s, std::size_t size, const align_spec &spec) { - CharPtr out = CharPtr(); + pointer_type out = pointer_type(); if (spec.width() > size) { out = grow_buffer(spec.width()); Char fill = internal::char_traits::cast(spec.fill()); @@ -2472,15 +2468,15 @@ void basic_writer::write_str( } template -typename basic_writer::CharPtr basic_writer::fill_padding( - CharPtr buffer, unsigned total_size, +typename basic_writer::pointer_type basic_writer::fill_padding( + pointer_type buffer, unsigned total_size, std::size_t content_size, wchar_t fill) { std::size_t padding = total_size - content_size; std::size_t left_padding = padding / 2; Char fill_char = internal::char_traits::cast(fill); std::uninitialized_fill_n(buffer, left_padding, fill_char); buffer += left_padding; - CharPtr content = buffer; + pointer_type content = buffer; std::uninitialized_fill_n(buffer + content_size, padding - left_padding, fill_char); return content; @@ -2488,7 +2484,8 @@ typename basic_writer::CharPtr basic_writer::fill_padding( template template -typename basic_writer::CharPtr basic_writer::prepare_int_buffer( +typename basic_writer::pointer_type + basic_writer::prepare_int_buffer( unsigned num_digits, const Spec &spec, const char *prefix, unsigned prefix_size) { unsigned width = spec.width(); @@ -2507,25 +2504,25 @@ typename basic_writer::CharPtr basic_writer::prepare_int_buffer( buffer_.reserve(width); unsigned fill_size = width - number_size; if (align != ALIGN_LEFT) { - CharPtr p = grow_buffer(fill_size); + pointer_type p = grow_buffer(fill_size); std::uninitialized_fill(p, p + fill_size, fill); } - CharPtr result = prepare_int_buffer( + pointer_type result = prepare_int_buffer( num_digits, subspec, prefix, prefix_size); if (align == ALIGN_LEFT) { - CharPtr p = grow_buffer(fill_size); + pointer_type p = grow_buffer(fill_size); std::uninitialized_fill(p, p + fill_size, fill); } return result; } unsigned size = prefix_size + num_digits; if (width <= size) { - CharPtr p = grow_buffer(size); + pointer_type p = grow_buffer(size); std::uninitialized_copy(prefix, prefix + prefix_size, p); return p + size - 1; } - CharPtr p = grow_buffer(width); - CharPtr end = p + width; + pointer_type p = grow_buffer(width); + pointer_type end = p + width; if (align == ALIGN_LEFT) { std::uninitialized_copy(prefix, prefix + prefix_size, p); p += size; @@ -2567,7 +2564,8 @@ void basic_writer::write_int(T value, const Spec& spec) { switch (spec.type()) { case 0: case 'd': { unsigned num_digits = internal::count_digits(abs_value); - CharPtr p = prepare_int_buffer(num_digits, spec, prefix, prefix_size) + 1; + pointer_type p = + prepare_int_buffer(num_digits, spec, prefix, prefix_size) + 1; internal::format_decimal(get(p), abs_value, 0); break; } @@ -2631,7 +2629,7 @@ void basic_writer::write_int(T value, const Spec& spec) { fmt::basic_string_view sep(&thousands_sep, 1); unsigned size = static_cast( num_digits + sep.size() * ((num_digits - 1) / 3)); - CharPtr p = prepare_int_buffer(size, spec, prefix, prefix_size) + 1; + pointer_type p = prepare_int_buffer(size, spec, prefix, prefix_size) + 1; internal::format_decimal(get(p), abs_value, 0, internal::add_thousands_sep(sep)); break; @@ -2688,7 +2686,7 @@ void basic_writer::write_double(T value, const format_specs &spec) { --nan_size; ++nan; } - CharPtr out = write_str(nan, nan_size, spec); + pointer_type out = write_str(nan, nan_size, spec); if (sign) *out = sign; return; @@ -2703,7 +2701,7 @@ void basic_writer::write_double(T value, const format_specs &spec) { --inf_size; ++inf; } - CharPtr out = write_str(inf, inf_size, spec); + pointer_type out = write_str(inf, inf_size, spec); if (sign) *out = sign; return; @@ -2784,7 +2782,7 @@ void basic_writer::write_double(T value, const format_specs &spec) { } if (spec.align() == ALIGN_CENTER && spec.width() > n) { width = spec.width(); - CharPtr p = grow_buffer(width); + pointer_type p = grow_buffer(width); std::memmove(get(p) + (width - n) / 2, get(p), n * sizeof(Char)); fill_padding(p, spec.width(), n, fill); return; diff --git a/fmt/printf.h b/fmt/printf.h index 7e6b06cd..4a86c381 100644 --- a/fmt/printf.h +++ b/fmt/printf.h @@ -245,8 +245,8 @@ class printf_arg_formatter : public internal::arg_formatter_base { basic_writer &w = this->writer(); if (fmt_spec.type_ && fmt_spec.type_ != 'c') w.write_int(value, fmt_spec); - typedef typename basic_writer::CharPtr CharPtr; - CharPtr out = CharPtr(); + typedef typename basic_writer::pointer_type pointer_type; + pointer_type out = pointer_type(); if (fmt_spec.width_ > 1) { Char fill = ' '; out = w.grow_buffer(fmt_spec.width_); From af00e4f9c95de8ee04b3c4f25c3bdabd95ef4364 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Mon, 4 Sep 2017 12:28:53 -0700 Subject: [PATCH 142/340] Remove printf_arg_formatter from format.h and cleanup --- fmt/format.h | 26 +++++++------------------- fmt/printf.h | 22 +++++----------------- test/printf-test.cc | 2 +- 3 files changed, 13 insertions(+), 37 deletions(-) diff --git a/fmt/format.h b/fmt/format.h index 6ef31e9c..e11a05cf 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -356,30 +356,22 @@ namespace fmt { using std::move; #endif -template -class basic_buffer; - -typedef basic_buffer buffer; -typedef basic_buffer wbuffer; - template class basic_writer; template class basic_arg; -template -class arg_formatter; - -template -class printf_arg_formatter; - template class basic_context; typedef basic_context context; typedef basic_context wcontext; +// A formatter for objects of type T. +template +struct formatter; + /** \rst An implementation of ``std::basic_string_view`` for pre-C++17. It provides a @@ -482,10 +474,6 @@ class format_error : public std::runtime_error { ~format_error() throw(); }; -// A formatter for objects of type T. -template -struct formatter; - namespace internal { // Casts nonnegative integer to unsigned. @@ -589,6 +577,9 @@ class basic_buffer { virtual std::locale locale() const { return std::locale(); } }; +typedef basic_buffer buffer; +typedef basic_buffer wbuffer; + template template void basic_buffer::append(const U *begin, const U *end) { @@ -2304,9 +2295,6 @@ class basic_writer { template friend class internal::arg_formatter_base; - template - friend class printf_arg_formatter; - public: /** Constructs a ``basic_writer`` object. diff --git a/fmt/printf.h b/fmt/printf.h index 4a86c381..69f7a687 100644 --- a/fmt/printf.h +++ b/fmt/printf.h @@ -241,25 +241,13 @@ class printf_arg_formatter : public internal::arg_formatter_base { /** Formats a character. */ void operator()(Char value) { - const format_specs &fmt_spec = this->spec(); + format_specs &fmt_spec = this->spec(); basic_writer &w = this->writer(); if (fmt_spec.type_ && fmt_spec.type_ != 'c') - w.write_int(value, fmt_spec); - typedef typename basic_writer::pointer_type pointer_type; - pointer_type out = pointer_type(); - if (fmt_spec.width_ > 1) { - Char fill = ' '; - out = w.grow_buffer(fmt_spec.width_); - if (fmt_spec.align_ != ALIGN_LEFT) { - std::fill_n(out, fmt_spec.width_ - 1, fill); - out += fmt_spec.width_ - 1; - } else { - std::fill_n(out + 1, fmt_spec.width_ - 1, fill); - } - } else { - out = w.grow_buffer(1); - } - *out = static_cast(value); + return (*this)(static_cast(value)); + fmt_spec.flags_ = 0; + fmt_spec.align_ = ALIGN_RIGHT; + Base::operator()(value); } /** Formats a null-terminated C string. */ diff --git a/test/printf-test.cc b/test/printf-test.cc index c2d9e3d1..7ab5390e 100644 --- a/test/printf-test.cc +++ b/test/printf-test.cc @@ -137,7 +137,7 @@ TEST(PrintfTest, ZeroFlag) { EXPECT_PRINTF("+00042", "%00+6d", 42); // '0' flag is ignored for non-numeric types. - EXPECT_PRINTF(" x", "%05c", 'x'); + EXPECT_PRINTF("0000x", "%05c", 'x'); } TEST(PrintfTest, PlusFlag) { From 7413239f4985bb39dddc843c5a2af9e4e752f63e Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Mon, 4 Sep 2017 13:12:52 -0700 Subject: [PATCH 143/340] Remove unnecessary qualification --- fmt/format.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/fmt/format.h b/fmt/format.h index e11a05cf..4b864028 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -624,7 +624,6 @@ inline std::basic_string to_string(const basic_buffer& buffer) { The output can be converted to an ``std::string`` with ``to_string(out)``. \endrst */ -// template > class basic_memory_buffer : private Allocator, public basic_buffer { @@ -990,13 +989,13 @@ struct no_thousands_sep { template class add_thousands_sep { private: - fmt::basic_string_view sep_; + basic_string_view sep_; // Index of a decimal digit with the least significant digit having index 0. unsigned digit_index_; public: - explicit add_thousands_sep(fmt::basic_string_view sep) + explicit add_thousands_sep(basic_string_view sep) : sep_(sep), digit_index_(0) {} void operator()(Char *&buffer) { From 1cade7ef4dd57ce54d9f56f8cb16104500802da7 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Mon, 4 Sep 2017 13:52:29 -0700 Subject: [PATCH 144/340] Remove FMT_USE_RVALUE_REFERENCES --- fmt/format.h | 29 +++-------------------------- 1 file changed, 3 insertions(+), 26 deletions(-) diff --git a/fmt/format.h b/fmt/format.h index 4b864028..37fff41c 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -128,22 +128,6 @@ # define FMT_NORETURN #endif -#ifndef FMT_USE_RVALUE_REFERENCES -// Don't use rvalue references when compiling with clang and an old libstdc++ -// as the latter doesn't provide std::move. -# if defined(FMT_GNUC_LIBSTD_VERSION) && FMT_GNUC_LIBSTD_VERSION <= 402 -# define FMT_USE_RVALUE_REFERENCES 0 -# else -# define FMT_USE_RVALUE_REFERENCES \ - (FMT_HAS_FEATURE(cxx_rvalue_references) || \ - FMT_GCC_VERSION >= 403 || FMT_MSC_VER >= 1600) -# endif -#endif - -#if FMT_USE_RVALUE_REFERENCES -# include // for std::move -#endif - // Check if exceptions are disabled. #if defined(__GNUC__) && !defined(__EXCEPTIONS) # define FMT_EXCEPTIONS 0 @@ -205,10 +189,9 @@ // makes the fmt::literals implementation easier. However, an explicit check // for variadic templates is added here just in case. // For Intel's compiler both it and the system gcc/msc must support UDLs. -# if FMT_USE_RVALUE_REFERENCES && \ - (FMT_HAS_FEATURE(cxx_user_literals) || \ - FMT_GCC_VERSION >= 407 || FMT_MSC_VER >= 1900) && \ - (!defined(FMT_ICC_VERSION) || FMT_ICC_VERSION >= 1500) +# if (FMT_HAS_FEATURE(cxx_user_literals) || \ + FMT_GCC_VERSION >= 407 || FMT_MSC_VER >= 1900) && \ + (!defined(FMT_ICC_VERSION) || FMT_ICC_VERSION >= 1500) # define FMT_USE_USER_DEFINED_LITERALS 1 # else # define FMT_USE_USER_DEFINED_LITERALS 0 @@ -352,10 +335,6 @@ class numeric_limits : namespace fmt { -#if FMT_USE_RVALUE_REFERENCES -using std::move; -#endif - template class basic_writer; @@ -646,7 +625,6 @@ class basic_memory_buffer : private Allocator, public basic_buffer { } ~basic_memory_buffer() { deallocate(); } -#if FMT_USE_RVALUE_REFERENCES private: // Move data from other to this buffer. void move(basic_memory_buffer &other) { @@ -689,7 +667,6 @@ class basic_memory_buffer : private Allocator, public basic_buffer { move(other); return *this; } -#endif // Returns a copy of the allocator associated with this buffer. Allocator get_allocator() const { return *this; } From c18a4041f99dd3123f0a9fd47c6f28b49a132d47 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Mon, 4 Sep 2017 13:56:14 -0700 Subject: [PATCH 145/340] Remove conditional and to_iterator --- fmt/format.h | 26 +------------------------- fmt/printf.h | 2 +- test/util-test.cc | 9 --------- 3 files changed, 2 insertions(+), 35 deletions(-) diff --git a/fmt/format.h b/fmt/format.h index 37fff41c..be884d76 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -768,12 +768,6 @@ class char_traits : public basic_char_traits { const wchar_t *format, unsigned width, int precision, T value); }; -template -struct conditional { typedef T type; }; - -template -struct conditional { typedef F type; }; - template class null_terminating_iterator; @@ -851,24 +845,6 @@ class null_terminating_iterator { const Char *end_; }; -template < - typename T, - typename Char, - typename std::enable_if< - std::is_same>::value, int>::type = 0> -null_terminating_iterator to_iterator(basic_string_view v) { - const Char *s = v.data(); - return null_terminating_iterator(s, s + v.size()); -} - -template < - typename T, - typename Char, - typename std::enable_if::value, int>::type = 0> -const Char *to_iterator(basic_string_view v) { - return v.data(); -} - template const T *pointer_from(const T *p) { return p; } @@ -894,7 +870,7 @@ template struct int_traits { // Smallest of uint32_t and uint64_t that is large enough to represent // all values of T. - typedef typename conditional< + typedef typename std::conditional< std::numeric_limits::digits <= 32, uint32_t, uint64_t>::type main_type; }; diff --git a/fmt/printf.h b/fmt/printf.h index 69f7a687..8c2095a3 100644 --- a/fmt/printf.h +++ b/fmt/printf.h @@ -99,7 +99,7 @@ class ArgConverter { typename std::enable_if::value>::type operator()(U value) { bool is_signed = type_ == 'd' || type_ == 'i'; - typedef typename internal::conditional< + typedef typename std::conditional< std::is_same::value, U, T>::type TargetType; if (sizeof(TargetType) <= sizeof(int)) { // Extra casts are used to silence warnings. diff --git a/test/util-test.cc b/test/util-test.cc index b63b9047..17390c1c 100644 --- a/test/util-test.cc +++ b/test/util-test.cc @@ -839,12 +839,3 @@ TEST(UtilTest, IsEnumConvertibleToInt) { EXPECT_TRUE(fmt::internal::convert_to_int::enable_conversion); } #endif - -TEST(UtilTest, Conditional) { - int i = 0; - fmt::internal::conditional::type *pi = &i; - (void)pi; - char c = 0; - fmt::internal::conditional::type *pc = &c; - (void)pc; -} From 1a09194ae69b54278663d2f79eb74e68d398b744 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Wed, 6 Sep 2017 07:00:21 -0700 Subject: [PATCH 146/340] Cleanup type handling --- fmt/format.h | 110 +++++++++++++++++++++++++-------------------------- 1 file changed, 54 insertions(+), 56 deletions(-) diff --git a/fmt/format.h b/fmt/format.h index be884d76..fee63d08 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -1142,57 +1142,55 @@ template struct is_named_arg : std::false_type {}; template -struct is_named_arg< named_arg > : std::true_type {}; +struct is_named_arg> : std::true_type {}; template -constexpr Type gettype() { - return is_named_arg::value ? - NAMED_ARG : (convert_to_int::value ? INT : CUSTOM); +constexpr Type get_type() { + return std::is_reference::value || std::is_array::value ? + get_type::type>() : + (is_named_arg::value ? + NAMED_ARG : (convert_to_int::value ? INT : CUSTOM)); } -template <> constexpr Type gettype() { return BOOL; } -template <> constexpr Type gettype() { return INT; } -template <> constexpr Type gettype() { return UINT; } -template <> constexpr Type gettype() { return INT; } -template <> constexpr Type gettype() { return UINT; } -template <> constexpr Type gettype() { +template <> constexpr Type get_type() { return BOOL; } +template <> constexpr Type get_type() { return INT; } +template <> constexpr Type get_type() { return UINT; } +template <> constexpr Type get_type() { return INT; } +template <> constexpr Type get_type() { return UINT; } +template <> constexpr Type get_type() { return sizeof(long) == sizeof(int) ? INT : LONG_LONG; } -template <> constexpr Type gettype() { - return sizeof(unsigned long) == sizeof(unsigned) ? - UINT : ULONG_LONG; +template <> constexpr Type get_type() { + return sizeof(unsigned long) == sizeof(unsigned) ? UINT : ULONG_LONG; } -template <> constexpr Type gettype() { return LONG_LONG; } -template <> constexpr Type gettype() { return ULONG_LONG; } -template <> constexpr Type gettype() { return DOUBLE; } -template <> constexpr Type gettype() { return DOUBLE; } -template <> constexpr Type gettype() { return LONG_DOUBLE; } -template <> constexpr Type gettype() { return INT; } -template <> constexpr Type gettype() { return UINT; } -template <> constexpr Type gettype() { return CHAR; } +template <> constexpr Type get_type() { return LONG_LONG; } +template <> constexpr Type get_type() { return ULONG_LONG; } +template <> constexpr Type get_type() { return DOUBLE; } +template <> constexpr Type get_type() { return DOUBLE; } +template <> constexpr Type get_type() { return LONG_DOUBLE; } +template <> constexpr Type get_type() { return INT; } +template <> constexpr Type get_type() { return UINT; } +template <> constexpr Type get_type() { return CHAR; } #if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED) -template <> constexpr Type gettype() { return CHAR; } +template <> constexpr Type get_type() { return CHAR; } #endif -template <> constexpr Type gettype() { return CSTRING; } -template <> constexpr Type gettype() { return CSTRING; } -template <> constexpr Type gettype() { return CSTRING; } -template <> constexpr Type gettype() { return CSTRING; } -template <> constexpr Type gettype() { return CSTRING; } -template <> constexpr Type gettype() { return CSTRING; } -template <> constexpr Type gettype() { return STRING; } -template <> constexpr Type gettype() { return STRING; } -template <> constexpr Type gettype() { return TSTRING; } -template <> constexpr Type gettype() { return TSTRING; } -template <> constexpr Type gettype() { return TSTRING; } -template <> constexpr Type gettype() { return TSTRING; } -template <> constexpr Type gettype() { return POINTER; } -template <> constexpr Type gettype() { return POINTER; } -template <> constexpr Type gettype() { return POINTER; } - -template -constexpr Type type() { return gettype::type>(); } +template <> constexpr Type get_type() { return CSTRING; } +template <> constexpr Type get_type() { return CSTRING; } +template <> constexpr Type get_type() { return CSTRING; } +template <> constexpr Type get_type() { return CSTRING; } +template <> constexpr Type get_type() { return CSTRING; } +template <> constexpr Type get_type() { return CSTRING; } +template <> constexpr Type get_type() { return STRING; } +template <> constexpr Type get_type() { return STRING; } +template <> constexpr Type get_type() { return TSTRING; } +template <> constexpr Type get_type() { return TSTRING; } +template <> constexpr Type get_type() { return TSTRING; } +template <> constexpr Type get_type() { return TSTRING; } +template <> constexpr Type get_type() { return POINTER; } +template <> constexpr Type get_type() { return POINTER; } +template <> constexpr Type get_type() { return POINTER; } // A formatting argument value. template @@ -1268,7 +1266,7 @@ class value { #define FMT_MAKE_VALUE_(Type, field, TYPE, rhs) \ value(Type value) { \ - static_assert(internal::type() == internal::TYPE, "invalid type"); \ + static_assert(get_type() == internal::TYPE, "invalid type"); \ this->field = rhs; \ } @@ -1309,14 +1307,14 @@ class value { #if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED) typedef typename wchar_helper::supported WChar; value(WChar value) { - static_assert(internal::type() == internal::CHAR, "invalid type"); + static_assert(get_type() == internal::CHAR, "invalid type"); this->int_value = value; } #endif #define FMT_MAKE_STR_VALUE(Type, TYPE) \ value(Type value) { \ - static_assert(internal::type() == internal::TYPE, "invalid type"); \ + static_assert(get_type() == internal::TYPE, "invalid type"); \ set_string(value); \ } @@ -1331,7 +1329,7 @@ class value { #define FMT_MAKE_WSTR_VALUE(Type, TYPE) \ value(typename wchar_helper::supported value) { \ - static_assert(internal::type() == internal::TYPE, "invalid type"); \ + static_assert(get_type() == internal::TYPE, "invalid type"); \ set_string(value); \ } @@ -1347,7 +1345,7 @@ class value { template value(const T &value, typename std::enable_if::value, int>::type = 0) { - static_assert(internal::type() == internal::CUSTOM, "invalid type"); + static_assert(get_type() == internal::CUSTOM, "invalid type"); this->custom.value = &value; this->custom.format = &format_custom_arg; } @@ -1355,7 +1353,7 @@ class value { template value(const T &value, typename std::enable_if::value, int>::type = 0) { - static_assert(internal::type() == internal::INT, "invalid type"); + static_assert(get_type() == internal::INT, "invalid type"); this->int_value = value; } @@ -1364,7 +1362,7 @@ class value { template value(const named_arg &value) { static_assert( - internal::type &>() == internal::NAMED_ARG, + get_type &>() == internal::NAMED_ARG, "invalid type"); this->pointer = &value; } @@ -1465,7 +1463,7 @@ namespace internal { template basic_arg make_arg(const T &value) { basic_arg arg; - arg.type_ = internal::type(); + arg.type_ = get_type(); arg.value_ = value; return arg; } @@ -1503,12 +1501,12 @@ struct named_arg : basic_arg { }; template -constexpr uint64_t make_type() { - return type() | (make_type() << 4); +constexpr uint64_t get_types() { + return get_type() | (get_types() << 4); } template <> -constexpr uint64_t make_type() { return 0; } +constexpr uint64_t get_types() { return 0; } // Maximum number of arguments with packed types. enum { MAX_PACKED_ARGS = 15 }; @@ -1546,7 +1544,7 @@ class arg_store { public: static const uint64_t TYPES = NUM_ARGS <= internal::MAX_PACKED_ARGS ? - internal::make_type() : -static_cast(NUM_ARGS); + internal::get_types() : -static_cast(NUM_ARGS); arg_store(const Args &... args) : data_(Array{{internal::make_arg(args)...}}) {} @@ -3494,10 +3492,10 @@ const Char *do_format_arg(basic_buffer &buffer, } // Specifies whether to format T using the standard formatter. -// It is not possible to use gettype in formatter specialization directly +// It is not possible to use get_type in formatter specialization directly // because of a bug in MSVC. template -struct format_type : std::integral_constant() != CUSTOM> {}; +struct format_type : std::integral_constant() != CUSTOM> {}; // Specifies whether to format enums. template @@ -3533,7 +3531,7 @@ struct formatter< auto it = internal::null_terminating_iterator(format); using handler_type = internal::dynamic_specs_handler; internal::specs_checker - handler(handler_type(specs_), internal::gettype()); + handler(handler_type(specs_), internal::get_type()); it = parse_format_specs(it, handler); return pointer_from(it); } @@ -3595,7 +3593,7 @@ struct dynamic_formatter { void on_hash() {} }; internal::specs_checker - checker(null_handler(), internal::gettype()); + checker(null_handler(), internal::get_type()); checker.on_align(specs_.align()); if (specs_.flags_ == 0) { // Do nothing. From 9ee7c2163cee80d7160dc22e7d3999a780394681 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Wed, 6 Sep 2017 07:12:07 -0700 Subject: [PATCH 147/340] Type -> type --- fmt/format.h | 97 ++++++++++++++++++++++++++-------------------------- 1 file changed, 48 insertions(+), 49 deletions(-) diff --git a/fmt/format.h b/fmt/format.h index fee63d08..30d77f99 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -1100,7 +1100,7 @@ FMT_DISABLE_CONVERSION_TO_INT(float); FMT_DISABLE_CONVERSION_TO_INT(double); FMT_DISABLE_CONVERSION_TO_INT(long double); -enum Type { +enum type { NONE, NAMED_ARG, // Integer types should go first, INT, UINT, LONG_LONG, ULONG_LONG, BOOL, CHAR, LAST_INTEGER_TYPE = CHAR, @@ -1109,14 +1109,14 @@ enum Type { CSTRING, STRING, TSTRING, POINTER, CUSTOM }; -inline bool is_integral(Type type) { - FMT_ASSERT(type != internal::NAMED_ARG, "invalid argument type"); - return type > internal::NONE && type <= internal::LAST_INTEGER_TYPE; +inline bool is_integral(type t) { + FMT_ASSERT(t != internal::NAMED_ARG, "invalid argument type"); + return t > internal::NONE && t <= internal::LAST_INTEGER_TYPE; } -inline bool is_numeric(Type type) { - FMT_ASSERT(type != internal::NAMED_ARG, "invalid argument type"); - return type > internal::NONE && type <= internal::LAST_NUMERIC_TYPE; +inline bool is_numeric(type t) { + FMT_ASSERT(t != internal::NAMED_ARG, "invalid argument type"); + return t > internal::NONE && t <= internal::LAST_NUMERIC_TYPE; } template @@ -1145,52 +1145,52 @@ template struct is_named_arg> : std::true_type {}; template -constexpr Type get_type() { +constexpr type get_type() { return std::is_reference::value || std::is_array::value ? get_type::type>() : (is_named_arg::value ? NAMED_ARG : (convert_to_int::value ? INT : CUSTOM)); } -template <> constexpr Type get_type() { return BOOL; } -template <> constexpr Type get_type() { return INT; } -template <> constexpr Type get_type() { return UINT; } -template <> constexpr Type get_type() { return INT; } -template <> constexpr Type get_type() { return UINT; } -template <> constexpr Type get_type() { +template <> constexpr type get_type() { return BOOL; } +template <> constexpr type get_type() { return INT; } +template <> constexpr type get_type() { return UINT; } +template <> constexpr type get_type() { return INT; } +template <> constexpr type get_type() { return UINT; } +template <> constexpr type get_type() { return sizeof(long) == sizeof(int) ? INT : LONG_LONG; } -template <> constexpr Type get_type() { +template <> constexpr type get_type() { return sizeof(unsigned long) == sizeof(unsigned) ? UINT : ULONG_LONG; } -template <> constexpr Type get_type() { return LONG_LONG; } -template <> constexpr Type get_type() { return ULONG_LONG; } -template <> constexpr Type get_type() { return DOUBLE; } -template <> constexpr Type get_type() { return DOUBLE; } -template <> constexpr Type get_type() { return LONG_DOUBLE; } -template <> constexpr Type get_type() { return INT; } -template <> constexpr Type get_type() { return UINT; } -template <> constexpr Type get_type() { return CHAR; } +template <> constexpr type get_type() { return LONG_LONG; } +template <> constexpr type get_type() { return ULONG_LONG; } +template <> constexpr type get_type() { return DOUBLE; } +template <> constexpr type get_type() { return DOUBLE; } +template <> constexpr type get_type() { return LONG_DOUBLE; } +template <> constexpr type get_type() { return INT; } +template <> constexpr type get_type() { return UINT; } +template <> constexpr type get_type() { return CHAR; } #if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED) -template <> constexpr Type get_type() { return CHAR; } +template <> constexpr type get_type() { return CHAR; } #endif -template <> constexpr Type get_type() { return CSTRING; } -template <> constexpr Type get_type() { return CSTRING; } -template <> constexpr Type get_type() { return CSTRING; } -template <> constexpr Type get_type() { return CSTRING; } -template <> constexpr Type get_type() { return CSTRING; } -template <> constexpr Type get_type() { return CSTRING; } -template <> constexpr Type get_type() { return STRING; } -template <> constexpr Type get_type() { return STRING; } -template <> constexpr Type get_type() { return TSTRING; } -template <> constexpr Type get_type() { return TSTRING; } -template <> constexpr Type get_type() { return TSTRING; } -template <> constexpr Type get_type() { return TSTRING; } -template <> constexpr Type get_type() { return POINTER; } -template <> constexpr Type get_type() { return POINTER; } -template <> constexpr Type get_type() { return POINTER; } +template <> constexpr type get_type() { return CSTRING; } +template <> constexpr type get_type() { return CSTRING; } +template <> constexpr type get_type() { return CSTRING; } +template <> constexpr type get_type() { return CSTRING; } +template <> constexpr type get_type() { return CSTRING; } +template <> constexpr type get_type() { return CSTRING; } +template <> constexpr type get_type() { return STRING; } +template <> constexpr type get_type() { return STRING; } +template <> constexpr type get_type() { return TSTRING; } +template <> constexpr type get_type() { return TSTRING; } +template <> constexpr type get_type() { return TSTRING; } +template <> constexpr type get_type() { return TSTRING; } +template <> constexpr type get_type() { return POINTER; } +template <> constexpr type get_type() { return POINTER; } +template <> constexpr type get_type() { return POINTER; } // A formatting argument value. template @@ -1362,8 +1362,7 @@ class value { template value(const named_arg &value) { static_assert( - get_type &>() == internal::NAMED_ARG, - "invalid type"); + get_type &>() == NAMED_ARG, "invalid type"); this->pointer = &value; } }; @@ -1386,7 +1385,7 @@ template class basic_arg { private: internal::value value_; - internal::Type type_; + internal::type type_; template friend basic_arg internal::make_arg(const T &value); @@ -1403,7 +1402,7 @@ class basic_arg { explicit operator bool() const noexcept { return type_ != internal::NONE; } - internal::Type type() const { return type_; } + internal::type type() const { return type_; } bool is_integral() const { return internal::is_integral(type_); } bool is_numeric() const { return internal::is_numeric(type_); } @@ -1583,10 +1582,10 @@ class basic_args { const format_arg *args_; }; - typename internal::Type type(unsigned index) const { + typename internal::type type(unsigned index) const { unsigned shift = index * 4; uint64_t mask = 0xf; - return static_cast( + return static_cast( (types_ & (mask << shift)) >> shift); } @@ -1773,7 +1772,7 @@ void arg_map::init(const basic_args &args) { args.type(MAX_PACKED_ARGS - 1) == internal::NONE; if (use_values) { for (unsigned i = 0;/*nothing*/; ++i) { - internal::Type arg_type = args.type(i); + internal::type arg_type = args.type(i); switch (arg_type) { case internal::NONE: return; @@ -1788,7 +1787,7 @@ void arg_map::init(const basic_args &args) { return; } for (unsigned i = 0; i != MAX_PACKED_ARGS; ++i) { - internal::Type arg_type = args.type(i); + internal::type arg_type = args.type(i); if (arg_type == internal::NAMED_ARG) { named_arg = static_cast(args.args_[i].value_.pointer); map_.push_back(Pair(named_arg->name, *named_arg)); @@ -3155,7 +3154,7 @@ class specs_setter { template class specs_checker : public Handler { public: - explicit specs_checker(const Handler& handler, Type arg_type) + explicit specs_checker(const Handler& handler, type arg_type) : Handler(handler), arg_type_(arg_type) {} void on_align(alignment align) { @@ -3220,7 +3219,7 @@ class specs_checker : public Handler { } } - Type arg_type_; + type arg_type_; }; template From 2972de4ba3009cc1ae9eae9da928522cd5298343 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Wed, 6 Sep 2017 07:29:48 -0700 Subject: [PATCH 148/340] Char -> char_type --- fmt/format.h | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/fmt/format.h b/fmt/format.h index 30d77f99..c2244390 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -1211,7 +1211,7 @@ class value { custom_value custom; }; - typedef typename Context::char_type Char; + using char_type = typename Context::char_type; private: // The following two methods are private to disallow formatting of @@ -1229,12 +1229,12 @@ class value { // fmt::format("{}", L"test"); // To fix this, use a wide format string: fmt::format(L"{}", L"test"). #if !FMT_MSC_VER || defined(_NATIVE_WCHAR_T_DEFINED) - value(typename wchar_helper::unsupported); + value(typename wchar_helper::unsupported); #endif - value(typename wchar_helper::unsupported); - value(typename wchar_helper::unsupported); - value(typename wchar_helper::unsupported); - value(typename wchar_helper::unsupported); + value(typename wchar_helper::unsupported); + value(typename wchar_helper::unsupported); + value(typename wchar_helper::unsupported); + value(typename wchar_helper::unsupported); void set_string(string_view str) { this->string.value = str.data(); @@ -1249,8 +1249,8 @@ class value { // Formats an argument of a custom type, such as a user-defined class. template static void format_custom_arg( - basic_buffer &buffer, const void *arg, - basic_string_view &format, void *context) { + basic_buffer &buffer, const void *arg, + basic_string_view &format, void *context) { Context &ctx = *static_cast(context); // Get the formatter type through the context to allow different contexts // have different extension points, e.g. `formatter` for `format` and @@ -1305,16 +1305,16 @@ class value { FMT_MAKE_VALUE(char, int_value, CHAR) #if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED) - typedef typename wchar_helper::supported WChar; + typedef typename wchar_helper::supported WChar; value(WChar value) { - static_assert(get_type() == internal::CHAR, "invalid type"); + static_assert(get_type() == CHAR, "invalid type"); this->int_value = value; } #endif #define FMT_MAKE_STR_VALUE(Type, TYPE) \ value(Type value) { \ - static_assert(get_type() == internal::TYPE, "invalid type"); \ + static_assert(get_type() == TYPE, "invalid type"); \ set_string(value); \ } @@ -1328,8 +1328,8 @@ class value { FMT_MAKE_STR_VALUE(string_view, STRING) #define FMT_MAKE_WSTR_VALUE(Type, TYPE) \ - value(typename wchar_helper::supported value) { \ - static_assert(get_type() == internal::TYPE, "invalid type"); \ + value(typename wchar_helper::supported value) { \ + static_assert(get_type() == TYPE, "invalid type"); \ set_string(value); \ } @@ -1345,7 +1345,7 @@ class value { template value(const T &value, typename std::enable_if::value, int>::type = 0) { - static_assert(get_type() == internal::CUSTOM, "invalid type"); + static_assert(get_type() == CUSTOM, "invalid type"); this->custom.value = &value; this->custom.format = &format_custom_arg; } @@ -1353,16 +1353,16 @@ class value { template value(const T &value, typename std::enable_if::value, int>::type = 0) { - static_assert(get_type() == internal::INT, "invalid type"); + static_assert(get_type() == INT, "invalid type"); this->int_value = value; } // Additional template param `Char_` is needed here because make_type always // uses char. - template - value(const named_arg &value) { + template + value(const named_arg &value) { static_assert( - get_type &>() == NAMED_ARG, "invalid type"); + get_type &>() == NAMED_ARG, "invalid type"); this->pointer = &value; } }; From 53cf0735610e382e7bb155496e4a383d32a0fdef Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Fri, 8 Sep 2017 07:43:04 -0700 Subject: [PATCH 149/340] Get rid of FMT_MAKE_VALUE macro --- fmt/format.h | 294 +++++++++++++++++++++++---------------------------- 1 file changed, 134 insertions(+), 160 deletions(-) diff --git a/fmt/format.h b/fmt/format.h index c2244390..3d573282 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -1043,20 +1043,6 @@ FMT_API void format_windows_error(fmt::buffer &out, int error_code, template struct null {}; -// A helper class template to enable or disable overloads taking wide -// characters and strings in value's constructor. -template -struct wchar_helper { - typedef null supported; - typedef T unsupported; -}; - -template -struct wchar_helper { - typedef T supported; - typedef null unsupported; -}; - typedef char yes[1]; typedef char no[2]; @@ -1192,10 +1178,26 @@ template <> constexpr type get_type() { return POINTER; } template <> constexpr type get_type() { return POINTER; } template <> constexpr type get_type() { return POINTER; } +// Formatting of wide characters and strings into a narrow output is disallowed: +// fmt::format("{}", L"test"); // error +// To fix this, use a wide format string: +// fmt::format(L"{}", L"test"); +template +inline void require_wchar() { + static_assert( + std::is_same::value, + "formatting of wide characters into a narrow output is disallowed"); +} + +template +inline const T *as_const(T *p) { return p; } + // A formatting argument value. template class value { public: + using char_type = typename Context::char_type; + union { int int_value; unsigned uint_value; @@ -1207,38 +1209,122 @@ class value { string_value string; string_value sstring; string_value ustring; - string_value tstring; - custom_value custom; + string_value tstring; + custom_value custom; }; - using char_type = typename Context::char_type; + value() {} + value(bool val) { set(int_value, val); } + value(short val) { set(int_value, val); } + value(unsigned short val) { set(uint_value, val); } + value(int val) { set(int_value, val); } + value(unsigned val) { set(uint_value, val); } + + value(long val) { + // To minimize the number of types we need to deal with, long is + // translated either to int or to long long depending on its size. + if (const_check(sizeof(val) == sizeof(int))) + int_value = static_cast(val); + else + long_long_value = val; + } + + value(unsigned long val) { + if (const_check(sizeof(val) == sizeof(unsigned))) + uint_value = static_cast(val); + else + ulong_long_value = val; + } + + value(long long val) { set(long_long_value, val); } + value(unsigned long long val) { set(ulong_long_value, val); } + value(float val) { set(double_value, val); } + value(double val) { set(double_value, val); } + value(long double val) { set(long_double_value, val); } + value(signed char val) { set(int_value, val); } + value(unsigned char val) { set(uint_value, val); } + value(char val) { set(int_value, val); } + +#if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED) + value(wchar_t value) { + require_wchar(); + set(int_value, value); + } +#endif + + value(char *s) { set(string.value, s); } + value(const char *s) { set(string.value, s); } + value(signed char *s) { set(sstring.value, s); } + value(const signed char *s) { set(sstring.value, s); } + value(unsigned char *s) { set(ustring.value, s); } + value(const unsigned char *s) { set(ustring.value, s); } + value(string_view s) { set_string(string, s); } + value(const std::string &s) { set_string(string, s); } + +#define FMT_MAKE_WSTR_VALUE(Type, TYPE) \ + value(Type value) { \ + require_wchar(); \ + static_assert(get_type() == TYPE, "invalid type"); \ + set_string(value); \ + } + + FMT_MAKE_WSTR_VALUE(wchar_t *, TSTRING) + FMT_MAKE_WSTR_VALUE(const wchar_t *, TSTRING) + FMT_MAKE_WSTR_VALUE(wstring_view, TSTRING) + FMT_MAKE_WSTR_VALUE(const std::wstring &, TSTRING) + + // Formatting of arbitrary pointers is disallowed. If you want to output a + // pointer cast it to "void *" or "const void *". In particular, this forbids + // formatting of "[const] volatile char *" which is printed as bool by + // iostreams. + template + value(const T *p) { + static_assert(std::is_same::value, + "formatting of non-void pointers is disallowed"); + set(pointer, p); + } + + template + value(T *p) : value(as_const(p)) {} + + value(std::nullptr_t) { pointer = nullptr; } + + template + value(const T &value, + typename std::enable_if::value, int>::type = 0) { + static_assert(get_type() == INT, "invalid type"); + int_value = value; + } + + template + value(const T &value, + typename std::enable_if::value, int>::type = 0) { + static_assert(get_type() == CUSTOM, "invalid type"); + custom.value = &value; + custom.format = &format_custom_arg; + } + + // Additional template param `Char` is needed here because get_type always + // uses char. + template + value(const named_arg &value) { + static_assert( + get_type &>() == NAMED_ARG, "invalid type"); + pointer = &value; + } private: - // The following two methods are private to disallow formatting of - // arbitrary pointers. If you want to output a pointer cast it to - // "void *" or "const void *". In particular, this forbids formatting - // of "[const] volatile char *" which is printed as bool by iostreams. - // Do not implement! - template - value(const T *value); - template - value(T *value); + template + void set(T &field, const U &value) { + static_assert(get_type() == TYPE, "invalid type"); + field = value; + } - // The following methods are private to disallow formatting of wide - // characters and strings into narrow strings as in - // fmt::format("{}", L"test"); - // To fix this, use a wide format string: fmt::format(L"{}", L"test"). -#if !FMT_MSC_VER || defined(_NATIVE_WCHAR_T_DEFINED) - value(typename wchar_helper::unsupported); -#endif - value(typename wchar_helper::unsupported); - value(typename wchar_helper::unsupported); - value(typename wchar_helper::unsupported); - value(typename wchar_helper::unsupported); - - void set_string(string_view str) { - this->string.value = str.data(); - this->string.size = str.size(); + template + void set_string(T &field, const U &value) { + static_assert(get_type() == TYPE, "invalid type"); + field.value = value.data(); + field.size = value.size(); } void set_string(wstring_view str) { @@ -1260,111 +1346,6 @@ class value { format.remove_prefix(it - begin(format)); f.format(buffer, *static_cast(arg), ctx); } - - public: - value() {} - -#define FMT_MAKE_VALUE_(Type, field, TYPE, rhs) \ - value(Type value) { \ - static_assert(get_type() == internal::TYPE, "invalid type"); \ - this->field = rhs; \ - } - -#define FMT_MAKE_VALUE(Type, field, TYPE) \ - FMT_MAKE_VALUE_(Type, field, TYPE, value) - - FMT_MAKE_VALUE(bool, int_value, BOOL) - FMT_MAKE_VALUE(short, int_value, INT) - FMT_MAKE_VALUE(unsigned short, uint_value, UINT) - FMT_MAKE_VALUE(int, int_value, INT) - FMT_MAKE_VALUE(unsigned, uint_value, UINT) - - value(long value) { - // To minimize the number of types we need to deal with, long is - // translated either to int or to long long depending on its size. - if (const_check(sizeof(long) == sizeof(int))) - this->int_value = static_cast(value); - else - this->long_long_value = value; - } - - value(unsigned long value) { - if (const_check(sizeof(unsigned long) == sizeof(unsigned))) - this->uint_value = static_cast(value); - else - this->ulong_long_value = value; - } - - FMT_MAKE_VALUE(long long, long_long_value, LONG_LONG) - FMT_MAKE_VALUE(unsigned long long, ulong_long_value, ULONG_LONG) - FMT_MAKE_VALUE(float, double_value, DOUBLE) - FMT_MAKE_VALUE(double, double_value, DOUBLE) - FMT_MAKE_VALUE(long double, long_double_value, LONG_DOUBLE) - FMT_MAKE_VALUE(signed char, int_value, INT) - FMT_MAKE_VALUE(unsigned char, uint_value, UINT) - FMT_MAKE_VALUE(char, int_value, CHAR) - -#if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED) - typedef typename wchar_helper::supported WChar; - value(WChar value) { - static_assert(get_type() == CHAR, "invalid type"); - this->int_value = value; - } -#endif - -#define FMT_MAKE_STR_VALUE(Type, TYPE) \ - value(Type value) { \ - static_assert(get_type() == TYPE, "invalid type"); \ - set_string(value); \ - } - - FMT_MAKE_VALUE(char *, string.value, CSTRING) - FMT_MAKE_VALUE(const char *, string.value, CSTRING) - FMT_MAKE_VALUE(signed char *, sstring.value, CSTRING) - FMT_MAKE_VALUE(const signed char *, sstring.value, CSTRING) - FMT_MAKE_VALUE(unsigned char *, ustring.value, CSTRING) - FMT_MAKE_VALUE(const unsigned char *, ustring.value, CSTRING) - FMT_MAKE_STR_VALUE(const std::string &, STRING) - FMT_MAKE_STR_VALUE(string_view, STRING) - -#define FMT_MAKE_WSTR_VALUE(Type, TYPE) \ - value(typename wchar_helper::supported value) { \ - static_assert(get_type() == TYPE, "invalid type"); \ - set_string(value); \ - } - - FMT_MAKE_WSTR_VALUE(wchar_t *, TSTRING) - FMT_MAKE_WSTR_VALUE(const wchar_t *, TSTRING) - FMT_MAKE_WSTR_VALUE(const std::wstring &, TSTRING) - FMT_MAKE_WSTR_VALUE(wstring_view, TSTRING) - - FMT_MAKE_VALUE(void *, pointer, POINTER) - FMT_MAKE_VALUE(const void *, pointer, POINTER) - value(std::nullptr_t) { pointer = nullptr; } - - template - value(const T &value, - typename std::enable_if::value, int>::type = 0) { - static_assert(get_type() == CUSTOM, "invalid type"); - this->custom.value = &value; - this->custom.format = &format_custom_arg; - } - - template - value(const T &value, - typename std::enable_if::value, int>::type = 0) { - static_assert(get_type() == INT, "invalid type"); - this->int_value = value; - } - - // Additional template param `Char_` is needed here because make_type always - // uses char. - template - value(const named_arg &value) { - static_assert( - get_type &>() == NAMED_ARG, "invalid type"); - this->pointer = &value; - } }; template @@ -2224,14 +2205,6 @@ class basic_writer { template void write_str(basic_string_view str, const format_specs &spec); - // This following methods are private to disallow writing wide characters - // and strings to a char buffer. If you want to print a wide string as a - // pointer as std::ostream does, cast it to const void*. - // Do not implement! - void operator<<(typename internal::wchar_helper::unsupported); - void operator<<( - typename internal::wchar_helper::unsupported); - // Appends floating-point length specifier to the format string. // The second argument is only used for overload resolution. void append_float_length(Char *&format_ptr, long double) { @@ -2330,7 +2303,8 @@ class basic_writer { buffer_.push_back(value); } - void write(typename internal::wchar_helper::supported value) { + void write(wchar_t value) { + internal::require_wchar(); buffer_.push_back(value); } @@ -2339,14 +2313,14 @@ class basic_writer { Writes *value* to the buffer. \endrst */ - void write(basic_string_view value) { - const Char *str = value.data(); + void write(string_view value) { + const char *str = value.data(); buffer_.append(str, str + value.size()); } - void write( - typename internal::wchar_helper::supported value) { - const char *str = value.data(); + void write(basic_string_view value) { + internal::require_wchar(); + const wchar_t *str = value.data(); buffer_.append(str, str + value.size()); } From be887d92696afdcf9ab15c89ee5bf6d10be62e96 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Fri, 8 Sep 2017 08:09:28 -0700 Subject: [PATCH 150/340] Replace internal::get with std::declval --- fmt/format.h | 7 +++---- fmt/ostream.h | 3 ++- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/fmt/format.h b/fmt/format.h index 3d573282..5fb9611b 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -1046,9 +1046,6 @@ struct null {}; typedef char yes[1]; typedef char no[2]; -template -T &get(); - yes &convert(unsigned long long); no &convert(...); @@ -1073,7 +1070,9 @@ struct convert_to_int_impl2 { template struct convert_to_int { - enum { enable_conversion = sizeof(convert(get())) == sizeof(yes) }; + enum { + enable_conversion = sizeof(convert(std::declval())) == sizeof(yes) + }; enum { value = convert_to_int_impl2::value }; }; diff --git a/fmt/ostream.h b/fmt/ostream.h index e7e0b8e7..66af91b4 100644 --- a/fmt/ostream.h +++ b/fmt/ostream.h @@ -63,7 +63,8 @@ template struct convert_to_int_impl { // Convert to int only if T doesn't have an overloaded operator<<. enum { - value = sizeof(convert(get() << get())) == sizeof(no) + value = sizeof(convert(std::declval() << std::declval())) + == sizeof(no) }; }; From fced79b0ee1d79818f327746190f185db8fa2a28 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Fri, 8 Sep 2017 08:26:05 -0700 Subject: [PATCH 151/340] Get rid of old compat macros --- fmt/format.h | 34 +++------------------------------- fmt/posix.cc | 2 +- test/posix-mock-test.cc | 6 ------ 3 files changed, 4 insertions(+), 38 deletions(-) diff --git a/fmt/format.h b/fmt/format.h index 5fb9611b..da1ef297 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -165,24 +165,11 @@ # endif #endif -// A macro to disallow the copy constructor and operator= functions -// This should be used in the private: declarations for a class -#ifndef FMT_USE_DELETED_FUNCTIONS -# define FMT_USE_DELETED_FUNCTIONS 0 -#endif - -#if FMT_USE_DELETED_FUNCTIONS || FMT_HAS_FEATURE(cxx_deleted_functions) || \ - FMT_GCC_VERSION >= 404 || FMT_MSC_VER >= 1800 -# define FMT_DELETED_OR_UNDEFINED = delete -# define FMT_DISALLOW_COPY_AND_ASSIGN(TypeName) \ +// A macro to disallow the copy construction and assignment. +#define FMT_DISALLOW_COPY_AND_ASSIGN(TypeName) \ TypeName(const TypeName&) = delete; \ TypeName& operator=(const TypeName&) = delete -#else -# define FMT_DELETED_OR_UNDEFINED -# define FMT_DISALLOW_COPY_AND_ASSIGN(TypeName) \ - TypeName(const TypeName&); \ - TypeName& operator=(const TypeName&) -#endif +#define FMT_DELETED_OR_UNDEFINED = delete #ifndef FMT_USE_USER_DEFINED_LITERALS // All compilers which support UDLs also support variadic templates. This @@ -1447,27 +1434,12 @@ basic_arg make_arg(const T &value) { return arg; } -#define FMT_CONCAT(a, b) a##b - #if FMT_GCC_VERSION >= 407 # define FMT_UNUSED __attribute__((unused)) #else # define FMT_UNUSED #endif -#ifndef FMT_USE_STATIC_ASSERT -# define FMT_USE_STATIC_ASSERT 0 -#endif - -#if FMT_USE_STATIC_ASSERT || FMT_HAS_FEATURE(cxx_static_assert) || \ - FMT_GCC_VERSION >= 403 || _MSC_VER >= 1600 -# define FMT_STATIC_ASSERT(cond, message) static_assert(cond, message) -#else -# define FMT_CONCAT_(a, b) FMT_CONCAT(a, b) -# define FMT_STATIC_ASSERT(cond, message) \ - typedef int FMT_CONCAT_(Assert, __LINE__)[(cond) ? 1 : -1] FMT_UNUSED -#endif - template struct named_arg : basic_arg { typedef typename Context::char_type Char; diff --git a/fmt/posix.cc b/fmt/posix.cc index 59e92539..1d473d22 100644 --- a/fmt/posix.cc +++ b/fmt/posix.cc @@ -144,7 +144,7 @@ long long fmt::File::size() const { Stat file_stat = Stat(); if (FMT_POSIX_CALL(fstat(fd_, &file_stat)) == -1) throw system_error(errno, "cannot get file attributes"); - FMT_STATIC_ASSERT(sizeof(long long) >= sizeof(file_stat.st_size), + static_assert(sizeof(long long) >= sizeof(file_stat.st_size), "return type of File::size is not large enough"); return file_stat.st_size; #endif diff --git a/test/posix-mock-test.cc b/test/posix-mock-test.cc index ece17e8d..c132e1e7 100644 --- a/test/posix-mock-test.cc +++ b/test/posix-mock-test.cc @@ -218,12 +218,6 @@ void write_file(fmt::cstring_view filename, fmt::string_view content) { f.print("{}", content); } -TEST(UtilTest, StaticAssert) { - FMT_STATIC_ASSERT(true, "success"); - // Static assertion failure is tested in compile-test because it causes - // a compile-time error. -} - TEST(UtilTest, GetPageSize) { #ifdef _WIN32 SYSTEM_INFO si = {}; From a3191a99038ad05b9de622dd14680def719a6e9d Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Fri, 8 Sep 2017 08:42:01 -0700 Subject: [PATCH 152/340] Get rid of FMT_MAKE_WSTR_VALUE macro --- fmt/format.h | 39 +++++++++++++++++---------------------- 1 file changed, 17 insertions(+), 22 deletions(-) diff --git a/fmt/format.h b/fmt/format.h index da1ef297..fdbbe4ed 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -1244,20 +1244,12 @@ class value { value(const signed char *s) { set(sstring.value, s); } value(unsigned char *s) { set(ustring.value, s); } value(const unsigned char *s) { set(ustring.value, s); } - value(string_view s) { set_string(string, s); } - value(const std::string &s) { set_string(string, s); } - -#define FMT_MAKE_WSTR_VALUE(Type, TYPE) \ - value(Type value) { \ - require_wchar(); \ - static_assert(get_type() == TYPE, "invalid type"); \ - set_string(value); \ - } - - FMT_MAKE_WSTR_VALUE(wchar_t *, TSTRING) - FMT_MAKE_WSTR_VALUE(const wchar_t *, TSTRING) - FMT_MAKE_WSTR_VALUE(wstring_view, TSTRING) - FMT_MAKE_WSTR_VALUE(const std::wstring &, TSTRING) + value(string_view s) { set_string(s); } + value(const std::string &s) { set_string(s); } + value(wstring_view s) { set_wstring(s); } + value(const std::wstring &s) { set_wstring(s); } + value(wchar_t *s) { set_wstring(wstring_view(s)); } + value(const wchar_t *s) { set_wstring(wstring_view(s)); } // Formatting of arbitrary pointers is disallowed. If you want to output a // pointer cast it to "void *" or "const void *". In particular, this forbids @@ -1306,16 +1298,19 @@ class value { field = value; } - template - void set_string(T &field, const U &value) { - static_assert(get_type() == TYPE, "invalid type"); - field.value = value.data(); - field.size = value.size(); + template + void set_string(const T &value) { + static_assert(get_type() == STRING, "invalid type"); + string.value = value.data(); + string.size = value.size(); } - void set_string(wstring_view str) { - this->tstring.value = str.data(); - this->tstring.size = str.size(); + template + void set_wstring(const T &value) { + require_wchar(); + static_assert(get_type() == TSTRING, "invalid type"); + tstring.value = value.data(); + tstring.size = value.size(); } // Formats an argument of a custom type, such as a user-defined class. From 0cda806dcce000600a1a81115f73eeeea5a67b31 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Fri, 8 Sep 2017 11:25:49 -0700 Subject: [PATCH 153/340] Fix compile tests --- test/compile-test/CMakeLists.txt | 3 --- 1 file changed, 3 deletions(-) diff --git a/test/compile-test/CMakeLists.txt b/test/compile-test/CMakeLists.txt index b7126248..4e90fb1f 100644 --- a/test/compile-test/CMakeLists.txt +++ b/test/compile-test/CMakeLists.txt @@ -63,9 +63,6 @@ expect_compile_error("fmt::MemoryWriter() << fmt::pad(42, 5, L' ');") # Formatting a wide character with a narrow format string is forbidden. expect_compile_error("fmt::format(\"{}\", L'a';") -expect_compile("FMT_STATIC_ASSERT(true, \"this should never happen\");") -expect_compile_error("FMT_STATIC_ASSERT(0 > 1, \"oops\");") - # Make sure that compiler features detected in the header # match the features detected in CMake. if (SUPPORTS_USER_DEFINED_LITERALS) From 534bff7d31f952b8eaa884fb2d46908a3de79f12 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sat, 9 Sep 2017 07:38:52 -0700 Subject: [PATCH 154/340] Fix handling of max packed arguments --- fmt/format.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/fmt/format.h b/fmt/format.h index fdbbe4ed..b2d2b023 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -1488,9 +1488,8 @@ class arg_store { Array data_; public: - static const uint64_t TYPES = - NUM_ARGS <= internal::MAX_PACKED_ARGS ? - internal::get_types() : -static_cast(NUM_ARGS); + static const uint64_t TYPES = IS_PACKED ? + internal::get_types() : -static_cast(NUM_ARGS); arg_store(const Args &... args) : data_(Array{{internal::make_arg(args)...}}) {} From 39bc319b3590207151a6c7e7b160b359f9b26ecc Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sun, 10 Sep 2017 07:35:32 -0700 Subject: [PATCH 155/340] Update test results --- README.rst | 39 +++++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/README.rst b/README.rst index 6c1a796e..c606bbf0 100644 --- a/README.rst +++ b/README.rst @@ -298,11 +298,12 @@ further details see the `source ================= ============= =========== Library Method Run Time, s ================= ============= =========== -EGLIBC 2.19 printf 1.30 -libstdc++ 4.8.2 std::ostream 1.85 -fmt 1.0 fmt::print 1.42 -tinyformat 2.0.1 tfm::printf 2.25 -Boost Format 1.54 boost::format 9.94 +libc printf 1.35 +libc++ std::ostream 3.42 +fmt 534bff7 fmt::print 1.56 +tinyformat 2.0.1 tfm::printf 3.73 +Boost Format 1.54 boost::format 8.44 +Folly Format folly::format 2.54 ================= ============= =========== As you can see ``boost::format`` is much slower than the alternative methods; this @@ -322,19 +323,20 @@ from `format-benchmark `_ tests compile time and code bloat for nontrivial projects. It generates 100 translation units and uses ``printf()`` or its alternative five times in each to simulate a medium sized project. The resulting -executable size and compile time (g++-4.8.1, Ubuntu GNU/Linux 13.10, -best of three) is shown in the following tables. +executable size and compile time (Apple LLVM version 8.1.0 (clang-802.0.42), +macOS Sierra, best of three) is shown in the following tables. **Optimized build (-O3)** ============ =============== ==================== ================== Method Compile Time, s Executable size, KiB Stripped size, KiB ============ =============== ==================== ================== -printf 2.6 41 30 -IOStreams 19.4 92 70 -fmt 46.8 46 34 -tinyformat 64.6 418 386 -Boost Format 222.8 990 923 +printf 2.3 29 26 +IOStreams 26.9 59 55 +fmt 38.0 37 34 +tinyformat 42.5 104 98 +Boost Format 112.2 774 751 +Folly Format 152.3 104 87 ============ =============== ==================== ================== As you can see, fmt has two times less overhead in terms of resulting @@ -346,14 +348,15 @@ Boost Format has by far the largest overheads. ============ =============== ==================== ================== Method Compile Time, s Executable size, KiB Stripped size, KiB ============ =============== ==================== ================== -printf 2.1 41 30 -IOStreams 19.7 86 62 -fmt 47.9 108 86 -tinyformat 27.7 234 190 -Boost Format 122.6 884 763 +printf 2.0 33 30 +IOStreams 25.4 56 52 +fmt 37.0 57 51 +tinyformat 30.2 88 82 +Boost Format 54.0 364 302 +Folly Format 107.1 438 424 ============ =============== ==================== ================== -``libc``, ``libstdc++`` and ``libfmt`` are all linked as shared +``libc``, ``lib(std)c++`` and ``libfmt`` are all linked as shared libraries to compare formatting function overhead only. Boost Format and tinyformat are header-only libraries so they don't provide any linkage options. From 5a8ae0bb0545d5fe4edcc53269c53287aeb28587 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Wed, 13 Sep 2017 08:36:06 -0700 Subject: [PATCH 156/340] Fix a warning --- fmt/printf.h | 1 - 1 file changed, 1 deletion(-) diff --git a/fmt/printf.h b/fmt/printf.h index 8c2095a3..ac4b33de 100644 --- a/fmt/printf.h +++ b/fmt/printf.h @@ -242,7 +242,6 @@ class printf_arg_formatter : public internal::arg_formatter_base { /** Formats a character. */ void operator()(Char value) { format_specs &fmt_spec = this->spec(); - basic_writer &w = this->writer(); if (fmt_spec.type_ && fmt_spec.type_ != 'c') return (*this)(static_cast(value)); fmt_spec.flags_ = 0; From 83dd2ab9191695b5d55a078af21b23c53c123298 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sat, 16 Sep 2017 15:30:13 -0700 Subject: [PATCH 157/340] Simplify dynamic_specs_handler --- fmt/format.h | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/fmt/format.h b/fmt/format.h index b2d2b023..8f323c4c 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -3238,22 +3238,24 @@ class dynamic_specs_handler: public specs_setter { template void on_dynamic_width(Id arg_id) { - set(specs_.width_ref, arg_id); + specs_.width_ref = make_arg_ref(arg_id); } template void on_dynamic_precision(Id arg_id) { - set(specs_.precision_ref, arg_id); + specs_.precision_ref = make_arg_ref(arg_id); } private: + using arg_ref = arg_ref; + template - void set(arg_ref &ref, Id arg_id) { - ref = arg_ref(arg_id); + arg_ref make_arg_ref(Id arg_id) { + return arg_ref(arg_id); } - void set(arg_ref &ref, auto_id) { - ref.kind = arg_ref::NONE; + arg_ref make_arg_ref(auto_id) { + return arg_ref(arg_ref::NONE); } dynamic_format_specs &specs_; @@ -3291,7 +3293,7 @@ Iterator parse_arg_id(Iterator it, Handler handler) { // format specifiers. template Iterator parse_format_specs(Iterator it, Handler &handler) { - typedef typename Iterator::value_type char_type; + using char_type = typename Iterator::value_type; // Parse fill and alignment. if (char_type c = *it) { auto p = it + 1; From ec4f5175f152ec2d342b7da794b2135cd0ecb167 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sat, 16 Sep 2017 16:50:40 -0700 Subject: [PATCH 158/340] Replace Range with ParseContext in parse() --- fmt/format.h | 60 +++++++++++++++++++++++++++------------------ fmt/time.h | 6 ++--- test/format-test.cc | 6 ++--- test/util-test.cc | 12 ++++----- 4 files changed, 48 insertions(+), 36 deletions(-) diff --git a/fmt/format.h b/fmt/format.h index 8f323c4c..c1f723ac 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -351,6 +351,8 @@ class basic_string_view { std::size_t size_; public: + using char_type = Char; + basic_string_view() : data_(0), size_(0) {} /** Constructs a string reference object from a C string and a size. */ @@ -388,6 +390,9 @@ class basic_string_view { /** Returns the string size. */ std::size_t size() const { return size_; } + const Char *begin() const { return data_; } + const Char *end() const { return data_ + size_; } + void remove_prefix(size_t n) { data_ += n; size_ -= n; @@ -425,9 +430,6 @@ class basic_string_view { typedef basic_string_view string_view; typedef basic_string_view wstring_view; -template -inline const Char *begin(basic_string_view s) { return s.data(); } - /** A formatting error such as invalid format string. */ class format_error : public std::runtime_error { public: @@ -776,7 +778,7 @@ class null_terminating_iterator { : ptr_(ptr), end_(end) {} explicit null_terminating_iterator(basic_string_view s) - : ptr_(s.data()), end_(s.data() + s.size()) {} + : ptr_(s.begin()), end_(s.end()) {} null_terminating_iterator &operator=(const Char *ptr) { assert(ptr <= end_); @@ -1324,7 +1326,7 @@ class value { // `printf_formatter` for `printf`. typename Context::template formatter_type f; auto it = f.parse(format); - format.remove_prefix(it - begin(format)); + format.remove_prefix(it - format.begin()); f.format(buffer, *static_cast(arg), ctx); } }; @@ -3230,11 +3232,19 @@ struct dynamic_format_specs : basic_format_specs { arg_ref precision_ref; }; -template -class dynamic_specs_handler: public specs_setter { +// Format spec handler that saves references to arguments representing dynamic +// width and precision to be resolved at formatting time. +// ParseContext: parsing context representing a sequence of format string +// characters and an argument counter for automatic indexing. +template +class dynamic_specs_handler : + public specs_setter { public: - dynamic_specs_handler(dynamic_format_specs &specs) - : specs_setter(specs), specs_(specs) {} + using char_type = typename ParseContext::char_type; + + dynamic_specs_handler( + dynamic_format_specs &specs, ParseContext &ctx) + : specs_setter(specs), specs_(specs), context_(ctx) {} template void on_dynamic_width(Id arg_id) { @@ -3247,7 +3257,7 @@ class dynamic_specs_handler: public specs_setter { } private: - using arg_ref = arg_ref; + using arg_ref = arg_ref; template arg_ref make_arg_ref(Id arg_id) { @@ -3255,10 +3265,12 @@ class dynamic_specs_handler: public specs_setter { } arg_ref make_arg_ref(auto_id) { + // TODO: get next index from context return arg_ref(arg_ref::NONE); } - dynamic_format_specs &specs_; + dynamic_format_specs &specs_; + ParseContext &context_; }; template @@ -3417,7 +3429,7 @@ const Char *do_format_arg(basic_buffer &buffer, if (*it == ':') { format.remove_prefix(1); if (visit(custom_formatter(buffer, format, ctx), arg)) - return begin(format); + return format.begin(); specs_checker> handler(specs_handler(specs, ctx), arg.type()); it = parse_format_specs(it + 1, handler); @@ -3466,12 +3478,12 @@ struct formatter< // Parses format specifiers stopping either at the end of the range or at the // terminating '}'. - template - auto parse(Range format) -> decltype(begin(format)) { - auto it = internal::null_terminating_iterator(format); - using handler_type = internal::dynamic_specs_handler; + template + auto parse(ParseContext &ctx) -> decltype(ctx.begin()) { + auto it = internal::null_terminating_iterator(ctx); + using handler_type = internal::dynamic_specs_handler; internal::specs_checker - handler(handler_type(specs_), internal::get_type()); + handler(handler_type(specs_, ctx), internal::get_type()); it = parse_format_specs(it, handler); return pointer_from(it); } @@ -3495,9 +3507,9 @@ template struct formatter::value>::type> : public formatter { - template - auto parse(Range format) -> decltype(begin(format)) { - return begin(format); + template + auto parse(ParseContext &ctx) -> decltype(ctx.begin()) { + return ctx.begin(); } }; @@ -3513,11 +3525,11 @@ struct formatter struct dynamic_formatter { - template - auto parse(Range format) -> decltype(begin(format)) { - auto it = internal::null_terminating_iterator(format); + template + auto parse(ParseContext &ctx) -> decltype(ctx.begin()) { + auto it = internal::null_terminating_iterator(ctx); // Checks are deferred to formatting time when the argument type is known. - internal::dynamic_specs_handler handler(specs_); + internal::dynamic_specs_handler handler(specs_, ctx); it = parse_format_specs(it, handler); return pointer_from(it); } diff --git a/fmt/time.h b/fmt/time.h index 648c60ef..c1687373 100644 --- a/fmt/time.h +++ b/fmt/time.h @@ -17,9 +17,9 @@ namespace fmt { template <> struct formatter { - template - auto parse(Range format) -> decltype(begin(format)) { - auto it = internal::null_terminating_iterator(format); + template + auto parse(ParseContext &ctx) -> decltype(ctx.begin()) { + auto it = internal::null_terminating_iterator(ctx); if (*it == ':') ++it; auto end = it; diff --git a/test/format-test.cc b/test/format-test.cc index 85dac3dc..7ceb4d4b 100644 --- a/test/format-test.cc +++ b/test/format-test.cc @@ -1233,9 +1233,9 @@ TEST(FormatterTest, FormatStringView) { namespace fmt { template <> struct formatter { - template - auto parse(Range format) -> decltype(begin(format)) { - return begin(format); + template + auto parse(ParseContext &ctx) -> decltype(ctx.begin()) { + return ctx.begin(); } void format(buffer &buf, const Date &d, context &) { diff --git a/test/util-test.cc b/test/util-test.cc index 17390c1c..c3387639 100644 --- a/test/util-test.cc +++ b/test/util-test.cc @@ -75,9 +75,9 @@ basic_arg make_arg(const T &value) { namespace fmt { template struct formatter { - template - auto parse(Range format) -> decltype(begin(format)) { - return begin(format); + template + auto parse(ParseContext &ctx) -> decltype(ctx.begin()) { + return ctx.begin(); } void format(basic_buffer &b, Test, basic_context &) { @@ -436,9 +436,9 @@ struct CustomContext { template struct formatter_type { - template - auto parse(Range range) -> decltype(begin(range)) { - return begin(range); + template + auto parse(ParseContext &ctx) -> decltype(ctx.begin()) { + return ctx.begin(); } void format(fmt::buffer &, const T &, CustomContext& ctx) { From 8cbf54473351badf709f26af4230ae7d431ef0a4 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sun, 17 Sep 2017 08:32:57 -0700 Subject: [PATCH 159/340] Add parse context --- fmt/format.h | 87 +++++++++++++++++++++-------------- fmt/printf.cc | 4 +- fmt/printf.h | 29 ++++++------ test/custom-formatter-test.cc | 4 +- test/ostream-test.cc | 2 +- test/util-test.cc | 13 +++--- 6 files changed, 79 insertions(+), 60 deletions(-) diff --git a/fmt/format.h b/fmt/format.h index c1f723ac..98f33e13 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -777,8 +777,9 @@ class null_terminating_iterator { null_terminating_iterator(const Char *ptr, const Char *end) : ptr_(ptr), end_(end) {} - explicit null_terminating_iterator(basic_string_view s) - : ptr_(s.begin()), end_(s.end()) {} + template + explicit null_terminating_iterator(const Range &r) + : ptr_(r.begin()), end_(r.end()) {} null_terminating_iterator &operator=(const Char *ptr) { assert(ptr <= end_); @@ -1102,8 +1103,7 @@ struct string_value { template struct custom_value { typedef void (*FormatFunc)( - basic_buffer &buffer, const void *arg, - basic_string_view& format, void *ctx); + basic_buffer &buffer, const void *arg, void *ctx); const void *value; FormatFunc format; @@ -1318,15 +1318,14 @@ class value { // Formats an argument of a custom type, such as a user-defined class. template static void format_custom_arg( - basic_buffer &buffer, const void *arg, - basic_string_view &format, void *context) { + basic_buffer &buffer, const void *arg, void *context) { Context &ctx = *static_cast(context); // Get the formatter type through the context to allow different contexts // have different extension points, e.g. `formatter` for `format` and // `printf_formatter` for `printf`. typename Context::template formatter_type f; - auto it = f.parse(format); - format.remove_prefix(it - format.begin()); + auto &&parse_ctx = ctx.get_parse_context(); + parse_ctx.advance_to(f.parse(parse_ctx)); f.format(buffer, *static_cast(arg), ctx); } }; @@ -1876,8 +1875,27 @@ class arg_formatter_base { } }; +template +class parse_context { + private: + basic_string_view format_str_; + + public: + using char_type = Char; + + explicit parse_context(basic_string_view format_str) + : format_str_(format_str) {} + + const Char *begin() const { return format_str_.begin(); } + const Char *end() const { return format_str_.end(); } + + void advance_to(const Char *p) { + format_str_.remove_prefix(p - begin()); + } +}; + template -class context_base { +class context_base : public parse_context{ private: basic_args args_; int next_arg_index_; @@ -1885,8 +1903,8 @@ class context_base { protected: typedef basic_arg format_arg; - explicit context_base(basic_args args) - : args_(args), next_arg_index_(0) {} + context_base(basic_string_view format_str, basic_args args) + : parse_context(format_str), args_(args), next_arg_index_(0) {} ~context_base() {} basic_args args() const { return args_; } @@ -1922,6 +1940,9 @@ class context_base { next_arg_index_ = -1; return true; } + + public: + parse_context &get_parse_context() { return *this; } }; } // namespace internal @@ -1952,8 +1973,7 @@ class arg_formatter : public internal::arg_formatter_base { /** Formats an argument of a custom (user-defined) type. */ void operator()(internal::custom_value c) { - basic_string_view format_str; - c.format(this->writer().buffer(), c.value, format_str, &ctx_); + c.format(this->writer().buffer(), c.value, &ctx_); } }; @@ -1984,7 +2004,9 @@ class basic_context : stored in the object so make sure they have appropriate lifetimes. \endrst */ - basic_context(basic_args args): Base(args) {} + basic_context( + basic_string_view format_str, basic_args args) + : Base(format_str, args) {} format_arg next_arg() { const char *error = 0; @@ -3001,16 +3023,14 @@ template class custom_formatter { private: basic_buffer &buffer_; - basic_string_view &format_; Context &ctx_; public: - custom_formatter(basic_buffer &buffer, basic_string_view &format, - Context &ctx) - : buffer_(buffer), format_(format), ctx_(ctx) {} + custom_formatter(basic_buffer &buffer,Context &ctx) + : buffer_(buffer), ctx_(ctx) {} bool operator()(internal::custom_value custom) { - custom.format(buffer_, custom.value, format_, &ctx_); + custom.format(buffer_, custom.value, &ctx_); return true; } @@ -3257,16 +3277,16 @@ class dynamic_specs_handler : } private: - using arg_ref = arg_ref; + using arg_ref_type = arg_ref; template - arg_ref make_arg_ref(Id arg_id) { - return arg_ref(arg_id); + arg_ref_type make_arg_ref(Id arg_id) { + return arg_ref_type(arg_id); } - arg_ref make_arg_ref(auto_id) { + arg_ref_type make_arg_ref(auto_id) { // TODO: get next index from context - return arg_ref(arg_ref::NONE); + return arg_ref_type(arg_ref_type::NONE); } dynamic_format_specs &specs_; @@ -3422,17 +3442,16 @@ Iterator parse_format_specs(Iterator it, Handler &handler) { template const Char *do_format_arg(basic_buffer &buffer, const basic_arg &arg, - basic_string_view format, Context &ctx) { - auto it = null_terminating_iterator(format); + auto it = null_terminating_iterator(ctx); basic_format_specs specs; if (*it == ':') { - format.remove_prefix(1); - if (visit(custom_formatter(buffer, format, ctx), arg)) - return format.begin(); + ctx.advance_to(pointer_from(++it)); + if (visit(custom_formatter(buffer, ctx), arg)) + return ctx.begin(); specs_checker> handler(specs_handler(specs, ctx), arg.type()); - it = parse_format_specs(it + 1, handler); + it = parse_format_specs(it, handler); } if (*it != '}') @@ -3595,8 +3614,8 @@ inline typename basic_context::format_arg template void vformat_to(basic_buffer &buffer, basic_string_view format_str, basic_args args) { - basic_context ctx(args); - auto start = internal::null_terminating_iterator(format_str); + basic_context ctx(format_str, args); + auto start = internal::null_terminating_iterator(ctx); auto it = start; using internal::pointer_from; while (*it) { @@ -3626,8 +3645,8 @@ void vformat_to(basic_buffer &buffer, basic_string_view format_str, } handler(ctx, arg); it = parse_arg_id(it, handler); - format_str.remove_prefix(pointer_from(it) - format_str.data()); - it = internal::do_format_arg(buffer, arg, format_str, ctx); + ctx.advance_to(pointer_from(it)); + it = internal::do_format_arg(buffer, arg, ctx); if (*it != '}') FMT_THROW(format_error(fmt::format("unknown format specifier"))); start = ++it; diff --git a/fmt/printf.cc b/fmt/printf.cc index c107c46b..53d4c0b9 100644 --- a/fmt/printf.cc +++ b/fmt/printf.cc @@ -14,7 +14,7 @@ FMT_FUNC int vfprintf(std::FILE *f, string_view format, printf_args args) { } #ifndef FMT_HEADER_ONLY -template void printf_context::format(string_view, buffer &); -template void printf_context::format(wstring_view, wbuffer &); +template void printf_context::format(buffer &); +template void printf_context::format(wbuffer &); #endif } diff --git a/fmt/printf.h b/fmt/printf.h index ac4b33de..eb9e39db 100644 --- a/fmt/printf.h +++ b/fmt/printf.h @@ -269,11 +269,10 @@ class printf_arg_formatter : public internal::arg_formatter_base { /** Formats an argument of a custom (user-defined) type. */ void operator()(internal::custom_value c) { - const Char format_str_data[] = {'}', '\0'}; - basic_string_view format_str = format_str_data; + const Char format_str[] = {'}', '\0'}; auto args = basic_args>(); - basic_context ctx(args); - c.format(this->writer().buffer(), c.value, format_str, &ctx); + basic_context ctx(basic_string_view(format_str), args); + c.format(this->writer().buffer(), c.value, &ctx); } }; @@ -283,9 +282,8 @@ class printf_context; template struct printf_formatter { - const Char *parse(basic_string_view s) { - return s.data(); - } + template + const Char *parse(ParseContext& ctx) { return ctx.begin(); } void format(basic_buffer &buf, const T &value, printf_context &) { internal::format_value(buf, value); @@ -329,11 +327,14 @@ class printf_context : appropriate lifetimes. \endrst */ - explicit printf_context(basic_args args): Base(args) {} + printf_context( + basic_string_view format_str, basic_args args) + : Base(format_str, args) {} + + using Base::get_parse_context; /** Formats stored arguments and writes the output to the buffer. */ - FMT_API void format( - basic_string_view format_str, basic_buffer &buffer); + FMT_API void format(basic_buffer &buffer); }; template @@ -415,9 +416,9 @@ unsigned printf_context::parse_header( } template -void printf_context::format( - basic_string_view format_str, basic_buffer &buffer) { - auto start = iterator(format_str); +void printf_context::format(basic_buffer &buffer) { + Base &base = *this; + auto start = iterator(base); auto it = start; using internal::pointer_from; while (*it) { @@ -519,7 +520,7 @@ void printf_context::format( template void printf(basic_buffer &buf, basic_string_view format, basic_args> args) { - printf_context(args).format(format, buf); + printf_context(format, args).format(buf); } typedef basic_args> printf_args; diff --git a/test/custom-formatter-test.cc b/test/custom-formatter-test.cc index b84db61e..e189fa4d 100644 --- a/test/custom-formatter-test.cc +++ b/test/custom-formatter-test.cc @@ -65,8 +65,8 @@ std::string custom_vsprintf( const char* format_str, fmt::basic_args args) { fmt::memory_buffer buffer; - CustomPrintfFormatter formatter(args); - formatter.format(format_str, buffer); + CustomPrintfFormatter formatter(format_str, args); + formatter.format(buffer); return std::string(buffer.data(), buffer.size()); } diff --git a/test/ostream-test.cc b/test/ostream-test.cc index b5deb6ad..cff83272 100644 --- a/test/ostream-test.cc +++ b/test/ostream-test.cc @@ -65,7 +65,7 @@ struct TestArgFormatter : fmt::arg_formatter { TEST(OStreamTest, CustomArg) { fmt::memory_buffer buffer; - fmt::context ctx((fmt::args())); + fmt::context ctx("", fmt::args()); fmt::format_specs spec; TestArgFormatter af(buffer, ctx, spec); visit(af, fmt::internal::make_arg(TestEnum())); diff --git a/test/util-test.cc b/test/util-test.cc index c3387639..5c276e31 100644 --- a/test/util-test.cc +++ b/test/util-test.cc @@ -448,8 +448,9 @@ struct CustomContext { bool called; - fmt::string_view format() { return ""; } - void advance_to(const char *) {} + fmt::internal::parse_context get_parse_context() { + return fmt::internal::parse_context(""); + } }; TEST(UtilTest, MakeValueWithCustomFormatter) { @@ -457,8 +458,7 @@ TEST(UtilTest, MakeValueWithCustomFormatter) { fmt::internal::value arg(t); CustomContext ctx = {false}; fmt::memory_buffer buffer; - fmt::string_view format_str; - arg.custom.format(buffer, &t, format_str, &ctx); + arg.custom.format(buffer, &t, &ctx); EXPECT_TRUE(ctx.called); } @@ -602,9 +602,8 @@ TEST(UtilTest, CustomArg) { testing::Invoke([&](fmt::internal::custom_value custom) { EXPECT_EQ(&test, custom.value); fmt::memory_buffer buffer; - fmt::context ctx((fmt::args())); - fmt::string_view format_str; - custom.format(buffer, &test, format_str, &ctx); + fmt::context ctx("", fmt::args()); + custom.format(buffer, &test, &ctx); EXPECT_EQ("test", std::string(buffer.data(), buffer.size())); return Visitor::Result(); })); From d45544d14e8c033179f23f460037f93c75c91bb3 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Wed, 27 Sep 2017 19:04:15 -0700 Subject: [PATCH 160/340] Fix width handling in dynamic formatting --- fmt/format.h | 83 ++++++++++++++++++++++++++++----------------- test/format-test.cc | 1 + 2 files changed, 52 insertions(+), 32 deletions(-) diff --git a/fmt/format.h b/fmt/format.h index 98f33e13..0035fa4e 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -1875,36 +1875,70 @@ class arg_formatter_base { } }; +// Parsing context representing a format string range being parsed and an +// argument counter for automatic indexing. template class parse_context { private: basic_string_view format_str_; + int next_arg_index_; + + protected: + bool check_no_auto_index(const char *&error) { + if (next_arg_index_ > 0) { + error = "cannot switch from automatic to manual argument indexing"; + return false; + } + next_arg_index_ = -1; + return true; + } public: using char_type = Char; + using iterator = const Char*; explicit parse_context(basic_string_view format_str) - : format_str_(format_str) {} + : format_str_(format_str), next_arg_index_(0) {} - const Char *begin() const { return format_str_.begin(); } - const Char *end() const { return format_str_.end(); } + // Returns an iterator to the beginning of the format string range being + // parsed. + iterator begin() const { return format_str_.begin(); } - void advance_to(const Char *p) { - format_str_.remove_prefix(p - begin()); + // Returns an iterator past the end of the format string range being parsed. + iterator end() const { return format_str_.end(); } + + // Advances the begin iterator to ``it``. + void advance_to(iterator it) { + format_str_.remove_prefix(it - begin()); } + + // Returns the next argument index. + unsigned next_arg_index(const char *&error) { + if (next_arg_index_ >= 0) + return internal::to_unsigned(next_arg_index_++); + error = "cannot switch from manual to automatic argument indexing"; + return 0; + } + + void check_arg_id(unsigned index) { + const char *error = 0; + if (!check_no_auto_index(error)) + FMT_THROW(format_error(error)); + } + + void check_arg_id(basic_string_view) {} }; template class context_base : public parse_context{ private: basic_args args_; - int next_arg_index_; protected: typedef basic_arg format_arg; context_base(basic_string_view format_str, basic_args args) - : parse_context(format_str), args_(args), next_arg_index_(0) {} + : parse_context(format_str), args_(args) {} ~context_base() {} basic_args args() const { return args_; } @@ -1924,23 +1958,6 @@ class context_base : public parse_context{ this->do_get_arg(arg_index, error) : format_arg(); } - // Returns the next argument index. - unsigned next_arg_index(const char *&error) { - if (next_arg_index_ >= 0) - return internal::to_unsigned(next_arg_index_++); - error = "cannot switch from manual to automatic argument indexing"; - return 0; - } - - bool check_no_auto_index(const char *&error) { - if (next_arg_index_ > 0) { - error = "cannot switch from automatic to manual argument indexing"; - return false; - } - next_arg_index_ = -1; - return true; - } - public: parse_context &get_parse_context() { return *this; } }; @@ -2018,7 +2035,6 @@ class basic_context : format_arg get_arg(unsigned arg_index) { const char *error = 0; - this->check_no_auto_index(error); format_arg arg = this->do_get_arg(arg_index, error); if (error) FMT_THROW(format_error(error)); @@ -3221,6 +3237,7 @@ class specs_handler: public specs_setter { template basic_arg get_arg(Id arg_id) { + context_.check_arg_id(arg_id); return context_.get_arg(arg_id); } @@ -3254,8 +3271,6 @@ struct dynamic_format_specs : basic_format_specs { // Format spec handler that saves references to arguments representing dynamic // width and precision to be resolved at formatting time. -// ParseContext: parsing context representing a sequence of format string -// characters and an argument counter for automatic indexing. template class dynamic_specs_handler : public specs_setter { @@ -3285,8 +3300,11 @@ class dynamic_specs_handler : } arg_ref_type make_arg_ref(auto_id) { - // TODO: get next index from context - return arg_ref_type(arg_ref_type::NONE); + const char *error = 0; + auto index = context_.next_arg_index(error); + if (error) + FMT_THROW(format_error(error)); + return arg_ref_type(index); } dynamic_format_specs &specs_; @@ -3477,7 +3495,6 @@ static void handle_dynamic_spec( Spec &value, arg_ref ref, basic_context &ctx) { switch (ref.kind) { case arg_ref::NONE: - // Do nothing. break; case arg_ref::INDEX: internal::set_dynamic_spec(value, ctx.get_arg(ref.index)); @@ -3485,7 +3502,6 @@ static void handle_dynamic_spec( case arg_ref::NAME: internal::set_dynamic_spec(value, ctx.get_arg(ref.name)); break; - // TODO: handle automatic numbering } } } // namespace internal @@ -3635,7 +3651,10 @@ void vformat_to(basic_buffer &buffer, basic_string_view format_str, id_handler(Context &c, basic_arg &a): context(c), arg(a) {} void operator()() { arg = context.next_arg(); } - void operator()(unsigned id) { arg = context.get_arg(id); } + void operator()(unsigned id) { + context.check_arg_id(id); + arg = context.get_arg(id); + } void operator()(basic_string_view id) { arg = context.get_arg(id); } diff --git a/test/format-test.cc b/test/format-test.cc index 7ceb4d4b..f50f1b3d 100644 --- a/test/format-test.cc +++ b/test/format-test.cc @@ -1561,6 +1561,7 @@ TEST(FormatTest, DynamicFormatter) { auto str = variant("foo"); EXPECT_EQ("42", format("{:d}", num)); EXPECT_EQ("foo", format("{:s}", str)); + EXPECT_EQ(" 42 foo ", format("{:{}} {:{}}", num, 3, str, 4)); EXPECT_THROW_MSG(format("{:=}", str), format_error, "format specifier '=' requires numeric argument"); EXPECT_THROW_MSG(format("{:+}", str), From 643fb0662e5edd0fd9646f689589d6cc99bf6433 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Wed, 27 Sep 2017 21:18:37 -0700 Subject: [PATCH 161/340] Check for argument indexing switch --- fmt/format.h | 1 + test/format-test.cc | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/fmt/format.h b/fmt/format.h index 0035fa4e..5c527a4e 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -3296,6 +3296,7 @@ class dynamic_specs_handler : template arg_ref_type make_arg_ref(Id arg_id) { + context_.check_arg_id(arg_id); return arg_ref_type(arg_id); } diff --git a/test/format-test.cc b/test/format-test.cc index f50f1b3d..b1156108 100644 --- a/test/format-test.cc +++ b/test/format-test.cc @@ -1562,6 +1562,10 @@ TEST(FormatTest, DynamicFormatter) { EXPECT_EQ("42", format("{:d}", num)); EXPECT_EQ("foo", format("{:s}", str)); EXPECT_EQ(" 42 foo ", format("{:{}} {:{}}", num, 3, str, 4)); + EXPECT_THROW_MSG(format("{0:{}}", num), + format_error, "cannot switch from manual to automatic argument indexing"); + EXPECT_THROW_MSG(format("{:{0}}", num), + format_error, "cannot switch from automatic to manual argument indexing"); EXPECT_THROW_MSG(format("{:=}", str), format_error, "format specifier '=' requires numeric argument"); EXPECT_THROW_MSG(format("{:+}", str), From be5b4552d97e8d578cfe6fc0d83802bac857f6d6 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Wed, 27 Sep 2017 22:40:58 -0700 Subject: [PATCH 162/340] Make null_terminating_iterator more iteratory --- fmt/format.h | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/fmt/format.h b/fmt/format.h index 5c527a4e..877105bd 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -769,8 +769,11 @@ const Char *pointer_from(null_terminating_iterator it); template class null_terminating_iterator { public: - typedef Char value_type; - typedef std::ptrdiff_t difference_type; + using difference_type = std::ptrdiff_t; + using value_type = Char; + using pointer = const Char*; + using reference = const Char&; + using iterator_category = std::random_access_iterator_tag; null_terminating_iterator() : ptr_(0), end_(0) {} @@ -3314,7 +3317,7 @@ class dynamic_specs_handler : template Iterator parse_arg_id(Iterator it, Handler handler) { - typedef typename Iterator::value_type char_type; + using char_type = typename std::iterator_traits::value_type; char_type c = *it; if (c == '}' || c == ':') { handler(); From d5e918b61f941a26267a2e8a34738f901ed96606 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Thu, 28 Sep 2017 08:46:47 -0700 Subject: [PATCH 163/340] Detect C++14 compiler support --- CMakeLists.txt | 4 +- fmt/CMakeLists.txt | 2 +- support/cmake/{cxx11.cmake => cxx14.cmake} | 44 +++++++++++----------- test/CMakeLists.txt | 12 +++--- test/add-subdirectory-test/CMakeLists.txt | 4 +- test/compile-test/CMakeLists.txt | 2 +- test/find-package-test/CMakeLists.txt | 4 +- 7 files changed, 36 insertions(+), 36 deletions(-) rename support/cmake/{cxx11.cmake => cxx14.cmake} (64%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 353940f8..47319e1d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -23,7 +23,7 @@ option(FMT_PEDANTIC "Enable extra warnings and expensive tests." OFF) option(FMT_DOC "Generate the doc target." ${MASTER_PROJECT}) option(FMT_INSTALL "Generate the install target." ${MASTER_PROJECT}) option(FMT_TEST "Generate the test target." ${MASTER_PROJECT}) -option(FMT_USE_CPP11 "Enable the addition of C++11 compiler flags." ON) +option(FMT_USE_CPP14 "Enable the addition of C++14 compiler flags." ON) project(FMT) @@ -43,7 +43,7 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/support/cmake") -include(cxx11) +include(cxx14) if (CMAKE_COMPILER_IS_GNUCXX OR (CMAKE_CXX_COMPILER_ID MATCHES "Clang")) set(PEDANTIC_COMPILE_FLAGS -Wall -Wextra -Wshadow -pedantic) diff --git a/fmt/CMakeLists.txt b/fmt/CMakeLists.txt index c2c7f0fe..ac3ad4ea 100644 --- a/fmt/CMakeLists.txt +++ b/fmt/CMakeLists.txt @@ -16,7 +16,7 @@ if (FMT_CPPFORMAT) endif () # Starting with cmake 3.1 the CXX_STANDARD property can be used instead. -target_compile_options(fmt PUBLIC ${CPP11_FLAG}) +target_compile_options(fmt PUBLIC ${CPP14_FLAG}) if (FMT_PEDANTIC) target_compile_options(fmt PRIVATE ${PEDANTIC_COMPILE_FLAGS}) endif () diff --git a/support/cmake/cxx11.cmake b/support/cmake/cxx14.cmake similarity index 64% rename from support/cmake/cxx11.cmake rename to support/cmake/cxx14.cmake index 21d12543..7b427a37 100644 --- a/support/cmake/cxx11.cmake +++ b/support/cmake/cxx14.cmake @@ -1,55 +1,55 @@ -# C++11 feature support detection +# C++14 feature support detection -if (NOT FMT_USE_CPP11) +if (NOT FMT_USE_CPP14) return() endif () include(CheckCXXCompilerFlag) -if (FMT_USE_CPP11) - check_cxx_compiler_flag(-std=c++11 HAVE_STD_CPP11_FLAG) - if (HAVE_STD_CPP11_FLAG) - # Check if including cmath works with -std=c++11 and -O3. +if (FMT_USE_CPP14) + check_cxx_compiler_flag(-std=c++14 HAVE_STD_CPP14_FLAG) + if (HAVE_STD_CPP14_FLAG) + # Check if including cmath works with -std=c++14 and -O3. # It may not in MinGW due to bug http://ehc.ac/p/mingw/bugs/2250/. - set(CMAKE_REQUIRED_FLAGS "-std=c++11 -O3") + set(CMAKE_REQUIRED_FLAGS "-std=c++14 -O3") check_cxx_source_compiles(" #include - int main() {}" FMT_CPP11_CMATH) - # Check if including works with -std=c++11. + int main() {}" FMT_CPP14_CMATH) + # Check if including works with -std=c++14. # It may not in MinGW due to bug http://sourceforge.net/p/mingw/bugs/2024/. check_cxx_source_compiles(" #include - int main() {}" FMT_CPP11_UNISTD_H) - # Check if snprintf works with -std=c++11. It may not in MinGW. + int main() {}" FMT_CPP14_UNISTD_H) + # Check if snprintf works with -std=c++14. It may not in MinGW. check_cxx_source_compiles(" #include int main() { char buffer[10]; snprintf(buffer, 10, \"foo\"); - }" FMT_CPP11_SNPRINTF) - if (FMT_CPP11_CMATH AND FMT_CPP11_UNISTD_H AND FMT_CPP11_SNPRINTF) - set(CPP11_FLAG -std=c++11) + }" FMT_CPP14_SNPRINTF) + if (FMT_CPP14_CMATH AND FMT_CPP14_UNISTD_H AND FMT_CPP14_SNPRINTF) + set(CPP14_FLAG -std=c++14) else () - check_cxx_compiler_flag(-std=gnu++11 HAVE_STD_GNUPP11_FLAG) - if (HAVE_STD_CPP11_FLAG) - set(CPP11_FLAG -std=gnu++11) + check_cxx_compiler_flag(-std=gnu++14 HAVE_STD_GNUPP14_FLAG) + if (HAVE_STD_CPP14_FLAG) + set(CPP14_FLAG -std=gnu++14) endif () endif () set(CMAKE_REQUIRED_FLAGS ) else () - check_cxx_compiler_flag(-std=c++0x HAVE_STD_CPP0X_FLAG) - if (HAVE_STD_CPP0X_FLAG) - set(CPP11_FLAG -std=c++0x) + check_cxx_compiler_flag(-std=c++1y HAVE_STD_CPP1Y_FLAG) + if (HAVE_STD_CPP1Y_FLAG) + set(CPP14_FLAG -std=c++1y) endif () endif () endif () if (CMAKE_CXX_STANDARD) # Don't use -std compiler flag if CMAKE_CXX_STANDARD is specified. - set(CPP11_FLAG ) + set(CPP14_FLAG ) endif () -set(CMAKE_REQUIRED_FLAGS ${CPP11_FLAG}) +set(CMAKE_REQUIRED_FLAGS ${CPP14_FLAG}) # Check if variadic templates are working and not affected by GCC bug 39653: # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=39653 diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 459a77dd..b99925fa 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -7,7 +7,7 @@ # at http://code.google.com/p/googletest/wiki/FAQ for more details. add_library(gmock STATIC gmock-gtest-all.cc gmock/gmock.h gtest/gtest.h gtest/gtest-spi.h) -target_compile_options(gmock PUBLIC ${CPP11_FLAG}) +target_compile_options(gmock PUBLIC ${CPP14_FLAG}) target_compile_definitions(gmock PUBLIC GTEST_HAS_STD_WSTRING=1) target_include_directories(gmock PUBLIC .) @@ -120,7 +120,7 @@ endif () check_cxx_compiler_flag(-fno-exceptions HAVE_FNO_EXCEPTIONS_FLAG) if (HAVE_FNO_EXCEPTIONS_FLAG) add_library(noexception-test ../fmt/format.cc) - target_compile_options(noexception-test PUBLIC ${CPP11_FLAG}) + target_compile_options(noexception-test PUBLIC ${CPP14_FLAG}) target_include_directories(noexception-test PRIVATE ${PROJECT_SOURCE_DIR}) target_compile_options(noexception-test PRIVATE -fno-exceptions) endif () @@ -129,7 +129,7 @@ if (FMT_PEDANTIC) # Test that the library compiles without windows.h. if (CMAKE_SYSTEM_NAME STREQUAL "Windows") add_library(no-windows-h-test ../fmt/format.cc) - target_compile_options(no-windows-h-test PUBLIC ${CPP11_FLAG}) + target_compile_options(no-windows-h-test PUBLIC ${CPP14_FLAG}) target_include_directories(no-windows-h-test PRIVATE ${PROJECT_SOURCE_DIR}) target_compile_definitions(no-windows-h-test PRIVATE FMT_USE_WINDOWS_H=0) endif () @@ -142,7 +142,7 @@ if (FMT_PEDANTIC) --build-makeprogram ${CMAKE_MAKE_PROGRAM} --build-options "-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}" - "-DCPP11_FLAG=${CPP11_FLAG}" + "-DCPP14_FLAG=${CPP14_FLAG}" "-DSUPPORTS_USER_DEFINED_LITERALS=${SUPPORTS_USER_DEFINED_LITERALS}") # test if the targets are findable from the build directory @@ -155,7 +155,7 @@ if (FMT_PEDANTIC) --build-makeprogram ${CMAKE_MAKE_PROGRAM} --build-options "-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}" - "-DCPP11_FLAG=${CPP11_FLAG}" + "-DCPP14_FLAG=${CPP14_FLAG}" "-DFMT_DIR=${PROJECT_BINARY_DIR}" "-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}") @@ -169,6 +169,6 @@ if (FMT_PEDANTIC) --build-makeprogram ${CMAKE_MAKE_PROGRAM} --build-options "-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}" - "-DCPP11_FLAG=${CPP11_FLAG}" + "-DCPP14_FLAG=${CPP14_FLAG}" "-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}") endif () diff --git a/test/add-subdirectory-test/CMakeLists.txt b/test/add-subdirectory-test/CMakeLists.txt index e99bc673..bb02888a 100644 --- a/test/add-subdirectory-test/CMakeLists.txt +++ b/test/add-subdirectory-test/CMakeLists.txt @@ -5,11 +5,11 @@ project(fmt-test) add_subdirectory(../.. fmt) add_executable(library-test "main.cc") -target_compile_options(library-test PUBLIC ${CPP11_FLAG}) +target_compile_options(library-test PUBLIC ${CPP14_FLAG}) target_link_libraries(library-test fmt) if (TARGET fmt-header-only) add_executable(header-only-test "main.cc") - target_compile_options(header-only-test PUBLIC ${CPP11_FLAG}) + target_compile_options(header-only-test PUBLIC ${CPP14_FLAG}) target_link_libraries(header-only-test fmt-header-only) endif () diff --git a/test/compile-test/CMakeLists.txt b/test/compile-test/CMakeLists.txt index 4e90fb1f..775b4067 100644 --- a/test/compile-test/CMakeLists.txt +++ b/test/compile-test/CMakeLists.txt @@ -4,7 +4,7 @@ cmake_minimum_required(VERSION 2.8) include(CheckCXXSourceCompiles) set(CMAKE_REQUIRED_INCLUDES ${CMAKE_CURRENT_SOURCE_DIR}/../..) -set(CMAKE_REQUIRED_FLAGS ${CPP11_FLAG}) +set(CMAKE_REQUIRED_FLAGS ${CPP14_FLAG}) function (generate_source result fragment) set(${result} " diff --git a/test/find-package-test/CMakeLists.txt b/test/find-package-test/CMakeLists.txt index 54180419..a57de003 100644 --- a/test/find-package-test/CMakeLists.txt +++ b/test/find-package-test/CMakeLists.txt @@ -5,11 +5,11 @@ project(fmt-test) find_package(FMT REQUIRED) add_executable(library-test main.cc) -target_compile_options(library-test PUBLIC ${CPP11_FLAG}) +target_compile_options(library-test PUBLIC ${CPP14_FLAG}) target_link_libraries(library-test fmt) if (TARGET fmt-header-only) add_executable(header-only-test main.cc) - target_compile_options(header-only-test PUBLIC ${CPP11_FLAG}) + target_compile_options(header-only-test PUBLIC ${CPP14_FLAG}) target_link_libraries(header-only-test fmt-header-only) endif () From 17f93fe0842f0b7e7abd8b0340509becb711a167 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Fri, 29 Sep 2017 12:26:57 -0700 Subject: [PATCH 164/340] Make basic_string_view ctors constexpr --- fmt/format.h | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/fmt/format.h b/fmt/format.h index 877105bd..3cf25848 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -353,10 +353,11 @@ class basic_string_view { public: using char_type = Char; - basic_string_view() : data_(0), size_(0) {} + constexpr basic_string_view() noexcept : data_(0), size_(0) {} /** Constructs a string reference object from a C string and a size. */ - basic_string_view(const Char *s, std::size_t size) : data_(s), size_(size) {} + constexpr basic_string_view(const Char *s, std::size_t size) noexcept + : data_(s), size_(size) {} /** \rst @@ -364,7 +365,7 @@ class basic_string_view { the size with ``std::char_traits::length``. \endrst */ - basic_string_view(const Char *s) + constexpr basic_string_view(const Char *s) : data_(s), size_(std::char_traits::length(s)) {} /** @@ -372,7 +373,7 @@ class basic_string_view { Constructs a string reference from an ``std::string`` object. \endrst */ - basic_string_view(const std::basic_string &s) + constexpr basic_string_view(const std::basic_string &s) noexcept : data_(s.c_str()), size_(s.size()) {} /** From 1b5ccf6c13cab30f57d4dbc2e71a32594c30809f Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sun, 15 Oct 2017 16:54:47 -0700 Subject: [PATCH 165/340] Make parse_arg_id constexpr --- fmt/format.h | 48 +++++++++++++++++++++++++++------------------ test/format-test.cc | 37 ++++++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+), 19 deletions(-) diff --git a/fmt/format.h b/fmt/format.h index 3cf25848..370b6fc3 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -365,7 +365,7 @@ class basic_string_view { the size with ``std::char_traits::length``. \endrst */ - constexpr basic_string_view(const Char *s) + basic_string_view(const Char *s) : data_(s), size_(std::char_traits::length(s)) {} /** @@ -389,7 +389,7 @@ class basic_string_view { const Char *data() const { return data_; } /** Returns the string size. */ - std::size_t size() const { return size_; } + constexpr std::size_t size() const { return size_; } const Char *begin() const { return data_; } const Char *end() const { return data_ + size_; } @@ -762,7 +762,7 @@ template class null_terminating_iterator; template -const Char *pointer_from(null_terminating_iterator it); +constexpr const Char *pointer_from(null_terminating_iterator it); // An iterator that produces a null terminator on *end. This simplifies parsing // and allows comparing the performance of processing a null-terminated string @@ -840,10 +840,10 @@ class null_terminating_iterator { }; template -const T *pointer_from(const T *p) { return p; } +constexpr const T *pointer_from(const T *p) { return p; } template -const Char *pointer_from(null_terminating_iterator it) { +constexpr const Char *pointer_from(null_terminating_iterator it) { return it.ptr_; } @@ -3012,7 +3012,7 @@ void arg(wstring_view, const internal::named_arg&) namespace fmt { namespace internal { template -inline bool is_name_start(Char c) { +constexpr bool is_name_start(Char c) { return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || '_' == c; } @@ -3020,7 +3020,7 @@ inline bool is_name_start(Char c) { // This function assumes that the first character of it is a digit and a // presence of a non-digit character at the end. template -unsigned parse_nonnegative_int(Iterator &it) { +constexpr unsigned parse_nonnegative_int(Iterator &it) { assert('0' <= *it && *it <= '9'); unsigned value = 0; do { @@ -3316,8 +3316,14 @@ class dynamic_specs_handler : ParseContext &context_; }; +struct error_handler { + void on_error(const char *message) { + FMT_THROW(format_error(message)); + } +}; + template -Iterator parse_arg_id(Iterator it, Handler handler) { +constexpr Iterator parse_arg_id(Iterator it, Handler& handler) { using char_type = typename std::iterator_traits::value_type; char_type c = *it; if (c == '}' || c == ':') { @@ -3326,13 +3332,17 @@ Iterator parse_arg_id(Iterator it, Handler handler) { } if (c >= '0' && c <= '9') { unsigned index = parse_nonnegative_int(it); - if (*it != '}' && *it != ':') - FMT_THROW(format_error("invalid format string")); + if (*it != '}' && *it != ':') { + handler.on_error("invalid format string"); + return it; + } handler(index); return it; } - if (!is_name_start(c)) - FMT_THROW(format_error("invalid format string")); + if (!is_name_start(c)) { + handler.on_error("invalid format string"); + return it; + } auto start = it; do { c = *++it; @@ -3413,7 +3423,7 @@ Iterator parse_format_specs(Iterator it, Handler &handler) { if ('0' <= *it && *it <= '9') { handler.on_width(parse_nonnegative_int(it)); } else if (*it == '{') { - struct width_handler { + struct width_handler : error_handler { explicit width_handler(Handler &h) : handler(h) {} void operator()() { handler.on_dynamic_width(auto_id()); } @@ -3423,8 +3433,8 @@ Iterator parse_format_specs(Iterator it, Handler &handler) { } Handler &handler; - }; - it = parse_arg_id(it + 1, width_handler(handler)); + } wh(handler); + it = parse_arg_id(it + 1, wh); if (*it++ != '}') FMT_THROW(format_error("invalid format string")); } @@ -3435,7 +3445,7 @@ Iterator parse_format_specs(Iterator it, Handler &handler) { if ('0' <= *it && *it <= '9') { handler.on_precision(parse_nonnegative_int(it)); } else if (*it == '{') { - struct precision_handler { + struct precision_handler : error_handler { explicit precision_handler(Handler &h) : handler(h) {} void operator()() { handler.on_dynamic_precision(auto_id()); } @@ -3445,8 +3455,8 @@ Iterator parse_format_specs(Iterator it, Handler &handler) { } Handler &handler; - }; - it = parse_arg_id(it + 1, precision_handler(handler)); + } ph(handler); + it = parse_arg_id(it + 1, ph); if (*it++ != '}') FMT_THROW(format_error("invalid format string")); } else { @@ -3652,7 +3662,7 @@ void vformat_to(basic_buffer &buffer, basic_string_view format_str, buffer.append(pointer_from(start), pointer_from(it) - 1); basic_arg arg; - struct id_handler { + struct id_handler : internal::error_handler { id_handler(Context &c, basic_arg &a): context(c), arg(a) {} void operator()() { arg = context.next_arg(); } diff --git a/test/format-test.cc b/test/format-test.cc index b1156108..a857f7ed 100644 --- a/test/format-test.cc +++ b/test/format-test.cc @@ -1581,3 +1581,40 @@ TEST(FormatTest, DynamicFormatter) { EXPECT_THROW_MSG(format("{:.2}", num), format_error, "precision not allowed in integer format specifier"); } + +struct TestHandler { + enum Result { NONE, EMPTY, INDEX, NAME, ERROR }; + Result result = NONE; + unsigned index = 0; + string_view name; + + constexpr void operator()() { result = EMPTY; } + + constexpr void operator()(unsigned index) { + result = INDEX; + this->index = index; + } + + constexpr void operator()(string_view name) { + result = NAME; + this->name = name; + } + + constexpr void on_error(const char *) { result = ERROR; } +}; + +constexpr TestHandler parse_arg_id(const char* id) { + TestHandler h; + fmt::internal::parse_arg_id(id, h); + return h; +} + +TEST(FormatTest, ConstexprParseArgId) { + static_assert(parse_arg_id(":").result == TestHandler::EMPTY, ""); + static_assert(parse_arg_id("}").result == TestHandler::EMPTY, ""); + static_assert(parse_arg_id("42:").result == TestHandler::INDEX, ""); + static_assert(parse_arg_id("42:").index == 42, ""); + static_assert(parse_arg_id("foo:").result == TestHandler::NAME, ""); + static_assert(parse_arg_id("foo:").name.size() == 3, ""); + static_assert(parse_arg_id("!").result == TestHandler::ERROR, ""); +} From 3785afc5a3f7f27cd11ade8c7371eecd2b02fa81 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sun, 15 Oct 2017 17:15:01 -0700 Subject: [PATCH 166/340] Pass errors to handler instead of throwing (#566) --- .travis.yml | 15 ++++++++++-- fmt/format.h | 49 +++++++++++++++++++++++++-------------- support/cmake/cxx14.cmake | 1 + support/travis-build.py | 6 ++--- 4 files changed, 48 insertions(+), 23 deletions(-) diff --git a/.travis.yml b/.travis.yml index 56a704c5..aa734f7d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,13 +14,24 @@ env: 6pxmyzLHSn1ZR7OX5rfPvwM3tOyZ3H0= matrix: - BUILD=Doc - - BUILD=Debug STANDARD=0x - - BUILD=Release STANDARD=0x + - BUILD=Debug STANDARD=14 + - BUILD=Release STANDARD=14 matrix: exclude: - os: osx env: BUILD=Doc +# Install gcc-6 for extended constexpr support. +addons: + apt: + sources: + - ubuntu-toolchain-r-test + packages: + - g++-6 + +before_install: + - export CXX=g++-6 + script: - support/travis-build.py diff --git a/fmt/format.h b/fmt/format.h index 370b6fc3..7d88a3a2 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -3100,9 +3100,15 @@ struct precision_handler { } }; +struct error_handler { + void on_error(const char *message) { + FMT_THROW(format_error(message)); + } +}; + // A format specifier handler that sets fields in basic_format_specs. template -class specs_setter { +class specs_setter : public error_handler { public: explicit specs_setter(basic_format_specs &specs): specs_(specs) {} @@ -3316,12 +3322,6 @@ class dynamic_specs_handler : ParseContext &context_; }; -struct error_handler { - void on_error(const char *message) { - FMT_THROW(format_error(message)); - } -}; - template constexpr Iterator parse_arg_id(Iterator it, Handler& handler) { using char_type = typename std::iterator_traits::value_type; @@ -3358,7 +3358,7 @@ constexpr Iterator parse_arg_id(Iterator it, Handler& handler) { // format specifiers. template Iterator parse_format_specs(Iterator it, Handler &handler) { - using char_type = typename Iterator::value_type; + using char_type = typename std::iterator_traits::value_type; // Parse fill and alignment. if (char_type c = *it) { auto p = it + 1; @@ -3382,8 +3382,10 @@ Iterator parse_format_specs(Iterator it, Handler &handler) { handler.on_align(align); if (p != it) { if (c == '}') break; - if (c == '{') - FMT_THROW(format_error("invalid fill character '{'")); + if (c == '{') { + handler.on_error("invalid fill character '{'"); + return it; + } it += 2; handler.on_fill(c); } else ++it; @@ -3423,7 +3425,7 @@ Iterator parse_format_specs(Iterator it, Handler &handler) { if ('0' <= *it && *it <= '9') { handler.on_width(parse_nonnegative_int(it)); } else if (*it == '{') { - struct width_handler : error_handler { + struct width_handler { explicit width_handler(Handler &h) : handler(h) {} void operator()() { handler.on_dynamic_width(auto_id()); } @@ -3432,11 +3434,17 @@ Iterator parse_format_specs(Iterator it, Handler &handler) { handler.on_dynamic_width(id); } + void on_error(const char *message) { + handler.on_error(message); + } + Handler &handler; } wh(handler); it = parse_arg_id(it + 1, wh); - if (*it++ != '}') - FMT_THROW(format_error("invalid format string")); + if (*it++ != '}') { + handler.on_error("invalid format string"); + return it; + } } // Parse precision. @@ -3445,7 +3453,7 @@ Iterator parse_format_specs(Iterator it, Handler &handler) { if ('0' <= *it && *it <= '9') { handler.on_precision(parse_nonnegative_int(it)); } else if (*it == '{') { - struct precision_handler : error_handler { + struct precision_handler { explicit precision_handler(Handler &h) : handler(h) {} void operator()() { handler.on_dynamic_precision(auto_id()); } @@ -3454,13 +3462,20 @@ Iterator parse_format_specs(Iterator it, Handler &handler) { handler.on_dynamic_precision(id); } + void on_error(const char *message) { + handler.on_error(message); + } + Handler &handler; } ph(handler); it = parse_arg_id(it + 1, ph); - if (*it++ != '}') - FMT_THROW(format_error("invalid format string")); + if (*it++ != '}') { + handler.on_error("invalid format string"); + return it; + } } else { - FMT_THROW(format_error("missing precision specifier")); + handler.on_error("missing precision specifier"); + return it; } handler.end_precision(); } diff --git a/support/cmake/cxx14.cmake b/support/cmake/cxx14.cmake index 7b427a37..c86cf508 100644 --- a/support/cmake/cxx14.cmake +++ b/support/cmake/cxx14.cmake @@ -49,6 +49,7 @@ if (CMAKE_CXX_STANDARD) set(CPP14_FLAG ) endif () +message(STATUS "CPP14_FLAG: ${CPP14_FLAG}") set(CMAKE_REQUIRED_FLAGS ${CPP14_FLAG}) # Check if variadic templates are working and not affected by GCC bug 39653: diff --git a/support/travis-build.py b/support/travis-build.py index 91017792..fc61aa72 100755 --- a/support/travis-build.py +++ b/support/travis-build.py @@ -89,10 +89,8 @@ common_cmake_flags = [ '-DCMAKE_INSTALL_PREFIX=' + install_dir, '-DCMAKE_BUILD_TYPE=' + build ] extra_cmake_flags = [] -if standard != '0x': - extra_cmake_flags = [ - '-DCMAKE_CXX_FLAGS=-std=c++' + standard, '-DFMT_USE_CPP11=OFF' - ] +if standard != '14': + extra_cmake_flags = ['-DCMAKE_CXX_FLAGS=-std=c++' + standard] check_call(['cmake', '-DFMT_DOC=OFF', '-DFMT_PEDANTIC=ON', fmt_dir] + common_cmake_flags + extra_cmake_flags, cwd=build_dir) From 7174de0d79093c7e1b011e18af4b756a74a06561 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Wed, 18 Oct 2017 06:36:08 -0700 Subject: [PATCH 167/340] Fix contexpr-ness of pointer_from --- fmt/format.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fmt/format.h b/fmt/format.h index 7d88a3a2..800daa95 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -832,7 +832,7 @@ class null_terminating_iterator { return ptr_ >= other.ptr_; } - friend const Char *pointer_from(null_terminating_iterator it); + friend constexpr const Char *pointer_from(null_terminating_iterator it); private: const Char *ptr_; From b8f85f671f840733056a00c4ed708a6800e9361d Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Wed, 18 Oct 2017 08:15:10 -0700 Subject: [PATCH 168/340] Use Visual Studio 2017 image on appveyor --- support/appveyor-build.py | 4 ++-- support/appveyor.yml | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/support/appveyor-build.py b/support/appveyor-build.py index 3b747f3c..cd6324fe 100755 --- a/support/appveyor-build.py +++ b/support/appveyor-build.py @@ -20,8 +20,8 @@ if build == 'mingw': else: # Add MSBuild 14.0 to PATH as described in # http://help.appveyor.com/discussions/problems/2229-v140-not-found-on-vs2105rc. - os.environ['PATH'] = r'C:\Program Files (x86)\MSBuild\14.0\Bin;' + path - generator = 'Visual Studio 14 2015' + os.environ['PATH'] = r'C:\Program Files (x86)\MSBuild\15.0\Bin;' + path + generator = 'Visual Studio 15 2017' if platform == 'x64': generator += ' Win64' cmake_command.append('-G' + generator) diff --git a/support/appveyor.yml b/support/appveyor.yml index a651c525..71c5349f 100644 --- a/support/appveyor.yml +++ b/support/appveyor.yml @@ -2,6 +2,8 @@ configuration: - Debug - Release +image: Visual Studio 2017 + environment: CTEST_OUTPUT_ON_FAILURE: 1 matrix: From 62616b88a66a71423c4a26eecef063020891cd4a Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Thu, 19 Oct 2017 06:06:13 -0700 Subject: [PATCH 169/340] Workaround a bug in MSVC's constexpr handling --- fmt/format.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/fmt/format.h b/fmt/format.h index 800daa95..7110827e 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -3024,7 +3024,11 @@ constexpr unsigned parse_nonnegative_int(Iterator &it) { assert('0' <= *it && *it <= '9'); unsigned value = 0; do { - unsigned new_value = value * 10 + (*it++ - '0'); + unsigned new_value = value * 10 + (*it - '0'); + // Workaround for MSVC "setup_exception stack overflow" error: + auto next = it; + ++next; + it = next; // Check if value wrapped around. if (new_value < value) { value = (std::numeric_limits::max)(); From bd5188c811e408ed88961e9ed1e7986c40c04e2a Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Thu, 19 Oct 2017 06:46:25 -0700 Subject: [PATCH 170/340] Remove MinGW because it's not on appveyor image --- support/appveyor.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/support/appveyor.yml b/support/appveyor.yml index 71c5349f..d7eb8434 100644 --- a/support/appveyor.yml +++ b/support/appveyor.yml @@ -10,7 +10,6 @@ environment: - BUILD: msvc - BUILD: msvc PLATFORM: x64 - - BUILD: mingw before_build: # Workaround for CMake not wanting sh.exe on PATH for MinGW. From b83241ff4d9b099ff72d46871a5a8121669819c0 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Thu, 19 Oct 2017 07:28:17 -0700 Subject: [PATCH 171/340] Make format spec parsing constexpr --- fmt/format.cc | 4 ++- fmt/format.h | 37 +++++++++++++-------- test/format-test.cc | 79 +++++++++++++++++++++++++++++++++++++++------ 3 files changed, 95 insertions(+), 25 deletions(-) diff --git a/fmt/format.cc b/fmt/format.cc index e759084b..bd12cb9b 100644 --- a/fmt/format.cc +++ b/fmt/format.cc @@ -58,9 +58,11 @@ # define FMT_CATCH(x) if (false) #endif +#ifdef __GNUC__ // Disable the warning about declaration shadowing because it affects too // many valid cases. -#pragma GCC diagnostic ignored "-Wshadow" +# pragma GCC diagnostic ignored "-Wshadow" +#endif #ifdef _MSC_VER # pragma warning(push) diff --git a/fmt/format.h b/fmt/format.h index 7110827e..37a19c92 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -3263,10 +3263,16 @@ template struct arg_ref { enum Kind { NONE, INDEX, NAME }; - arg_ref() : kind(NONE) {} + constexpr arg_ref() : kind(NONE), index(0) {} explicit arg_ref(unsigned index) : kind(INDEX), index(index) {} explicit arg_ref(basic_string_view name) : kind(NAME), name(name) {} + constexpr arg_ref &operator=(unsigned index) { + kind = INDEX; + this->index = index; + return *this; + } + Kind kind; union { unsigned index; @@ -3361,13 +3367,14 @@ constexpr Iterator parse_arg_id(Iterator it, Handler& handler) { // characters, possibly emulated via null_terminating_iterator, representing // format specifiers. template -Iterator parse_format_specs(Iterator it, Handler &handler) { +constexpr Iterator parse_format_specs(Iterator it, Handler &handler) { using char_type = typename std::iterator_traits::value_type; // Parse fill and alignment. if (char_type c = *it) { - auto p = it + 1; alignment align = ALIGN_DEFAULT; + int i = 1; do { + auto p = it + i; switch (*p) { case '<': align = ALIGN_LEFT; @@ -3395,7 +3402,7 @@ Iterator parse_format_specs(Iterator it, Handler &handler) { } else ++it; break; } - } while (--p >= it); + } while (--i >= 0); } // Parse sign. @@ -3430,15 +3437,15 @@ Iterator parse_format_specs(Iterator it, Handler &handler) { handler.on_width(parse_nonnegative_int(it)); } else if (*it == '{') { struct width_handler { - explicit width_handler(Handler &h) : handler(h) {} + explicit constexpr width_handler(Handler &h) : handler(h) {} - void operator()() { handler.on_dynamic_width(auto_id()); } - void operator()(unsigned id) { handler.on_dynamic_width(id); } - void operator()(basic_string_view id) { + constexpr void operator()() { handler.on_dynamic_width(auto_id()); } + constexpr void operator()(unsigned id) { handler.on_dynamic_width(id); } + constexpr void operator()(basic_string_view id) { handler.on_dynamic_width(id); } - void on_error(const char *message) { + constexpr void on_error(const char *message) { handler.on_error(message); } @@ -3458,15 +3465,17 @@ Iterator parse_format_specs(Iterator it, Handler &handler) { handler.on_precision(parse_nonnegative_int(it)); } else if (*it == '{') { struct precision_handler { - explicit precision_handler(Handler &h) : handler(h) {} + explicit constexpr precision_handler(Handler &h) : handler(h) {} - void operator()() { handler.on_dynamic_precision(auto_id()); } - void operator()(unsigned id) { handler.on_dynamic_precision(id); } - void operator()(basic_string_view id) { + constexpr void operator()() { handler.on_dynamic_precision(auto_id()); } + constexpr void operator()(unsigned id) { + handler.on_dynamic_precision(id); + } + constexpr void operator()(basic_string_view id) { handler.on_dynamic_precision(id); } - void on_error(const char *message) { + constexpr void on_error(const char *message) { handler.on_error(message); } diff --git a/test/format-test.cc b/test/format-test.cc index a857f7ed..f0c71b9a 100644 --- a/test/format-test.cc +++ b/test/format-test.cc @@ -1582,7 +1582,7 @@ TEST(FormatTest, DynamicFormatter) { format_error, "precision not allowed in integer format specifier"); } -struct TestHandler { +struct TestArgIDHandler { enum Result { NONE, EMPTY, INDEX, NAME, ERROR }; Result result = NONE; unsigned index = 0; @@ -1603,18 +1603,77 @@ struct TestHandler { constexpr void on_error(const char *) { result = ERROR; } }; -constexpr TestHandler parse_arg_id(const char* id) { - TestHandler h; - fmt::internal::parse_arg_id(id, h); +constexpr TestArgIDHandler parse_arg_id(const char* s) { + TestArgIDHandler h; + fmt::internal::parse_arg_id(s, h); return h; } -TEST(FormatTest, ConstexprParseArgId) { - static_assert(parse_arg_id(":").result == TestHandler::EMPTY, ""); - static_assert(parse_arg_id("}").result == TestHandler::EMPTY, ""); - static_assert(parse_arg_id("42:").result == TestHandler::INDEX, ""); +TEST(FormatTest, ConstexprParseArgID) { + static_assert(parse_arg_id(":").result == TestArgIDHandler::EMPTY, ""); + static_assert(parse_arg_id("}").result == TestArgIDHandler::EMPTY, ""); + static_assert(parse_arg_id("42:").result == TestArgIDHandler::INDEX, ""); static_assert(parse_arg_id("42:").index == 42, ""); - static_assert(parse_arg_id("foo:").result == TestHandler::NAME, ""); + static_assert(parse_arg_id("foo:").result == TestArgIDHandler::NAME, ""); static_assert(parse_arg_id("foo:").name.size() == 3, ""); - static_assert(parse_arg_id("!").result == TestHandler::ERROR, ""); + static_assert(parse_arg_id("!").result == TestArgIDHandler::ERROR, ""); +} + +struct TestFormatSpecsHandler { + enum Result { NONE, PLUS, MINUS, SPACE, HASH, ZERO, ERROR }; + Result result = NONE; + + fmt::alignment align = fmt::ALIGN_DEFAULT; + char fill = 0; + unsigned width = 0; + fmt::internal::arg_ref width_ref; + unsigned precision = 0; + fmt::internal::arg_ref precision_ref; + char type = 0; + + constexpr void on_align(fmt::alignment align) { this->align = align; } + constexpr void on_fill(char fill) { this->fill = fill; } + constexpr void on_plus() { result = PLUS; } + constexpr void on_minus() { result = MINUS; } + constexpr void on_space() { result = SPACE; } + constexpr void on_hash() { result = HASH; } + constexpr void on_zero() { result = ZERO; } + + constexpr void on_width(unsigned width) { this->width = width; } + constexpr void on_dynamic_width(fmt::internal::auto_id) {} + constexpr void on_dynamic_width(unsigned index) { width_ref = index; } + constexpr void on_dynamic_width(string_view) {} + + constexpr void on_precision(unsigned precision) { + this->precision = precision; + } + constexpr void on_dynamic_precision(fmt::internal::auto_id) {} + constexpr void on_dynamic_precision(unsigned index) { precision_ref = index; } + constexpr void on_dynamic_precision(string_view) {} + + constexpr void end_precision() {} + constexpr void on_type(char type) { this->type = type; } + constexpr void on_error(const char *) { result = ERROR; } +}; + +constexpr TestFormatSpecsHandler parse_specs(const char *s) { + TestFormatSpecsHandler h; + fmt::internal::parse_format_specs(s, h); + return h; +} + +TEST(FormatTest, ConstexprParseFormatSpecs) { + static_assert(parse_specs("<").align == fmt::ALIGN_LEFT, ""); + static_assert(parse_specs("*^").fill == '*', ""); + static_assert(parse_specs("+").result == TestFormatSpecsHandler::PLUS, ""); + static_assert(parse_specs("-").result == TestFormatSpecsHandler::MINUS, ""); + static_assert(parse_specs(" ").result == TestFormatSpecsHandler::SPACE, ""); + static_assert(parse_specs("#").result == TestFormatSpecsHandler::HASH, ""); + static_assert(parse_specs("0").result == TestFormatSpecsHandler::ZERO, ""); + static_assert(parse_specs("42").width == 42, ""); + static_assert(parse_specs("{42}").width_ref.index == 42, ""); + static_assert(parse_specs(".42").precision == 42, ""); + static_assert(parse_specs(".{42}").precision_ref.index == 42, ""); + static_assert(parse_specs("d").type == 'd', ""); + static_assert(parse_specs("{<").result == TestFormatSpecsHandler::ERROR, ""); } From 25aac0bee52cd02505cf79d8b6d2edcfb5b408c4 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Fri, 20 Oct 2017 06:47:17 -0700 Subject: [PATCH 172/340] Fix travis build on macOS --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index aa734f7d..314a2000 100644 --- a/.travis.yml +++ b/.travis.yml @@ -31,7 +31,7 @@ addons: - g++-6 before_install: - - export CXX=g++-6 + - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then export CXX=g++-6; fi script: - support/travis-build.py From c69e3086902d67ff8160127ba02799a7b4e770e9 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Fri, 20 Oct 2017 18:00:31 -0700 Subject: [PATCH 173/340] Update README.rst --- README.rst | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/README.rst b/README.rst index c606bbf0..b9a4e626 100644 --- a/README.rst +++ b/README.rst @@ -106,9 +106,7 @@ An object of any user-defined type for which there is an overloaded std::string s = fmt::format("The date is {}", Date(2012, 12, 9)); // s == "The date is 2012-12-9" -You can use the `FMT_VARIADIC -`_ -macro to create your own functions similar to `format +You can create your own functions similar to `format `_ and `print `_ which take arbitrary arguments: @@ -116,17 +114,19 @@ which take arbitrary arguments: .. code:: c++ // Prints formatted error message. - void report_error(const char *format, fmt::ArgList args) { + void vreport_error(const char *format, fmt::args args) { fmt::print("Error: "); - fmt::print(format, args); + fmt::vprint(format, args); + } + template + void report_error(const char *format, const Args & ... args) { + vreport_error(format, fmt::make_args(args)); } - FMT_VARIADIC(void, report_error, const char *) report_error("file not found: {}", path); -Note that you only need to define one function that takes ``fmt::ArgList`` -argument. ``FMT_VARIADIC`` automatically defines necessary wrappers that -accept variable number of arguments. +Note that ``vreport_error`` is not parameterized on argument types which can +improve compile times and reduce code size compared to fully parameterized version. Projects using this library --------------------------- From 3d11eac784e3520a4814d22cd2dd5d0d0f55056a Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sat, 21 Oct 2017 07:13:20 -0700 Subject: [PATCH 174/340] Workaround another MSVC constexpr bug --- fmt/format.h | 80 ++++++++++++++++++++++++++-------------------------- 1 file changed, 40 insertions(+), 40 deletions(-) diff --git a/fmt/format.h b/fmt/format.h index 37a19c92..c4b72b1c 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -3070,7 +3070,7 @@ struct is_integer { }; }; -struct width_handler { +struct width_checker { template typename std::enable_if::value, unsigned long long>::type operator()(T value) { @@ -3087,7 +3087,7 @@ struct width_handler { } }; -struct precision_handler { +struct precision_checker { template typename std::enable_if::value, unsigned long long>::type operator()(T value) { @@ -3234,13 +3234,13 @@ class specs_handler: public specs_setter { template void on_dynamic_width(Id arg_id) { - set_dynamic_spec( + set_dynamic_spec( this->specs_.width_, get_arg(arg_id)); } template void on_dynamic_precision(Id arg_id) { - set_dynamic_spec( + set_dynamic_spec( this->specs_.precision_, get_arg(arg_id)); } @@ -3361,6 +3361,36 @@ constexpr Iterator parse_arg_id(Iterator it, Handler& handler) { return it; } +template +struct width_handler { + explicit constexpr width_handler(Handler &h) : handler(h) {} + + constexpr void operator()() { handler.on_dynamic_width(auto_id()); } + constexpr void operator()(unsigned id) { handler.on_dynamic_width(id); } + constexpr void operator()(basic_string_view id) { + handler.on_dynamic_width(id); + } + + constexpr void on_error(const char *message) { handler.on_error(message); } + + Handler &handler; +}; + +template +struct precision_handler { + explicit constexpr precision_handler(Handler &h) : handler(h) {} + + constexpr void operator()() { handler.on_dynamic_precision(auto_id()); } + constexpr void operator()(unsigned id) { handler.on_dynamic_precision(id); } + constexpr void operator()(basic_string_view id) { + handler.on_dynamic_precision(id); + } + + constexpr void on_error(const char *message) { handler.on_error(message); } + + Handler &handler; +}; + // Parses standard format specifiers and sends notifications about parsed // components to handler. // it: an iterator pointing to the beginning of a null-terminated range of @@ -3436,21 +3466,7 @@ constexpr Iterator parse_format_specs(Iterator it, Handler &handler) { if ('0' <= *it && *it <= '9') { handler.on_width(parse_nonnegative_int(it)); } else if (*it == '{') { - struct width_handler { - explicit constexpr width_handler(Handler &h) : handler(h) {} - - constexpr void operator()() { handler.on_dynamic_width(auto_id()); } - constexpr void operator()(unsigned id) { handler.on_dynamic_width(id); } - constexpr void operator()(basic_string_view id) { - handler.on_dynamic_width(id); - } - - constexpr void on_error(const char *message) { - handler.on_error(message); - } - - Handler &handler; - } wh(handler); + width_handler wh(handler); it = parse_arg_id(it + 1, wh); if (*it++ != '}') { handler.on_error("invalid format string"); @@ -3464,23 +3480,7 @@ constexpr Iterator parse_format_specs(Iterator it, Handler &handler) { if ('0' <= *it && *it <= '9') { handler.on_precision(parse_nonnegative_int(it)); } else if (*it == '{') { - struct precision_handler { - explicit constexpr precision_handler(Handler &h) : handler(h) {} - - constexpr void operator()() { handler.on_dynamic_precision(auto_id()); } - constexpr void operator()(unsigned id) { - handler.on_dynamic_precision(id); - } - constexpr void operator()(basic_string_view id) { - handler.on_dynamic_precision(id); - } - - constexpr void on_error(const char *message) { - handler.on_error(message); - } - - Handler &handler; - } ph(handler); + precision_handler ph(handler); it = parse_arg_id(it + 1, ph); if (*it++ != '}') { handler.on_error("invalid format string"); @@ -3567,9 +3567,9 @@ struct formatter< } void format(basic_buffer &buf, const T &val, basic_context &ctx) { - internal::handle_dynamic_spec( + internal::handle_dynamic_spec( specs_.width_, specs_.width_ref, ctx); - internal::handle_dynamic_spec( + internal::handle_dynamic_spec( specs_.precision_, specs_.precision_ref, ctx); visit(arg_formatter(buf, ctx, specs_), internal::make_arg>(val)); @@ -3645,9 +3645,9 @@ struct dynamic_formatter { private: void handle_specs(basic_context &ctx) { - internal::handle_dynamic_spec( + internal::handle_dynamic_spec( specs_.width_, specs_.width_ref, ctx); - internal::handle_dynamic_spec( + internal::handle_dynamic_spec( specs_.precision_, specs_.precision_ref, ctx); } From 170f5c671f509d875dd84fd8ddf097989c43af60 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sat, 21 Oct 2017 07:38:49 -0700 Subject: [PATCH 175/340] Move headers to include/fmt --- CMakeLists.txt | 2 +- {fmt => include/fmt}/CMakeLists.txt | 7 ++++--- {fmt => include/fmt}/format.cc | 0 {fmt => include/fmt}/format.h | 0 {fmt => include/fmt}/ostream.cc | 0 {fmt => include/fmt}/ostream.h | 0 {fmt => include/fmt}/posix.cc | 0 {fmt => include/fmt}/posix.h | 0 {fmt => include/fmt}/printf.cc | 0 {fmt => include/fmt}/printf.h | 0 {fmt => include/fmt}/string.h | 0 {fmt => include/fmt}/time.h | 0 {fmt => include/fmt}/write.h | 0 test/CMakeLists.txt | 18 +++++++++++------- 14 files changed, 16 insertions(+), 11 deletions(-) rename {fmt => include/fmt}/CMakeLists.txt (94%) rename {fmt => include/fmt}/format.cc (100%) rename {fmt => include/fmt}/format.h (100%) rename {fmt => include/fmt}/ostream.cc (100%) rename {fmt => include/fmt}/ostream.h (100%) rename {fmt => include/fmt}/posix.cc (100%) rename {fmt => include/fmt}/posix.h (100%) rename {fmt => include/fmt}/printf.cc (100%) rename {fmt => include/fmt}/printf.h (100%) rename {fmt => include/fmt}/string.h (100%) rename {fmt => include/fmt}/time.h (100%) rename {fmt => include/fmt}/write.h (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 47319e1d..58050201 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -72,7 +72,7 @@ else () check_symbol_exists(open fcntl.h HAVE_OPEN) endif () -add_subdirectory(fmt) +add_subdirectory(include/fmt) if (FMT_DOC) add_subdirectory(doc) diff --git a/fmt/CMakeLists.txt b/include/fmt/CMakeLists.txt similarity index 94% rename from fmt/CMakeLists.txt rename to include/fmt/CMakeLists.txt index ac3ad4ea..ccde97ed 100644 --- a/fmt/CMakeLists.txt +++ b/include/fmt/CMakeLists.txt @@ -7,7 +7,8 @@ if (HAVE_OPEN) set(FMT_SOURCES ${FMT_SOURCES} posix.cc) endif () -add_library(fmt ${FMT_SOURCES} ${FMT_HEADERS} ../README.rst ../ChangeLog.rst) +add_library(fmt + ${FMT_SOURCES} ${FMT_HEADERS} ../../README.rst ../../ChangeLog.rst) option(FMT_CPPFORMAT "Build cppformat library for backward compatibility." OFF) if (FMT_CPPFORMAT) @@ -22,7 +23,7 @@ if (FMT_PEDANTIC) endif () target_include_directories(fmt PUBLIC - $ + $ $) set_target_properties(fmt PROPERTIES @@ -45,7 +46,7 @@ if (CMAKE_VERSION VERSION_GREATER 3.1.0 OR CMAKE_VERSION VERSION_EQUAL 3.1.0) target_compile_definitions(fmt-header-only INTERFACE FMT_HEADER_ONLY=1) target_include_directories(fmt-header-only INTERFACE - $ + $ $) endif () diff --git a/fmt/format.cc b/include/fmt/format.cc similarity index 100% rename from fmt/format.cc rename to include/fmt/format.cc diff --git a/fmt/format.h b/include/fmt/format.h similarity index 100% rename from fmt/format.h rename to include/fmt/format.h diff --git a/fmt/ostream.cc b/include/fmt/ostream.cc similarity index 100% rename from fmt/ostream.cc rename to include/fmt/ostream.cc diff --git a/fmt/ostream.h b/include/fmt/ostream.h similarity index 100% rename from fmt/ostream.h rename to include/fmt/ostream.h diff --git a/fmt/posix.cc b/include/fmt/posix.cc similarity index 100% rename from fmt/posix.cc rename to include/fmt/posix.cc diff --git a/fmt/posix.h b/include/fmt/posix.h similarity index 100% rename from fmt/posix.h rename to include/fmt/posix.h diff --git a/fmt/printf.cc b/include/fmt/printf.cc similarity index 100% rename from fmt/printf.cc rename to include/fmt/printf.cc diff --git a/fmt/printf.h b/include/fmt/printf.h similarity index 100% rename from fmt/printf.h rename to include/fmt/printf.h diff --git a/fmt/string.h b/include/fmt/string.h similarity index 100% rename from fmt/string.h rename to include/fmt/string.h diff --git a/fmt/time.h b/include/fmt/time.h similarity index 100% rename from fmt/time.h rename to include/fmt/time.h diff --git a/fmt/write.h b/include/fmt/write.h similarity index 100% rename from fmt/write.h rename to include/fmt/write.h diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index b99925fa..ab6faae1 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -98,8 +98,9 @@ endif () if (HAVE_OPEN) add_fmt_executable(posix-mock-test - posix-mock-test.cc ../fmt/format.cc ${TEST_MAIN_SRC}) - target_include_directories(posix-mock-test PRIVATE ${PROJECT_SOURCE_DIR}) + posix-mock-test.cc ../include/fmt/format.cc ${TEST_MAIN_SRC}) + target_include_directories( + posix-mock-test PRIVATE ${PROJECT_SOURCE_DIR}/include) target_compile_definitions(posix-mock-test PRIVATE FMT_USE_FILE_DESCRIPTORS=1) target_link_libraries(posix-mock-test gmock) add_test(NAME posix-mock-test COMMAND posix-mock-test) @@ -112,25 +113,28 @@ target_link_libraries(header-only-test gmock) if (TARGET fmt-header-only) target_link_libraries(header-only-test fmt-header-only) else () - target_include_directories(header-only-test PRIVATE ${PROJECT_SOURCE_DIR}) + target_include_directories( + header-only-test PRIVATE ${PROJECT_SOURCE_DIR}/include) target_compile_definitions(header-only-test PRIVATE FMT_HEADER_ONLY=1) endif () # Test that the library can be compiled with exceptions disabled. check_cxx_compiler_flag(-fno-exceptions HAVE_FNO_EXCEPTIONS_FLAG) if (HAVE_FNO_EXCEPTIONS_FLAG) - add_library(noexception-test ../fmt/format.cc) + add_library(noexception-test ../include/fmt/format.cc) target_compile_options(noexception-test PUBLIC ${CPP14_FLAG}) - target_include_directories(noexception-test PRIVATE ${PROJECT_SOURCE_DIR}) + target_include_directories( + noexception-test PRIVATE ${PROJECT_SOURCE_DIR}/include) target_compile_options(noexception-test PRIVATE -fno-exceptions) endif () if (FMT_PEDANTIC) # Test that the library compiles without windows.h. if (CMAKE_SYSTEM_NAME STREQUAL "Windows") - add_library(no-windows-h-test ../fmt/format.cc) + add_library(no-windows-h-test ../include/fmt/format.cc) target_compile_options(no-windows-h-test PUBLIC ${CPP14_FLAG}) - target_include_directories(no-windows-h-test PRIVATE ${PROJECT_SOURCE_DIR}) + target_include_directories( + no-windows-h-test PRIVATE ${PROJECT_SOURCE_DIR}/include) target_compile_definitions(no-windows-h-test PRIVATE FMT_USE_WINDOWS_H=0) endif () From 0ebdf41efac462a28bd594605d7358703bf7e14d Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sat, 21 Oct 2017 08:17:00 -0700 Subject: [PATCH 176/340] Fix compile-test --- test/compile-test/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/compile-test/CMakeLists.txt b/test/compile-test/CMakeLists.txt index 775b4067..ded517ad 100644 --- a/test/compile-test/CMakeLists.txt +++ b/test/compile-test/CMakeLists.txt @@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 2.8) include(CheckCXXSourceCompiles) -set(CMAKE_REQUIRED_INCLUDES ${CMAKE_CURRENT_SOURCE_DIR}/../..) +set(CMAKE_REQUIRED_INCLUDES ${CMAKE_CURRENT_SOURCE_DIR}/../../include) set(CMAKE_REQUIRED_FLAGS ${CPP14_FLAG}) function (generate_source result fragment) From 932ab2bfca1e77ae2a9df5f866262f59595b3298 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sat, 21 Oct 2017 08:37:52 -0700 Subject: [PATCH 177/340] Report error from parse_nonnegative_int via handler --- include/fmt/format.h | 20 ++++++++++---------- include/fmt/printf.h | 9 ++++++--- 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/include/fmt/format.h b/include/fmt/format.h index c4b72b1c..8e7e0121 100644 --- a/include/fmt/format.h +++ b/include/fmt/format.h @@ -1924,7 +1924,7 @@ class parse_context { return 0; } - void check_arg_id(unsigned index) { + void check_arg_id(unsigned) { const char *error = 0; if (!check_no_auto_index(error)) FMT_THROW(format_error(error)); @@ -3016,11 +3016,11 @@ constexpr bool is_name_start(Char c) { return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || '_' == c; } -// Parses an unsigned integer advancing it to the end of the parsed input. -// This function assumes that the first character of it is a digit and a -// presence of a non-digit character at the end. -template -constexpr unsigned parse_nonnegative_int(Iterator &it) { +// Parses the input as an unsigned integer. This function assumes that the +// first character is a digit and presence of a non-digit character at the end. +// it: an iterator pointing to the beginning of the input range. +template +constexpr unsigned parse_nonnegative_int(Iterator &it, ErrorHandler& handler) { assert('0' <= *it && *it <= '9'); unsigned value = 0; do { @@ -3039,7 +3039,7 @@ constexpr unsigned parse_nonnegative_int(Iterator &it) { // Convert to unsigned to prevent a warning. unsigned max_int = (std::numeric_limits::max)(); if (value > max_int) - FMT_THROW(format_error("number is too big")); + handler.on_error("number is too big"); return value; } @@ -3341,7 +3341,7 @@ constexpr Iterator parse_arg_id(Iterator it, Handler& handler) { return it; } if (c >= '0' && c <= '9') { - unsigned index = parse_nonnegative_int(it); + unsigned index = parse_nonnegative_int(it, handler); if (*it != '}' && *it != ':') { handler.on_error("invalid format string"); return it; @@ -3464,7 +3464,7 @@ constexpr Iterator parse_format_specs(Iterator it, Handler &handler) { // Parse width. if ('0' <= *it && *it <= '9') { - handler.on_width(parse_nonnegative_int(it)); + handler.on_width(parse_nonnegative_int(it, handler)); } else if (*it == '{') { width_handler wh(handler); it = parse_arg_id(it + 1, wh); @@ -3478,7 +3478,7 @@ constexpr Iterator parse_format_specs(Iterator it, Handler &handler) { if (*it == '.') { ++it; if ('0' <= *it && *it <= '9') { - handler.on_precision(parse_nonnegative_int(it)); + handler.on_precision(parse_nonnegative_int(it, handler)); } else if (*it == '{') { precision_handler ph(handler); it = parse_arg_id(it + 1, ph); diff --git a/include/fmt/printf.h b/include/fmt/printf.h index eb9e39db..a8533ef2 100644 --- a/include/fmt/printf.h +++ b/include/fmt/printf.h @@ -389,7 +389,8 @@ unsigned printf_context::parse_header( if (c >= '0' && c <= '9') { // Parse an argument index (if followed by '$') or a width possibly // preceded with '0' flag(s). - unsigned value = internal::parse_nonnegative_int(it); + internal::error_handler eh; + unsigned value = parse_nonnegative_int(it, eh); if (*it == '$') { // value is an argument index ++it; arg_index = value; @@ -407,7 +408,8 @@ unsigned printf_context::parse_header( parse_flags(spec, it); // Parse width. if (*it >= '0' && *it <= '9') { - spec.width_ = internal::parse_nonnegative_int(it); + internal::error_handler eh; + spec.width_ = parse_nonnegative_int(it, eh); } else if (*it == '*') { ++it; spec.width_ = visit(internal::PrintfWidthHandler(spec), get_arg(it)); @@ -441,7 +443,8 @@ void printf_context::format(basic_buffer &buffer) { if (*it == '.') { ++it; if ('0' <= *it && *it <= '9') { - spec.precision_ = static_cast(internal::parse_nonnegative_int(it)); + internal::error_handler eh; + spec.precision_ = static_cast(parse_nonnegative_int(it, eh)); } else if (*it == '*') { ++it; spec.precision_ = From 91014f01716c9e665871224a84d1d8f9d62b984f Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sun, 22 Oct 2017 06:43:41 -0700 Subject: [PATCH 178/340] Naming conventions --- test/format-test.cc | 60 ++++++++++++++++++++++----------------------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/test/format-test.cc b/test/format-test.cc index f0c71b9a..27ad78c4 100644 --- a/test/format-test.cc +++ b/test/format-test.cc @@ -1582,46 +1582,46 @@ TEST(FormatTest, DynamicFormatter) { format_error, "precision not allowed in integer format specifier"); } -struct TestArgIDHandler { - enum Result { NONE, EMPTY, INDEX, NAME, ERROR }; - Result result = NONE; +struct test_arg_id_handler { + enum result { NONE, EMPTY, INDEX, NAME, ERROR }; + result res = NONE; unsigned index = 0; string_view name; - constexpr void operator()() { result = EMPTY; } + constexpr void operator()() { res = EMPTY; } constexpr void operator()(unsigned index) { - result = INDEX; + res = INDEX; this->index = index; } constexpr void operator()(string_view name) { - result = NAME; + res = NAME; this->name = name; } - constexpr void on_error(const char *) { result = ERROR; } + constexpr void on_error(const char *) { res = ERROR; } }; -constexpr TestArgIDHandler parse_arg_id(const char* s) { - TestArgIDHandler h; +constexpr test_arg_id_handler parse_arg_id(const char* s) { + test_arg_id_handler h; fmt::internal::parse_arg_id(s, h); return h; } TEST(FormatTest, ConstexprParseArgID) { - static_assert(parse_arg_id(":").result == TestArgIDHandler::EMPTY, ""); - static_assert(parse_arg_id("}").result == TestArgIDHandler::EMPTY, ""); - static_assert(parse_arg_id("42:").result == TestArgIDHandler::INDEX, ""); + static_assert(parse_arg_id(":").res == test_arg_id_handler::EMPTY, ""); + static_assert(parse_arg_id("}").res == test_arg_id_handler::EMPTY, ""); + static_assert(parse_arg_id("42:").res == test_arg_id_handler::INDEX, ""); static_assert(parse_arg_id("42:").index == 42, ""); - static_assert(parse_arg_id("foo:").result == TestArgIDHandler::NAME, ""); + static_assert(parse_arg_id("foo:").res == test_arg_id_handler::NAME, ""); static_assert(parse_arg_id("foo:").name.size() == 3, ""); - static_assert(parse_arg_id("!").result == TestArgIDHandler::ERROR, ""); + static_assert(parse_arg_id("!").res == test_arg_id_handler::ERROR, ""); } -struct TestFormatSpecsHandler { +struct test_format_specs_handlers { enum Result { NONE, PLUS, MINUS, SPACE, HASH, ZERO, ERROR }; - Result result = NONE; + Result res = NONE; fmt::alignment align = fmt::ALIGN_DEFAULT; char fill = 0; @@ -1633,11 +1633,11 @@ struct TestFormatSpecsHandler { constexpr void on_align(fmt::alignment align) { this->align = align; } constexpr void on_fill(char fill) { this->fill = fill; } - constexpr void on_plus() { result = PLUS; } - constexpr void on_minus() { result = MINUS; } - constexpr void on_space() { result = SPACE; } - constexpr void on_hash() { result = HASH; } - constexpr void on_zero() { result = ZERO; } + constexpr void on_plus() { res = PLUS; } + constexpr void on_minus() { res = MINUS; } + constexpr void on_space() { res = SPACE; } + constexpr void on_hash() { res = HASH; } + constexpr void on_zero() { res = ZERO; } constexpr void on_width(unsigned width) { this->width = width; } constexpr void on_dynamic_width(fmt::internal::auto_id) {} @@ -1653,11 +1653,11 @@ struct TestFormatSpecsHandler { constexpr void end_precision() {} constexpr void on_type(char type) { this->type = type; } - constexpr void on_error(const char *) { result = ERROR; } + constexpr void on_error(const char *) { res = ERROR; } }; -constexpr TestFormatSpecsHandler parse_specs(const char *s) { - TestFormatSpecsHandler h; +constexpr test_format_specs_handlers parse_specs(const char *s) { + test_format_specs_handlers h; fmt::internal::parse_format_specs(s, h); return h; } @@ -1665,15 +1665,15 @@ constexpr TestFormatSpecsHandler parse_specs(const char *s) { TEST(FormatTest, ConstexprParseFormatSpecs) { static_assert(parse_specs("<").align == fmt::ALIGN_LEFT, ""); static_assert(parse_specs("*^").fill == '*', ""); - static_assert(parse_specs("+").result == TestFormatSpecsHandler::PLUS, ""); - static_assert(parse_specs("-").result == TestFormatSpecsHandler::MINUS, ""); - static_assert(parse_specs(" ").result == TestFormatSpecsHandler::SPACE, ""); - static_assert(parse_specs("#").result == TestFormatSpecsHandler::HASH, ""); - static_assert(parse_specs("0").result == TestFormatSpecsHandler::ZERO, ""); + static_assert(parse_specs("+").res == test_format_specs_handlers::PLUS, ""); + static_assert(parse_specs("-").res == test_format_specs_handlers::MINUS, ""); + static_assert(parse_specs(" ").res == test_format_specs_handlers::SPACE, ""); + static_assert(parse_specs("#").res == test_format_specs_handlers::HASH, ""); + static_assert(parse_specs("0").res == test_format_specs_handlers::ZERO, ""); static_assert(parse_specs("42").width == 42, ""); static_assert(parse_specs("{42}").width_ref.index == 42, ""); static_assert(parse_specs(".42").precision == 42, ""); static_assert(parse_specs(".{42}").precision_ref.index == 42, ""); static_assert(parse_specs("d").type == 'd', ""); - static_assert(parse_specs("{<").result == TestFormatSpecsHandler::ERROR, ""); + static_assert(parse_specs("{<").res == test_format_specs_handlers::ERROR, ""); } From a38bd9ca2423a9f46786732a576ebde05d54e3bf Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sun, 22 Oct 2017 07:19:45 -0700 Subject: [PATCH 179/340] Fix formatting and naming --- include/fmt/format.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/fmt/format.h b/include/fmt/format.h index 8e7e0121..62100abc 100644 --- a/include/fmt/format.h +++ b/include/fmt/format.h @@ -1106,11 +1106,11 @@ struct string_value { template struct custom_value { - typedef void (*FormatFunc)( + typedef void (*format_func)( basic_buffer &buffer, const void *arg, void *ctx); const void *value; - FormatFunc format; + format_func format; }; template @@ -3050,7 +3050,7 @@ class custom_formatter { Context &ctx_; public: - custom_formatter(basic_buffer &buffer,Context &ctx) + custom_formatter(basic_buffer &buffer, Context &ctx) : buffer_(buffer), ctx_(ctx) {} bool operator()(internal::custom_value custom) { From 6b3840b73c2520a658cf2cfa067f26771bf9ea70 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sun, 22 Oct 2017 08:18:26 -0700 Subject: [PATCH 180/340] Make format_specs construction constexpr --- include/fmt/format.h | 54 +++++++++++++++++++--------------- test/format-test.cc | 70 ++++++++++++++++++++++++++++++++++---------- 2 files changed, 84 insertions(+), 40 deletions(-) diff --git a/include/fmt/format.h b/include/fmt/format.h index 62100abc..7b9a6e5b 100644 --- a/include/fmt/format.h +++ b/include/fmt/format.h @@ -1630,12 +1630,13 @@ struct align_spec : empty_spec { wchar_t fill_; alignment align_; - align_spec(unsigned width, wchar_t fill, alignment align = ALIGN_DEFAULT) + constexpr align_spec( + unsigned width, wchar_t fill, alignment align = ALIGN_DEFAULT) : width_(width), fill_(fill), align_(align) {} - unsigned width() const { return width_; } - wchar_t fill() const { return fill_; } - alignment align() const { return align_; } + constexpr unsigned width() const { return width_; } + constexpr wchar_t fill() const { return fill_; } + constexpr alignment align() const { return align_; } int precision() const { return -1; } }; @@ -1670,7 +1671,8 @@ class basic_format_specs : public align_spec { int precision_; Char type_; - basic_format_specs(unsigned width = 0, char type = 0, wchar_t fill = ' ') + constexpr basic_format_specs( + unsigned width = 0, char type = 0, wchar_t fill = ' ') : align_spec(width, fill), flags_(0), precision_(-1), type_(type) {} template @@ -1679,9 +1681,9 @@ class basic_format_specs : public align_spec { set(specs...); } - bool flag(unsigned f) const { return (flags_ & f) != 0; } - int precision() const { return precision_; } - Char type() const { return type_; } + constexpr bool flag(unsigned f) const { return (flags_ & f) != 0; } + constexpr int precision() const { return precision_; } + constexpr Char type() const { return type_; } }; typedef basic_format_specs format_specs; @@ -3114,29 +3116,30 @@ struct error_handler { template class specs_setter : public error_handler { public: - explicit specs_setter(basic_format_specs &specs): specs_(specs) {} + explicit constexpr specs_setter(basic_format_specs &specs): + specs_(specs) {} - void on_align(alignment align) { specs_.align_ = align; } - void on_fill(Char fill) { specs_.fill_ = fill; } - void on_plus() { specs_.flags_ |= SIGN_FLAG | PLUS_FLAG; } - void on_minus() { specs_.flags_ |= MINUS_FLAG; } - void on_space() { specs_.flags_ |= SIGN_FLAG; } - void on_hash() { specs_.flags_ |= HASH_FLAG; } + constexpr void on_align(alignment align) { specs_.align_ = align; } + constexpr void on_fill(Char fill) { specs_.fill_ = fill; } + constexpr void on_plus() { specs_.flags_ |= SIGN_FLAG | PLUS_FLAG; } + constexpr void on_minus() { specs_.flags_ |= MINUS_FLAG; } + constexpr void on_space() { specs_.flags_ |= SIGN_FLAG; } + constexpr void on_hash() { specs_.flags_ |= HASH_FLAG; } - void on_zero() { + constexpr void on_zero() { specs_.align_ = ALIGN_NUMERIC; specs_.fill_ = '0'; } - void on_width(unsigned width) { specs_.width_ = width; } - void on_precision(unsigned precision) { specs_.precision_ = precision; } - void end_precision() {} + constexpr void on_width(unsigned width) { specs_.width_ = width; } + constexpr void on_precision(unsigned precision) { + specs_.precision_ = precision; + } + constexpr void end_precision() {} - void on_type(Char type) { specs_.type_ = type; } + constexpr void on_type(Char type) { specs_.type_ = type; } protected: - ~specs_setter() {} - basic_format_specs &specs_; }; @@ -3229,7 +3232,7 @@ class specs_handler: public specs_setter { public: typedef typename Context::char_type char_type; - specs_handler(basic_format_specs &specs, Context &ctx) + constexpr specs_handler(basic_format_specs &specs, Context &ctx) : specs_setter(specs), context_(ctx) {} template @@ -3508,8 +3511,11 @@ const Char *do_format_arg(basic_buffer &buffer, basic_format_specs specs; if (*it == ':') { ctx.advance_to(pointer_from(++it)); - if (visit(custom_formatter(buffer, ctx), arg)) + if (visit(custom_formatter(buffer, ctx), arg)) { + // TODO: if constexpr, then use formatter::parse, else dispatch + // dynamically return ctx.begin(); + } specs_checker> handler(specs_handler(specs, ctx), arg.type()); it = parse_format_specs(it, handler); diff --git a/test/format-test.cc b/test/format-test.cc index 27ad78c4..1cf6cd0d 100644 --- a/test/format-test.cc +++ b/test/format-test.cc @@ -1619,7 +1619,7 @@ TEST(FormatTest, ConstexprParseArgID) { static_assert(parse_arg_id("!").res == test_arg_id_handler::ERROR, ""); } -struct test_format_specs_handlers { +struct test_format_specs_handler { enum Result { NONE, PLUS, MINUS, SPACE, HASH, ZERO, ERROR }; Result res = NONE; @@ -1656,24 +1656,62 @@ struct test_format_specs_handlers { constexpr void on_error(const char *) { res = ERROR; } }; -constexpr test_format_specs_handlers parse_specs(const char *s) { - test_format_specs_handlers h; +constexpr test_format_specs_handler parse_test_specs(const char *s) { + test_format_specs_handler h; fmt::internal::parse_format_specs(s, h); return h; } TEST(FormatTest, ConstexprParseFormatSpecs) { - static_assert(parse_specs("<").align == fmt::ALIGN_LEFT, ""); - static_assert(parse_specs("*^").fill == '*', ""); - static_assert(parse_specs("+").res == test_format_specs_handlers::PLUS, ""); - static_assert(parse_specs("-").res == test_format_specs_handlers::MINUS, ""); - static_assert(parse_specs(" ").res == test_format_specs_handlers::SPACE, ""); - static_assert(parse_specs("#").res == test_format_specs_handlers::HASH, ""); - static_assert(parse_specs("0").res == test_format_specs_handlers::ZERO, ""); - static_assert(parse_specs("42").width == 42, ""); - static_assert(parse_specs("{42}").width_ref.index == 42, ""); - static_assert(parse_specs(".42").precision == 42, ""); - static_assert(parse_specs(".{42}").precision_ref.index == 42, ""); - static_assert(parse_specs("d").type == 'd', ""); - static_assert(parse_specs("{<").res == test_format_specs_handlers::ERROR, ""); + using handler = test_format_specs_handler; + static_assert(parse_test_specs("<").align == fmt::ALIGN_LEFT, ""); + static_assert(parse_test_specs("*^").fill == '*', ""); + static_assert(parse_test_specs("+").res == handler::PLUS, ""); + static_assert(parse_test_specs("-").res == handler::MINUS, ""); + static_assert(parse_test_specs(" ").res == handler::SPACE, ""); + static_assert(parse_test_specs("#").res == handler::HASH, ""); + static_assert(parse_test_specs("0").res == handler::ZERO, ""); + static_assert(parse_test_specs("42").width == 42, ""); + static_assert(parse_test_specs("{42}").width_ref.index == 42, ""); + static_assert(parse_test_specs(".42").precision == 42, ""); + static_assert(parse_test_specs(".{42}").precision_ref.index == 42, ""); + static_assert(parse_test_specs("d").type == 'd', ""); + static_assert(parse_test_specs("{<").res == handler::ERROR, ""); +} + +struct test_context { + using char_type = char; + + fmt::basic_arg next_arg() { + return fmt::basic_arg(); + } + + template + fmt::basic_arg get_arg(Id) { + return fmt::basic_arg(); + } + + template + void check_arg_id(Id) {} +}; + +constexpr fmt::format_specs parse_specs(const char *s) { + fmt::format_specs specs; + test_context ctx; + fmt::internal::specs_handler h(specs, ctx); + parse_format_specs(s, h); + return specs; +} + +TEST(FormatTest, ConstexprSpecsHandler) { + static_assert(parse_specs("<").align() == fmt::ALIGN_LEFT, ""); + static_assert(parse_specs("*^").fill() == '*', ""); + static_assert(parse_specs("+").flag(fmt::PLUS_FLAG), ""); + static_assert(parse_specs("-").flag(fmt::MINUS_FLAG), ""); + static_assert(parse_specs(" ").flag(fmt::SIGN_FLAG), ""); + static_assert(parse_specs("#").flag(fmt::HASH_FLAG), ""); + static_assert(parse_specs("0").align() == fmt::ALIGN_NUMERIC, ""); + static_assert(parse_specs("42").width() == 42, ""); + static_assert(parse_specs(".42").precision() == 42, ""); + static_assert(parse_specs("d").type() == 'd', ""); } From d2f2a8b0ca5f6a5243385ca247827a438cff7c2a Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sun, 22 Oct 2017 09:32:46 -0700 Subject: [PATCH 181/340] constexpr support of dynamic width and precision --- include/fmt/format.h | 57 +++++++++++++++++++++----------------------- test/format-test.cc | 14 +++++++---- 2 files changed, 36 insertions(+), 35 deletions(-) diff --git a/include/fmt/format.h b/include/fmt/format.h index 7b9a6e5b..751a1594 100644 --- a/include/fmt/format.h +++ b/include/fmt/format.h @@ -850,13 +850,13 @@ constexpr const Char *pointer_from(null_terminating_iterator it) { // Returns true if value is negative, false otherwise. // Same as (value < 0) but doesn't produce warnings if T is an unsigned type. template -inline typename std::enable_if::is_signed, bool>::type - is_negative(T value) { +constexpr typename std::enable_if< + std::numeric_limits::is_signed, bool>::type is_negative(T value) { return value < 0; } template -inline typename std::enable_if::is_signed, bool>::type - is_negative(T) { +constexpr typename std::enable_if< + !std::numeric_limits::is_signed, bool>::type is_negative(T) { return false; } @@ -1205,11 +1205,11 @@ class value { custom_value custom; }; - value() {} + constexpr value() {} value(bool val) { set(int_value, val); } value(short val) { set(int_value, val); } value(unsigned short val) { set(uint_value, val); } - value(int val) { set(int_value, val); } + constexpr value(int val) : int_value(val) {} value(unsigned val) { set(uint_value, val); } value(long val) { @@ -1299,7 +1299,7 @@ class value { private: template - void set(T &field, const U &value) { + constexpr void set(T &field, const U &value) { static_assert(get_type() == TYPE, "invalid type"); field = value; } @@ -1338,7 +1338,7 @@ template class arg_map; template -basic_arg make_arg(const T &value); +constexpr basic_arg make_arg(const T &value); } // namespace internal struct monostate {}; @@ -1355,17 +1355,17 @@ class basic_arg { internal::type type_; template - friend basic_arg internal::make_arg(const T &value); + friend constexpr basic_arg internal::make_arg(const T &value); template - friend typename std::result_of::type + friend constexpr typename std::result_of::type visit(Visitor &&vis, basic_arg arg); friend class basic_args; friend class internal::arg_map; public: - basic_arg() : type_(internal::NONE) {} + constexpr basic_arg() : type_(internal::NONE) {} explicit operator bool() const noexcept { return type_ != internal::NONE; } @@ -1384,7 +1384,7 @@ class basic_arg { \endrst */ template -typename std::result_of::type +constexpr typename std::result_of::type visit(Visitor &&vis, basic_arg arg) { typedef typename Context::char_type Char; switch (arg.type_) { @@ -1427,7 +1427,7 @@ typename std::result_of::type namespace internal { template -basic_arg make_arg(const T &value) { +constexpr basic_arg make_arg(const T &value) { basic_arg arg; arg.type_ = get_type(); arg.value_ = value; @@ -3074,16 +3074,16 @@ struct is_integer { struct width_checker { template - typename std::enable_if::value, unsigned long long>::type - operator()(T value) { + constexpr typename std::enable_if< + is_integer::value, unsigned long long>::type operator()(T value) { if (is_negative(value)) FMT_THROW(format_error("negative width")); return value; } template - typename std::enable_if::value, unsigned long long>::type - operator()(T) { + constexpr typename std::enable_if< + !is_integer::value, unsigned long long>::type operator()(T) { FMT_THROW(format_error("width is not integer")); return 0; } @@ -3091,16 +3091,16 @@ struct width_checker { struct precision_checker { template - typename std::enable_if::value, unsigned long long>::type - operator()(T value) { + constexpr typename std::enable_if< + is_integer::value, unsigned long long>::type operator()(T value) { if (is_negative(value)) FMT_THROW(format_error("negative precision")); return value; } template - typename std::enable_if::value, unsigned long long>::type - operator()(T) { + constexpr typename std::enable_if< + !is_integer::value, unsigned long long>::type operator()(T) { FMT_THROW(format_error("precision is not integer")); return 0; } @@ -3217,7 +3217,7 @@ class specs_checker : public Handler { }; template -inline void set_dynamic_spec(T &value, basic_arg arg) { +constexpr void set_dynamic_spec(T &value, basic_arg arg) { unsigned long long big_value = visit(Handler(), arg); if (big_value > (std::numeric_limits::max)()) FMT_THROW(format_error("number is too big")); @@ -3236,24 +3236,24 @@ class specs_handler: public specs_setter { : specs_setter(specs), context_(ctx) {} template - void on_dynamic_width(Id arg_id) { + constexpr void on_dynamic_width(Id arg_id) { set_dynamic_spec( this->specs_.width_, get_arg(arg_id)); } template - void on_dynamic_precision(Id arg_id) { + constexpr void on_dynamic_precision(Id arg_id) { set_dynamic_spec( this->specs_.precision_, get_arg(arg_id)); } private: - basic_arg get_arg(auto_id) { + constexpr basic_arg get_arg(auto_id) { return context_.next_arg(); } template - basic_arg get_arg(Id arg_id) { + constexpr basic_arg get_arg(Id arg_id) { context_.check_arg_id(arg_id); return context_.get_arg(arg_id); } @@ -3511,11 +3511,8 @@ const Char *do_format_arg(basic_buffer &buffer, basic_format_specs specs; if (*it == ':') { ctx.advance_to(pointer_from(++it)); - if (visit(custom_formatter(buffer, ctx), arg)) { - // TODO: if constexpr, then use formatter::parse, else dispatch - // dynamically + if (visit(custom_formatter(buffer, ctx), arg)) return ctx.begin(); - } specs_checker> handler(specs_handler(specs, ctx), arg.type()); it = parse_format_specs(it, handler); diff --git a/test/format-test.cc b/test/format-test.cc index 1cf6cd0d..48f6c439 100644 --- a/test/format-test.cc +++ b/test/format-test.cc @@ -1682,17 +1682,17 @@ TEST(FormatTest, ConstexprParseFormatSpecs) { struct test_context { using char_type = char; - fmt::basic_arg next_arg() { - return fmt::basic_arg(); + constexpr fmt::basic_arg next_arg() { + return fmt::internal::make_arg(11); } template - fmt::basic_arg get_arg(Id) { - return fmt::basic_arg(); + constexpr fmt::basic_arg get_arg(Id) { + return fmt::internal::make_arg(22); } template - void check_arg_id(Id) {} + constexpr void check_arg_id(Id) {} }; constexpr fmt::format_specs parse_specs(const char *s) { @@ -1712,6 +1712,10 @@ TEST(FormatTest, ConstexprSpecsHandler) { static_assert(parse_specs("#").flag(fmt::HASH_FLAG), ""); static_assert(parse_specs("0").align() == fmt::ALIGN_NUMERIC, ""); static_assert(parse_specs("42").width() == 42, ""); + static_assert(parse_specs("{}").width() == 11, ""); + static_assert(parse_specs("{0}").width() == 22, ""); static_assert(parse_specs(".42").precision() == 42, ""); + static_assert(parse_specs(".{}").precision() == 11, ""); + static_assert(parse_specs(".{0}").precision() == 22, ""); static_assert(parse_specs("d").type() == 'd', ""); } From 529d88ce95f2bc08f3cb04d67af994a970611d62 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sun, 22 Oct 2017 10:19:09 -0700 Subject: [PATCH 182/340] Make dynamic_format_specs construction constexpr --- include/fmt/format.h | 14 +++++++------- test/format-test.cc | 28 ++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 7 deletions(-) diff --git a/include/fmt/format.h b/include/fmt/format.h index 751a1594..1093bb5b 100644 --- a/include/fmt/format.h +++ b/include/fmt/format.h @@ -1205,7 +1205,7 @@ class value { custom_value custom; }; - constexpr value() {} + constexpr value() : int_value(0) {} value(bool val) { set(int_value, val); } value(short val) { set(int_value, val); } value(unsigned short val) { set(uint_value, val); } @@ -3267,7 +3267,7 @@ struct arg_ref { enum Kind { NONE, INDEX, NAME }; constexpr arg_ref() : kind(NONE), index(0) {} - explicit arg_ref(unsigned index) : kind(INDEX), index(index) {} + constexpr explicit arg_ref(unsigned index) : kind(INDEX), index(index) {} explicit arg_ref(basic_string_view name) : kind(NAME), name(name) {} constexpr arg_ref &operator=(unsigned index) { @@ -3300,17 +3300,17 @@ class dynamic_specs_handler : public: using char_type = typename ParseContext::char_type; - dynamic_specs_handler( + constexpr dynamic_specs_handler( dynamic_format_specs &specs, ParseContext &ctx) : specs_setter(specs), specs_(specs), context_(ctx) {} template - void on_dynamic_width(Id arg_id) { + constexpr void on_dynamic_width(Id arg_id) { specs_.width_ref = make_arg_ref(arg_id); } template - void on_dynamic_precision(Id arg_id) { + constexpr void on_dynamic_precision(Id arg_id) { specs_.precision_ref = make_arg_ref(arg_id); } @@ -3318,12 +3318,12 @@ class dynamic_specs_handler : using arg_ref_type = arg_ref; template - arg_ref_type make_arg_ref(Id arg_id) { + constexpr arg_ref_type make_arg_ref(Id arg_id) { context_.check_arg_id(arg_id); return arg_ref_type(arg_id); } - arg_ref_type make_arg_ref(auto_id) { + constexpr arg_ref_type make_arg_ref(auto_id) { const char *error = 0; auto index = context_.next_arg_index(error); if (error) diff --git a/test/format-test.cc b/test/format-test.cc index 48f6c439..e9826d38 100644 --- a/test/format-test.cc +++ b/test/format-test.cc @@ -1693,6 +1693,8 @@ struct test_context { template constexpr void check_arg_id(Id) {} + + constexpr unsigned next_arg_index(const char *&) { return 33; } }; constexpr fmt::format_specs parse_specs(const char *s) { @@ -1719,3 +1721,29 @@ TEST(FormatTest, ConstexprSpecsHandler) { static_assert(parse_specs(".{0}").precision() == 22, ""); static_assert(parse_specs("d").type() == 'd', ""); } + +constexpr fmt::internal::dynamic_format_specs + parse_dynamic_specs(const char *s) { + fmt::internal::dynamic_format_specs specs; + test_context ctx; + fmt::internal::dynamic_specs_handler h(specs, ctx); + parse_format_specs(s, h); + return specs; +} + +TEST(FormatTest, ConstexprDynamicSpecsHandler) { + static_assert(parse_dynamic_specs("<").align() == fmt::ALIGN_LEFT, ""); + static_assert(parse_dynamic_specs("*^").fill() == '*', ""); + static_assert(parse_dynamic_specs("+").flag(fmt::PLUS_FLAG), ""); + static_assert(parse_dynamic_specs("-").flag(fmt::MINUS_FLAG), ""); + static_assert(parse_dynamic_specs(" ").flag(fmt::SIGN_FLAG), ""); + static_assert(parse_dynamic_specs("#").flag(fmt::HASH_FLAG), ""); + static_assert(parse_dynamic_specs("0").align() == fmt::ALIGN_NUMERIC, ""); + static_assert(parse_dynamic_specs("42").width() == 42, ""); + static_assert(parse_dynamic_specs("{}").width_ref.index == 33, ""); + static_assert(parse_dynamic_specs("{42}").width_ref.index == 42, ""); + static_assert(parse_dynamic_specs(".42").precision() == 42, ""); + static_assert(parse_dynamic_specs(".{}").precision_ref.index == 33, ""); + static_assert(parse_dynamic_specs(".{42}").precision_ref.index == 42, ""); + static_assert(parse_dynamic_specs("d").type() == 'd', ""); +} From dd0b72e1ee393f1eeac7393dc37f909b76239317 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sun, 22 Oct 2017 14:44:52 -0700 Subject: [PATCH 183/340] Remove refactoring artefacts --- include/fmt/format.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/fmt/format.h b/include/fmt/format.h index 1093bb5b..54cdbe2d 100644 --- a/include/fmt/format.h +++ b/include/fmt/format.h @@ -3148,7 +3148,7 @@ class specs_setter : public error_handler { template class specs_checker : public Handler { public: - explicit specs_checker(const Handler& handler, type arg_type) + specs_checker(const Handler& handler, type arg_type) : Handler(handler), arg_type_(arg_type) {} void on_align(alignment align) { @@ -3537,7 +3537,7 @@ template struct format_enum : std::integral_constant::value> {}; template -static void handle_dynamic_spec( +void handle_dynamic_spec( Spec &value, arg_ref ref, basic_context &ctx) { switch (ref.kind) { case arg_ref::NONE: From aadb38a5e6190a647035321cc988430abea22ffa Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Mon, 23 Oct 2017 21:02:54 -0700 Subject: [PATCH 184/340] Make specs_checker constexpr --- include/fmt/format.h | 79 +++++++++++++++++++++++++------------------- test/format-test.cc | 24 ++++++++++++++ 2 files changed, 69 insertions(+), 34 deletions(-) diff --git a/include/fmt/format.h b/include/fmt/format.h index 54cdbe2d..298db537 100644 --- a/include/fmt/format.h +++ b/include/fmt/format.h @@ -1088,12 +1088,12 @@ enum type { CSTRING, STRING, TSTRING, POINTER, CUSTOM }; -inline bool is_integral(type t) { +constexpr bool is_integral(type t) { FMT_ASSERT(t != internal::NAMED_ARG, "invalid argument type"); return t > internal::NONE && t <= internal::LAST_INTEGER_TYPE; } -inline bool is_numeric(type t) { +constexpr bool is_numeric(type t) { FMT_ASSERT(t != internal::NAMED_ARG, "invalid argument type"); return t > internal::NONE && t <= internal::LAST_NUMERIC_TYPE; } @@ -2378,11 +2378,8 @@ void basic_writer::write_str( internal::report_unknown_type(spec.type_, "string"); const StrChar *str_value = s.data(); std::size_t str_size = s.size(); - if (str_size == 0) { - if (!str_value) { - FMT_THROW(format_error("string pointer is null")); - } - } + if (str_size == 0 && !str_value) + FMT_THROW(format_error("string pointer is null")); std::size_t precision = static_cast(spec.precision_); if (spec.precision_ >= 0 && precision < str_size) str_size = precision; @@ -3072,38 +3069,52 @@ struct is_integer { }; }; -struct width_checker { +template +class width_checker { + public: + explicit constexpr width_checker(ErrorHandler &eh) : handler_(eh) {} + template constexpr typename std::enable_if< is_integer::value, unsigned long long>::type operator()(T value) { if (is_negative(value)) - FMT_THROW(format_error("negative width")); + handler_.on_error("negative width"); return value; } template constexpr typename std::enable_if< !is_integer::value, unsigned long long>::type operator()(T) { - FMT_THROW(format_error("width is not integer")); + handler_.on_error("width is not integer"); return 0; } + + private: + ErrorHandler &handler_; }; -struct precision_checker { +template +class precision_checker { + public: + explicit constexpr precision_checker(ErrorHandler &eh) : handler_(eh) {} + template constexpr typename std::enable_if< is_integer::value, unsigned long long>::type operator()(T value) { if (is_negative(value)) - FMT_THROW(format_error("negative precision")); + handler_.on_error("negative precision"); return value; } template constexpr typename std::enable_if< !is_integer::value, unsigned long long>::type operator()(T) { - FMT_THROW(format_error("precision is not integer")); + handler_.on_error("precision is not integer"); return 0; } + + private: + ErrorHandler &handler_; }; struct error_handler { @@ -3148,41 +3159,41 @@ class specs_setter : public error_handler { template class specs_checker : public Handler { public: - specs_checker(const Handler& handler, type arg_type) + constexpr specs_checker(const Handler& handler, internal::type arg_type) : Handler(handler), arg_type_(arg_type) {} - void on_align(alignment align) { + constexpr void on_align(alignment align) { if (align == ALIGN_NUMERIC) require_numeric_argument('='); Handler::on_align(align); } - void on_plus() { + constexpr void on_plus() { check_sign('+'); Handler::on_plus(); } - void on_minus() { + constexpr void on_minus() { check_sign('-'); Handler::on_minus(); } - void on_space() { + constexpr void on_space() { check_sign(' '); Handler::on_space(); } - void on_hash() { + constexpr void on_hash() { require_numeric_argument('#'); Handler::on_hash(); } - void on_zero() { + constexpr void on_zero() { require_numeric_argument('0'); Handler::on_zero(); } - void end_precision() { + constexpr void end_precision() { if (is_integral(arg_type_) || arg_type_ == POINTER) { report_error("precision not allowed in {} format specifier", arg_type_ == POINTER ? "pointer" : "integer"); @@ -3191,12 +3202,12 @@ class specs_checker : public Handler { private: template - static void report_error(string_view format_str, const Args &... args) { - FMT_THROW(format_error(format(format_str, args...))); + void report_error(string_view format_str, const Args &... args) { + this->on_error(format(format_str, args...).c_str()); } template - void require_numeric_argument(Char spec) const { + constexpr void require_numeric_argument(Char spec) { if (!is_numeric(arg_type_)) { report_error("format specifier '{}' requires numeric argument", static_cast(spec)); @@ -3204,7 +3215,7 @@ class specs_checker : public Handler { } template - void check_sign(Char sign) const { + constexpr void check_sign(Char sign) { require_numeric_argument(sign); if (is_integral(arg_type_) && arg_type_ != INT && arg_type_ != LONG_LONG && arg_type_ != CHAR) { @@ -3213,14 +3224,15 @@ class specs_checker : public Handler { } } - type arg_type_; + internal::type arg_type_; }; -template +template