From bfdca8b576dee8ff84c90f751bd6a7ee30c8a6c8 Mon Sep 17 00:00:00 2001 From: vitaut Date: Wed, 20 Apr 2016 09:11:33 -0700 Subject: [PATCH] Make ArgVisitor public and document it Also remove unnecessary namespace qualification. --- cppformat/format.cc | 75 ++++++++-------- cppformat/format.h | 206 +++++++++++++++++++++++--------------------- doc/api.rst | 3 + test/util-test.cc | 16 ++-- 4 files changed, 157 insertions(+), 143 deletions(-) diff --git a/cppformat/format.cc b/cppformat/format.cc index daccd68f..4484b930 100644 --- a/cppformat/format.cc +++ b/cppformat/format.cc @@ -129,7 +129,7 @@ struct IntChecker { const char RESET_COLOR[] = "\x1b[0m"; -typedef void (*FormatFunc)(fmt::Writer &, int, fmt::StringRef); +typedef void (*FormatFunc)(Writer &, int, StringRef); // Portable thread-safe version of strerror. // Sets buffer to point to a string describing the error code. @@ -169,7 +169,7 @@ int safe_strerror( } // Handle the case when strerror_r is not available. - int handle(fmt::internal::Null<>) { + int handle(internal::Null<>) { return fallback(strerror_s(buffer_, buffer_size_, error_code_)); } @@ -181,7 +181,7 @@ int safe_strerror( } // Fallback to strerror if strerror_r and strerror_s are not available. - int fallback(fmt::internal::Null<>) { + int fallback(internal::Null<>) { errno = 0; buffer_ = strerror(error_code_); return errno; @@ -199,8 +199,8 @@ int safe_strerror( return StrError(error_code, buffer, buffer_size).run(); } -void format_error_code(fmt::Writer &out, int error_code, - fmt::StringRef message) FMT_NOEXCEPT { +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 // bad_alloc. @@ -209,22 +209,22 @@ void format_error_code(fmt::Writer &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 fmt::internal::IntTraits::MainType MainType; + typedef internal::IntTraits::MainType MainType; MainType abs_value = static_cast(error_code); if (internal::is_negative(error_code)) { abs_value = 0 - abs_value; ++error_code_size; } - error_code_size += fmt::internal::count_digits(abs_value); - if (message.size() <= fmt::internal::INLINE_BUFFER_SIZE - 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; - assert(out.size() <= fmt::internal::INLINE_BUFFER_SIZE); + assert(out.size() <= internal::INLINE_BUFFER_SIZE); } -void report_error(FormatFunc func, - int error_code, fmt::StringRef message) FMT_NOEXCEPT { - fmt::MemoryWriter full_message; +void report_error(FormatFunc func, int error_code, + StringRef message) FMT_NOEXCEPT { + MemoryWriter full_message; func(full_message, error_code, message); // Use Writer::data instead of Writer::c_str to avoid potential memory // allocation. @@ -233,7 +233,7 @@ void report_error(FormatFunc func, } // IsZeroInt::visit(arg) returns true iff arg is a zero integer. -class IsZeroInt : public fmt::internal::ArgVisitor { +class IsZeroInt : public ArgVisitor { public: template bool visit_any_int(T value) { return value == 0; } @@ -241,44 +241,43 @@ class IsZeroInt : public fmt::internal::ArgVisitor { // Checks if an argument is a valid printf width specifier and sets // left alignment if it is negative. -class WidthHandler : public fmt::internal::ArgVisitor { +class WidthHandler : public ArgVisitor { private: - fmt::FormatSpec &spec_; + FormatSpec &spec_; FMT_DISALLOW_COPY_AND_ASSIGN(WidthHandler); public: - explicit WidthHandler(fmt::FormatSpec &spec) : spec_(spec) {} + explicit WidthHandler(FormatSpec &spec) : spec_(spec) {} void report_unhandled_arg() { - FMT_THROW(fmt::FormatError("width is not integer")); + FMT_THROW(FormatError("width is not integer")); } template unsigned visit_any_int(T value) { - typedef typename fmt::internal::IntTraits::MainType UnsignedType; + typedef typename internal::IntTraits::MainType UnsignedType; UnsignedType width = static_cast(value); - if (fmt::internal::is_negative(value)) { - spec_.align_ = fmt::ALIGN_LEFT; + if (internal::is_negative(value)) { + spec_.align_ = ALIGN_LEFT; width = 0 - width; } if (width > INT_MAX) - FMT_THROW(fmt::FormatError("number is too big")); + FMT_THROW(FormatError("number is too big")); return static_cast(width); } }; -class PrecisionHandler : - public fmt::internal::ArgVisitor { +class PrecisionHandler : public ArgVisitor { public: void report_unhandled_arg() { - FMT_THROW(fmt::FormatError("precision is not integer")); + FMT_THROW(FormatError("precision is not integer")); } template int visit_any_int(T value) { if (!IntChecker::is_signed>::fits_in_int(value)) - FMT_THROW(fmt::FormatError("number is too big")); + FMT_THROW(FormatError("number is too big")); return static_cast(value); } }; @@ -298,15 +297,15 @@ struct is_same { // corresponding signed or unsigned type depending on the type specifier: // 'd' and 'i' - signed, other - unsigned) template -class ArgConverter : public fmt::internal::ArgVisitor, void> { +class ArgConverter : public ArgVisitor, void> { private: - fmt::internal::Arg &arg_; + internal::Arg &arg_; wchar_t type_; FMT_DISALLOW_COPY_AND_ASSIGN(ArgConverter); public: - ArgConverter(fmt::internal::Arg &arg, wchar_t type) + ArgConverter(internal::Arg &arg, wchar_t type) : arg_(arg), type_(type) {} void visit_bool(bool value) { @@ -317,8 +316,8 @@ class ArgConverter : public fmt::internal::ArgVisitor, void> { template void visit_any_int(U value) { bool is_signed = type_ == 'd' || type_ == 'i'; - using fmt::internal::Arg; - typedef typename fmt::internal::Conditional< + 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. @@ -327,7 +326,7 @@ class ArgConverter : public fmt::internal::ArgVisitor, void> { arg_.int_value = static_cast(static_cast(value)); } else { arg_.type = Arg::UINT; - typedef typename fmt::internal::MakeUnsigned::Type Unsigned; + typedef typename internal::MakeUnsigned::Type Unsigned; arg_.uint_value = static_cast(static_cast(value)); } } else { @@ -336,35 +335,35 @@ class ArgConverter : public fmt::internal::ArgVisitor, void> { // 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_.long_long_value = static_cast(value); } else { arg_.type = Arg::ULONG_LONG; arg_.ulong_long_value = - static_cast::Type>(value); + static_cast::Type>(value); } } } }; // Converts an integer argument to char for printf. -class CharConverter : public fmt::internal::ArgVisitor { +class CharConverter : public ArgVisitor { private: - fmt::internal::Arg &arg_; + internal::Arg &arg_; FMT_DISALLOW_COPY_AND_ASSIGN(CharConverter); public: - explicit CharConverter(fmt::internal::Arg &arg) : arg_(arg) {} + explicit CharConverter(internal::Arg &arg) : arg_(arg) {} template void visit_any_int(T value) { - arg_.type = Arg::CHAR; + arg_.type = internal::Arg::CHAR; arg_.int_value = static_cast(value); } }; // Write the content of w to os. -void write(std::ostream &os, fmt::Writer &w) { +void write(std::ostream &os, Writer &w) { const char *data = w.data(); typedef internal::MakeUnsigned::Type UnsignedStreamSize; UnsignedStreamSize size = w.size(); diff --git a/cppformat/format.h b/cppformat/format.h index 0be1bfbf..46a03965 100644 --- a/cppformat/format.h +++ b/cppformat/format.h @@ -1305,30 +1305,114 @@ struct NamedArg : Arg { : Arg(MakeArg< BasicFormatter >(value)), name(argname) {} }; +class RuntimeError : public std::runtime_error { + protected: + RuntimeError() : std::runtime_error("") {} +}; + +template +class PrintfArgFormatter; + +template +class ArgMap; +} // namespace internal + +/** An argument list. */ +class ArgList { + private: + // To reduce compiled code size per formatting function call, types of first + // MAX_PACKED_ARGS arguments are passed in the types_ field. + uint64_t types_; + union { + // If the number of arguments is less than MAX_PACKED_ARGS, the argument + // values are stored in values_, otherwise they are stored in 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::Arg *args_; + }; + + internal::Arg::Type type(unsigned index) const { + unsigned shift = index * 4; + uint64_t mask = 0xf; + return static_cast( + (types_ & (mask << shift)) >> shift); + } + + template + friend class internal::ArgMap; + + public: + // Maximum number of arguments with packed types. + enum { MAX_PACKED_ARGS = 16 }; + + ArgList() : types_(0) {} + + ArgList(ULongLong types, const internal::Value *values) + : types_(types), values_(values) {} + ArgList(ULongLong types, const internal::Arg *args) + : types_(types), args_(args) {} + + /** 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) { + Arg::Type arg_type = type(index); + internal::Value &val = arg; + if (arg_type != 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 = Arg::NONE; + return arg; + } + for (unsigned i = MAX_PACKED_ARGS; i <= index; ++i) { + if (args_[i].type == Arg::NONE) + return args_[i]; + } + return args_[index]; + } +}; + #define FMT_DISPATCH(call) static_cast(this)->call -// An argument visitor. -// To use ArgVisitor define a subclass that implements some or all of the -// visit methods with the same signatures as the methods in ArgVisitor, -// for example, visit_int(int). -// Pass the subclass as the Impl template parameter. Then calling -// 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 visit_double(double) method of a subclass will be called. -// If the subclass doesn't contain a method with this signature, then -// a corresponding method of ArgVisitor will be called. -// -// Example: -// class MyArgVisitor : public ArgVisitor { -// public: -// void visit_int(int value) { print("{}", value); } -// void visit_double(double value) { print("{}", value ); } -// }; -// -// ArgVisitor uses the curiously recurring template pattern: -// http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern +/** + \rst + An argument visitor. + 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, `visit_int(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 `visit_double(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 ); } + }; + + `~fmt::ArgVisitor` uses the `curiously recurring template pattern + `_. + \endrst + */ template class ArgVisitor { + private: + typedef internal::Arg Arg; + public: void report_unhandled_arg() {} @@ -1422,82 +1506,6 @@ class ArgVisitor { } }; -class RuntimeError : public std::runtime_error { - protected: - RuntimeError() : std::runtime_error("") {} -}; - -template -class PrintfArgFormatter; - -template -class ArgMap; -} // namespace internal - -/** An argument list. */ -class ArgList { - private: - // To reduce compiled code size per formatting function call, types of first - // MAX_PACKED_ARGS arguments are passed in the types_ field. - uint64_t types_; - union { - // If the number of arguments is less than MAX_PACKED_ARGS, the argument - // values are stored in values_, otherwise they are stored in 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::Arg *args_; - }; - - internal::Arg::Type type(unsigned index) const { - unsigned shift = index * 4; - uint64_t mask = 0xf; - return static_cast( - (types_ & (mask << shift)) >> shift); - } - - template - friend class internal::ArgMap; - - public: - // Maximum number of arguments with packed types. - enum { MAX_PACKED_ARGS = 16 }; - - ArgList() : types_(0) {} - - ArgList(ULongLong types, const internal::Value *values) - : types_(types), values_(values) {} - ArgList(ULongLong types, const internal::Arg *args) - : types_(types), args_(args) {} - - /** 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) { - Arg::Type arg_type = type(index); - internal::Value &val = arg; - if (arg_type != 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 = Arg::NONE; - return arg; - } - for (unsigned i = MAX_PACKED_ARGS; i <= index; ++i) { - if (args_[i].type == Arg::NONE) - return args_[i]; - } - return args_[index]; - } -}; - enum Alignment { ALIGN_DEFAULT, ALIGN_LEFT, ALIGN_RIGHT, ALIGN_CENTER, ALIGN_NUMERIC }; @@ -1911,9 +1919,9 @@ class PrintfFormatter : private FormatterBase { /** \rst An argument formatter. - To use `~fmt::BasicArgFormatter` define a subclass that implements some or all - of the visit methods with the same signatures as the methods in `ArgVisitor`, - for example, `visit_int(int)`. + 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, `visit_int(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 diff --git a/doc/api.rst b/doc/api.rst index 347dc649..618b5130 100644 --- a/doc/api.rst +++ b/doc/api.rst @@ -42,6 +42,9 @@ arguments in the resulting string. Argument formatters ------------------- +.. doxygenclass:: fmt::ArgVisitor + :members: + .. doxygenclass:: fmt::BasicArgFormatter :members: diff --git a/test/util-test.cc b/test/util-test.cc index df754b25..285fbb69 100644 --- a/test/util-test.cc +++ b/test/util-test.cc @@ -603,7 +603,7 @@ struct Result { Result(const wchar_t *s) : arg(make_arg(s)) {} }; -struct TestVisitor : fmt::internal::ArgVisitor { +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; } @@ -612,10 +612,14 @@ struct TestVisitor : fmt::internal::ArgVisitor { 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(Arg::StringValue s) { return s.value; } - Result visit_wstring(Arg::StringValue s) { return s.value; } + Result visit_string(fmt::internal::Arg::StringValue s) { + return s.value; + } + Result visit_wstring(fmt::internal::Arg::StringValue s) { + return s.value; + } Result visit_pointer(const void *p) { return p; } - Result visit_custom(Arg::CustomValue c) { + Result visit_custom(fmt::internal::Arg::CustomValue c) { return *static_cast(c.value); } }; @@ -652,7 +656,7 @@ TEST(ArgVisitorTest, VisitAll) { EXPECT_EQ(&t, result.arg.custom.value); } -struct TestAnyVisitor : fmt::internal::ArgVisitor { +struct TestAnyVisitor : fmt::ArgVisitor { template Result visit_any_int(T value) { return value; } @@ -677,7 +681,7 @@ TEST(ArgVisitorTest, VisitAny) { } struct TestUnhandledVisitor : - fmt::internal::ArgVisitor { + fmt::ArgVisitor { const char *visit_unhandled_arg() { return "test"; } };