From f2c4b6554919ef95a082b203e73e22f4e0a720ad Mon Sep 17 00:00:00 2001 From: Jamboree Date: Sat, 6 Jun 2015 01:59:11 +0800 Subject: [PATCH] Support named arguments (done) --- doc/api.rst | 4 + format.cc | 89 +++++++------ format.h | 318 +++++++++++++++++++++++++------------------- posix.h | 4 +- test/format-test.cc | 6 +- 5 files changed, 241 insertions(+), 180 deletions(-) diff --git a/doc/api.rst b/doc/api.rst index 5464f08b..725f2ec1 100644 --- a/doc/api.rst +++ b/doc/api.rst @@ -72,6 +72,10 @@ Write API Utilities ========= +.. doxygenfunction:: fmt::arg(StringRef, const T&) + +.. doxygendefine:: FMT_CAPTURE + .. doxygendefine:: FMT_VARIADIC .. doxygenclass:: fmt::ArgList diff --git a/format.cc b/format.cc index 398a2bbc..1083f638 100644 --- a/format.cc +++ b/format.cc @@ -268,7 +268,7 @@ int parse_nonnegative_int(const Char *&s) { template inline bool is_name_start(Char c) { - return 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' || '_' == c; + return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || '_' == c; } inline void require_numeric_argument(const Arg &arg, char spec) { @@ -408,10 +408,10 @@ inline Arg::StringValue ignore_incompatible_str( } // namespace FMT_FUNC void fmt::SystemError::init( - int err_code, StringRef format_str, ArgList args, const ArgMap &map) { + int err_code, StringRef format_str, ArgList args) { error_code_ = err_code; MemoryWriter w; - internal::format_system_error(w, err_code, format(format_str, args, map)); + internal::format_system_error(w, err_code, format(format_str, args)); std::runtime_error &base = *this; base = std::runtime_error(w.str()); } @@ -524,10 +524,10 @@ FMT_FUNC int fmt::internal::UTF16ToUTF8::convert(fmt::WStringRef s) { } FMT_FUNC void fmt::WindowsError::init( - int err_code, StringRef format_str, ArgList args, const ArgMap &map) { + int err_code, StringRef format_str, ArgList args) { error_code_ = err_code; MemoryWriter w; - internal::format_windows_error(w, err_code, format(format_str, args, map)); + internal::format_windows_error(w, err_code, format(format_str, args)); std::runtime_error &base = *this; base = std::runtime_error(w.str()); } @@ -700,21 +700,18 @@ inline Arg fmt::BasicFormatter::parse_arg_index(const Char *&s) { } template -inline Arg fmt::BasicFormatter::parse_arg_name(const Char *&s, const fmt::BasicArgMap &map) { - assert(is_name_start(*s)); - const Char *start = s; - Char c; - do { - c = *++s; - } while ('a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' || '0' <= c && c <= '9'); - const int* index = map.find(fmt::BasicStringRef(start, s - start)); - if (!index) - FMT_THROW(fmt::FormatError("argument not found")); - const char *error = 0; - Arg arg = get_arg(*index, error); - if (error) - FMT_THROW(fmt::FormatError(error)); - return arg; +inline Arg fmt::BasicFormatter::parse_arg_name(const Char *&s) { + assert(is_name_start(*s)); + const Char *start = s; + Char c; + do { + c = *++s; + } while (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || ('0' <= c && c <= '9')); + const char *error = 0; + Arg arg = get_arg(fmt::BasicStringRef(start, s - start), error); + if (error) + FMT_THROW(fmt::FormatError(error)); + return arg; } FMT_FUNC Arg fmt::internal::FormatterBase::do_get_arg( @@ -742,6 +739,18 @@ inline Arg fmt::internal::FormatterBase::get_arg( return Arg(); } +template +inline Arg fmt::internal::FormatterBase::get_arg( + const BasicStringRef& arg_name, const char *&error) { + const BasicArgMap* map = args_.get_arg_map(); + assert(map); + const unsigned* index = map->find(arg_name); + if (index) + return get_arg(*index, error); + error = "argument not found"; + return Arg(); +} + template void fmt::internal::PrintfFormatter::parse_flags( FormatSpec &spec, const Char *&s) { @@ -984,7 +993,7 @@ void fmt::internal::PrintfFormatter::format( template const Char *fmt::BasicFormatter::format( - const Char *&format_str, const Arg &arg, const BasicArgMap &map) { + const Char *&format_str, const Arg &arg) { const Char *s = format_str; FormatSpec spec; if (*s == ':') { @@ -1062,7 +1071,7 @@ const Char *fmt::BasicFormatter::format( spec.width_ = parse_nonnegative_int(s); } else if (*s == '{') { ++s; - const Arg &width_arg = is_name_start(*s) ? parse_arg_name(s, map) : parse_arg_index(s); + const Arg &width_arg = is_name_start(*s) ? parse_arg_name(s) : parse_arg_index(s); if (*s++ != '}') FMT_THROW(FormatError("invalid format string")); ULongLong value = 0; @@ -1099,7 +1108,7 @@ const Char *fmt::BasicFormatter::format( spec.precision_ = parse_nonnegative_int(s); } else if (*s == '{') { ++s; - const Arg &precision_arg = is_name_start(*s) ? parse_arg_name(s, map) : parse_arg_index(s); + const Arg &precision_arg = is_name_start(*s) ? parse_arg_name(s) : parse_arg_index(s); if (*s++ != '}') FMT_THROW(FormatError("invalid format string")); ULongLong value = 0; @@ -1152,7 +1161,7 @@ const Char *fmt::BasicFormatter::format( template void fmt::BasicFormatter::format( - BasicStringRef format_str, const ArgList &args, const BasicArgMap &map) { + BasicStringRef format_str, const ArgList &args) { const Char *s = start_ = format_str.c_str(); set_args(args); while (*s) { @@ -1166,8 +1175,8 @@ void fmt::BasicFormatter::format( if (c == '}') FMT_THROW(FormatError("unmatched '}' in format string")); write(writer_, start_, s - 1); - Arg arg = is_name_start(*s) ? parse_arg_name(s, map) : parse_arg_index(s); - s = format(s, arg, map); + Arg arg = is_name_start(*s) ? parse_arg_name(s) : parse_arg_index(s); + s = format(s, arg); } write(writer_, start_, s); } @@ -1184,33 +1193,33 @@ FMT_FUNC void fmt::report_windows_error( } #endif -FMT_FUNC void fmt::print(std::FILE *f, StringRef format_str, ArgList args, const ArgMap &map) { +FMT_FUNC void fmt::print(std::FILE *f, StringRef format_str, ArgList args) { MemoryWriter w; - w.write(format_str, args, map); + w.write(format_str, args); std::fwrite(w.data(), 1, w.size(), f); } -FMT_FUNC void fmt::print(StringRef format_str, ArgList args, const ArgMap &map) { - print(stdout, format_str, args, map); +FMT_FUNC void fmt::print(StringRef format_str, ArgList args) { + print(stdout, format_str, args); } -FMT_FUNC void fmt::print(std::ostream &os, StringRef format_str, ArgList args, const ArgMap &map) { +FMT_FUNC void fmt::print(std::ostream &os, StringRef format_str, ArgList args) { MemoryWriter w; - w.write(format_str, args, map); + w.write(format_str, args); os.write(w.data(), w.size()); } -FMT_FUNC void fmt::print_colored(Color c, StringRef format, ArgList args, const ArgMap &map) { +FMT_FUNC void fmt::print_colored(Color c, StringRef format, ArgList args) { char escape[] = "\x1b[30m"; escape[3] = '0' + static_cast(c); std::fputs(escape, stdout); - print(format, args, map); + print(format, args); std::fputs(RESET_COLOR, stdout); } -FMT_FUNC int fmt::fprintf(std::FILE *f, StringRef format, ArgList args, const ArgMap &map) { +FMT_FUNC int fmt::fprintf(std::FILE *f, StringRef format, ArgList args) { MemoryWriter w; - printf(w, format, args, map); + printf(w, format, args); std::size_t size = w.size(); return std::fwrite(w.data(), 1, size, f) < size ? -1 : static_cast(size); } @@ -1224,10 +1233,10 @@ template struct fmt::internal::BasicData; template void fmt::internal::FixedBuffer::grow(std::size_t); template const char *fmt::BasicFormatter::format( - const char *&format_str, const fmt::internal::Arg &arg, const BasicArgMap &map); + const char *&format_str, const fmt::internal::Arg &arg); template void fmt::BasicFormatter::format( - BasicStringRef format, const ArgList &args, const BasicArgMap &map); + BasicStringRef format, const ArgList &args); template void fmt::internal::PrintfFormatter::format( BasicWriter &writer, BasicStringRef format, const ArgList &args); @@ -1245,10 +1254,10 @@ template int fmt::internal::CharTraits::format_float( template void fmt::internal::FixedBuffer::grow(std::size_t); template const wchar_t *fmt::BasicFormatter::format( - const wchar_t *&format_str, const fmt::internal::Arg &arg, const BasicArgMap &map); + const wchar_t *&format_str, const fmt::internal::Arg &arg); template void fmt::BasicFormatter::format( - BasicStringRef format, const ArgList &args, const BasicArgMap &map); + BasicStringRef format, const ArgList &args); template void fmt::internal::PrintfFormatter::format( BasicWriter &writer, BasicStringRef format, diff --git a/format.h b/format.h index 3fd5ba4a..7fc80cba 100644 --- a/format.h +++ b/format.h @@ -768,12 +768,11 @@ struct Value { }; template -struct NamedArg -{ - BasicStringRef name; - T const& arg; +struct NamedArg { + BasicStringRef name; + T const& arg; - NamedArg(BasicStringRef name, T const& arg) : name(name), arg(arg) {} + NamedArg(BasicStringRef name, T const& arg) : name(name), arg(arg) {} }; // A formatting argument. It is a POD type to allow storage in @@ -980,47 +979,13 @@ class MakeValue : public Arg { }; template -inline const T &strip_name(const T &arg) -{ - return arg; +inline const T &strip_name(const T &arg) { + return arg; } template -inline const T &strip_name(const NamedArg &namedArg) -{ - return namedArg.arg; -} - -template -struct NamedArgsCounter -{ - static const int value = 0; -}; - -template -struct NamedArgsCounter : NamedArgsCounter -{}; - -template -struct NamedArgsCounter, U...> -{ - static const int value = 1 + NamedArgsCounter::value; -}; - -template -inline void add_named_args(NameIndexPair*) {} - -template -inline void add_named_args(NameIndexPair* map, T const&, U const&... rest) -{ - add_named_args(map, rest...); -} - -template -inline void add_named_args(NameIndexPair* map, const NamedArg &namedArg, U const&... rest) -{ - *map = NameIndexPair(namedArg.name, N); - add_named_args(map + 1, rest...); +inline const T &strip_name(const NamedArg &namedArg) { + return namedArg.arg; } #define FMT_DISPATCH(call) static_cast(this)->call @@ -1142,6 +1107,45 @@ class RuntimeError : public std::runtime_error { template class ArgFormatter; + +template +struct BasicArgMap { + typedef std::pair, unsigned> value_type; + + struct Compare { + bool operator()(const value_type &lhs, const value_type &rhs) const { + return lhs.first < rhs.first; + } + }; + + BasicArgMap() : map_(), size_() {} + + BasicArgMap(value_type* map, unsigned size) + : map_(map), size_(size) { + std::sort(map, map + size, Compare()); + } + + const unsigned* find(BasicStringRef name) const { + value_type* first = map_; + value_type* last = map_ + size_; + while (first != last) + { + value_type* it(first + ((last - first) >> 1)); + if (name < it->first) + last = it; + else if (it->first < name) + first = ++it; + else + return &it->second; + } + return 0; + } + +private: + + value_type* map_; + unsigned size_; +}; } // namespace internal /** An argument list. */ @@ -1159,6 +1163,7 @@ class ArgList { const internal::Value *values_; const internal::Arg *args_; }; + const void* map_; internal::Arg::Type type(unsigned index) const { unsigned shift = index * 4; @@ -1171,12 +1176,15 @@ class ArgList { // Maximum number of arguments with packed types. enum { MAX_PACKED_ARGS = 16 }; - ArgList() : types_(0) {} + ArgList() : types_(0), map_() {} - ArgList(ULongLong types, const internal::Value *values) - : types_(types), values_(values) {} - ArgList(ULongLong types, const internal::Arg *args) - : types_(types), args_(args) {} + template + ArgList(ULongLong types, const internal::Value *values, const internal::BasicArgMap* map) + : types_(types), values_(values), map_(map) {} + + template + ArgList(ULongLong types, const internal::Arg *args, const internal::BasicArgMap* map) + : types_(types), args_(args), map_(map) {} /** Returns the argument at specified index. */ internal::Arg operator[](unsigned index) const { @@ -1203,52 +1211,15 @@ class ArgList { } return args_[index]; } + + template + const internal::BasicArgMap* get_arg_map() const { + return static_cast*>(map_); + } }; struct FormatSpec; -template -struct BasicArgMap -{ - typedef std::pair, int> value_type; - - BasicArgMap() : map_(), size_() {} - - BasicArgMap(value_type* map, int size) - : map_(map), size_(size) - { - std::sort(map, map + size, [](const value_type &lhs, const value_type &rhs) - { - return lhs.first < rhs.first; - }); - } - - const int* find(BasicStringRef name) const - { - value_type* first = map_; - value_type* last = map_ + size_; - while (first != last) - { - value_type* it(first + (last - first >> 1)); - if (name < it->first) - last = it; - else if (it->first < name) - first = ++it; - else - return &it->second; - } - return nullptr; - } - -private: - - value_type* map_; - int size_; -}; - -typedef BasicArgMap ArgMap; -typedef BasicArgMap WArgMap; - namespace internal { class FormatterBase { @@ -1272,6 +1243,11 @@ class FormatterBase { // specified index. Arg get_arg(unsigned arg_index, const char *&error); + // Checks if manual indexing is used and returns the argument with + // specified name. + template + Arg get_arg(const BasicStringRef& arg_name, const char *&error); + template void write(BasicWriter &w, const Char *start, const Char *end) { if (start != end) @@ -1312,16 +1288,16 @@ class BasicFormatter : private internal::FormatterBase { internal::Arg parse_arg_index(const Char *&s); // Parses argument name and returns corresponding argument. - internal::Arg parse_arg_name(const Char *&s, const BasicArgMap &map); + internal::Arg parse_arg_name(const Char *&s); public: explicit BasicFormatter(BasicWriter &w) : writer_(w) {} BasicWriter &writer() { return writer_; } - void format(BasicStringRef format_str, const ArgList &args, const BasicArgMap &map); + void format(BasicStringRef format_str, const ArgList &args); - const Char *format(const Char *&format_str, const internal::Arg &arg, const BasicArgMap &map); + const Char *format(const Char *&format_str, const internal::Arg &arg); }; enum Alignment { @@ -1582,6 +1558,14 @@ struct ArgArray { (N < ArgList::MAX_PACKED_ARGS), Value, Arg>::type Type[SIZE]; }; +template +inline void add_named_arg(NameIndexPair* map, T const&, unsigned) {} + +template +inline void add_named_arg(NameIndexPair*& map, const NamedArg &namedArg, unsigned n) { + *map++ = NameIndexPair(namedArg.name, n); +} + #if FMT_USE_VARIADIC_TEMPLATES template inline uint64_t make_type(const Arg &first, const Args & ... tail) { @@ -1622,12 +1606,36 @@ inline void store_args(Arg *args, const T &arg, const Args & ... tail) { template ArgList make_arg_list(typename ArgArray::Type array, + const BasicArgMap* map, const Args & ... args) { if (check(sizeof...(Args) >= ArgList::MAX_PACKED_ARGS)) set_types(array, args...); store_args(array, args...); - return ArgList(make_type(args...), array); + return ArgList(make_type(args...), array, map); } + +template +struct NamedArgsCounter { + static const int value = 0; +}; + +template +struct NamedArgsCounter : NamedArgsCounter {}; + +template +struct NamedArgsCounter, U...> { + static const int value = 1 + NamedArgsCounter::value; +}; + +template +inline void add_named_args(NameIndexPair*) {} + +template +inline void add_named_args(NameIndexPair* map, const T &arg, const U &... rest) { + add_named_arg(map, arg, N); + add_named_args(map, rest...); +} + #else struct ArgType { @@ -1653,8 +1661,6 @@ inline uint64_t make_type(FMT_GEN15(FMT_ARG_TYPE_DEFAULT)) { # 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_MAKE_REF_char(n) fmt::internal::MakeValue(v##n) -# define FMT_MAKE_REF_wchar_t(n) fmt::internal::MakeValue(v##n) #if FMT_USE_VARIADIC_TEMPLATES // Defines a variadic function returning void. @@ -1663,10 +1669,10 @@ inline uint64_t make_type(FMT_GEN15(FMT_ARG_TYPE_DEFAULT)) { void func(arg_type arg0, const Args & ... args) { \ typename fmt::internal::ArgArray::Type array; \ const int count = fmt::internal::NamedArgsCounter::value; \ - fmt::BasicArgMap::value_type mapArray[count + 1]; \ + typename fmt::internal::BasicArgMap::value_type mapArray[count + 1]; \ fmt::internal::add_named_args<0>(mapArray, args...); \ - fmt::BasicArgMap map(mapArray, count); \ - func(arg0, fmt::internal::make_arg_list(array, fmt::internal::strip_name(args)...), map); \ + fmt::internal::BasicArgMap map(mapArray, count); \ + func(arg0, fmt::internal::make_arg_list(array, &map, fmt::internal::strip_name(args)...)); \ } // Defines a variadic constructor. @@ -1675,25 +1681,31 @@ inline uint64_t make_type(FMT_GEN15(FMT_ARG_TYPE_DEFAULT)) { ctor(arg0_type arg0, arg1_type arg1, const Args & ... args) { \ typename fmt::internal::ArgArray::Type array; \ const int count = fmt::internal::NamedArgsCounter::value; \ - fmt::BasicArgMap::value_type mapArray[count + 1]; \ + typename fmt::internal::BasicArgMap::value_type mapArray[count + 1]; \ fmt::internal::add_named_args<0>(mapArray, args...); \ - fmt::BasicArgMap map(mapArray, count); \ - func(arg0, arg1, fmt::internal::make_arg_list(array, fmt::internal::strip_name(args)...), map); \ + fmt::internal::BasicArgMap map(mapArray, count); \ + func(arg0, arg1, fmt::internal::make_arg_list(array, &map, fmt::internal::strip_name(args)...)); \ } #else -# define FMT_MAKE_REF(n) fmt::internal::MakeValue(v##n) -# define FMT_MAKE_REF2(n) v##n +# define FMT_MAKE_REF(n) fmt::internal::MakeValue(fmt::internal::strip_name(v##n)) +# define FMT_MAKE_REF2(n) fmt::internal::strip_name(v##n) +# define FMT_ADD_NAMED_ARG(n) fmt::internal::add_named_arg(mapPtr, v##n, 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)) { \ + typedef typename fmt::internal::BasicArgMap::value_type ArgMapValue; \ const fmt::internal::ArgArray::Type array = {FMT_GEN(n, FMT_MAKE_REF)}; \ + ArgMapValue mapArray[n]; \ + ArgMapValue* mapPtr = mapArray; \ + FMT_GEN(n, FMT_ADD_NAMED_ARG); \ + fmt::internal::BasicArgMap map(mapArray, unsigned(mapPtr - mapArray)); \ func(arg1, fmt::ArgList( \ - fmt::internal::make_type(FMT_GEN(n, FMT_MAKE_REF2)), array)); \ + fmt::internal::make_type(FMT_GEN(n, FMT_MAKE_REF2)), array, &map)); \ } // Emulates a variadic function returning void on a pre-C++11 compiler. @@ -1708,9 +1720,14 @@ inline uint64_t make_type(FMT_GEN15(FMT_ARG_TYPE_DEFAULT)) { # define FMT_CTOR(ctor, func, arg0_type, arg1_type, n) \ template \ ctor(arg0_type arg0, arg1_type arg1, FMT_GEN(n, FMT_MAKE_ARG)) { \ + typedef typename fmt::internal::BasicArgMap::value_type ArgMapValue; \ const fmt::internal::ArgArray::Type array = {FMT_GEN(n, FMT_MAKE_REF)}; \ + ArgMapValue mapArray[n]; \ + ArgMapValue* mapPtr = mapArray; \ + FMT_GEN(n, FMT_ADD_NAMED_ARG); \ + fmt::internal::BasicArgMap map(mapArray, unsigned(mapPtr - mapArray)); \ func(arg0, arg1, fmt::ArgList( \ - fmt::internal::make_type(FMT_GEN(n, FMT_MAKE_REF2)), array)); \ + fmt::internal::make_type(FMT_GEN(n, FMT_MAKE_REF2)), array, &map)); \ } // Emulates a variadic constructor on a pre-C++11 compiler. @@ -1755,7 +1772,7 @@ inline uint64_t make_type(FMT_GEN15(FMT_ARG_TYPE_DEFAULT)) { */ class SystemError : public internal::RuntimeError { private: - void init(int err_code, StringRef format_str, ArgList args, const ArgMap &map); + void init(int err_code, StringRef format_str, ArgList args); protected: int error_code_; @@ -1791,7 +1808,7 @@ class SystemError : public internal::RuntimeError { \endrst */ SystemError(int error_code, StringRef message) { - init(error_code, message, ArgList(), ArgMap()); + init(error_code, message, ArgList()); } FMT_VARIADIC_CTOR(SystemError, init, int, StringRef) @@ -1966,8 +1983,8 @@ class BasicWriter { See also :ref:`syntax`. \endrst */ - void write(BasicStringRef format, ArgList args, const BasicArgMap &map) { - BasicFormatter(*this).format(format, args, map); + void write(BasicStringRef format, ArgList args) { + BasicFormatter(*this).format(format, args); } FMT_VARIADIC_VOID(write, BasicStringRef) @@ -2515,7 +2532,7 @@ void format(BasicFormatter &f, const Char *&format_str, const T &value) { internal::Arg arg = internal::MakeValue(str); arg.type = static_cast( internal::MakeValue::type(str)); - format_str = f.format(format_str, arg, BasicArgMap()); + format_str = f.format(format_str, arg); } // Reports a system error without throwing an exception. @@ -2527,7 +2544,7 @@ void report_system_error(int error_code, StringRef message) FMT_NOEXCEPT; /** A Windows error. */ class WindowsError : public SystemError { private: - void init(int error_code, StringRef format_str, ArgList args, const ArgMap &map); + void init(int error_code, StringRef format_str, ArgList args); public: /** @@ -2559,7 +2576,7 @@ class WindowsError : public SystemError { \endrst */ WindowsError(int error_code, StringRef message) { - init(error_code, message, ArgList(), ArgMap()); + init(error_code, message, ArgList()); } FMT_VARIADIC_CTOR(WindowsError, init, int, StringRef) }; @@ -2578,7 +2595,7 @@ enum Color { BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE }; Example: PrintColored(fmt::RED, "Elapsed time: {0:.2f} seconds") << 1.23; */ -void print_colored(Color c, StringRef format, ArgList args, const ArgMap &map); +void print_colored(Color c, StringRef format, ArgList args); /** \rst @@ -2589,15 +2606,15 @@ void print_colored(Color c, StringRef format, ArgList args, const ArgMap &map); std::string message = format("The answer is {}", 42); \endrst */ -inline std::string format(StringRef format_str, ArgList args, const ArgMap &map) { +inline std::string format(StringRef format_str, ArgList args) { MemoryWriter w; - w.write(format_str, args, map); + w.write(format_str, args); return w.str(); } -inline std::wstring format(WStringRef format_str, ArgList args, const WArgMap &map) { +inline std::wstring format(WStringRef format_str, ArgList args) { WMemoryWriter w; - w.write(format_str, args, map); + w.write(format_str, args); return w.str(); } @@ -2610,7 +2627,7 @@ inline std::wstring format(WStringRef format_str, ArgList args, const WArgMap &m print(stderr, "Don't {}!", "panic"); \endrst */ -void print(std::FILE *f, StringRef format_str, ArgList args, const ArgMap &map); +void print(std::FILE *f, StringRef format_str, ArgList args); /** \rst @@ -2621,7 +2638,7 @@ void print(std::FILE *f, StringRef format_str, ArgList args, const ArgMap &map); print("Elapsed time: {0:.2f} seconds", 1.23); \endrst */ -void print(StringRef format_str, ArgList args, const ArgMap &map); +void print(StringRef format_str, ArgList args); /** \rst @@ -2632,10 +2649,10 @@ void print(StringRef format_str, ArgList args, const ArgMap &map); print(cerr, "Don't {}!", "panic"); \endrst */ -void print(std::ostream &os, StringRef format_str, ArgList args, const ArgMap &map); +void print(std::ostream &os, StringRef format_str, ArgList args); template -void printf(BasicWriter &w, BasicStringRef format, ArgList args, const ArgMap &) { +void printf(BasicWriter &w, BasicStringRef format, ArgList args) { internal::PrintfFormatter().format(w, format, args); } @@ -2648,9 +2665,9 @@ void printf(BasicWriter &w, BasicStringRef format, ArgList args, con std::string message = fmt::sprintf("The answer is %d", 42); \endrst */ -inline std::string sprintf(StringRef format, ArgList args, const ArgMap &map) { +inline std::string sprintf(StringRef format, ArgList args) { MemoryWriter w; - printf(w, format, args, map); + printf(w, format, args); return w.str(); } @@ -2663,7 +2680,7 @@ inline std::string sprintf(StringRef format, ArgList args, const ArgMap &map) { fmt::fprintf(stderr, "Don't %s!", "panic"); \endrst */ -int fprintf(std::FILE *f, StringRef format, ArgList args, const ArgMap &); +int fprintf(std::FILE *f, StringRef format, ArgList args); /** \rst @@ -2674,8 +2691,8 @@ int fprintf(std::FILE *f, StringRef format, ArgList args, const ArgMap &); fmt::printf("Elapsed time: %.2f seconds", 1.23); \endrst */ -inline int printf(StringRef format, ArgList args, const ArgMap &map) { - return fprintf(stdout, format, args, map); +inline int printf(StringRef format, ArgList args) { + return fprintf(stdout, format, args); } /** @@ -2782,13 +2799,24 @@ inline void format_decimal(char *&buffer, T value) { buffer += num_digits; } + +/** + \rst + Returns a named argument for formatting functions. + + **Example**:: + + print("Elapsed time: {s:.2f} seconds", arg("s", 1.23)); + + \endrst + */ template -inline internal::NamedArg arg(StringRef name, T const& arg) { +inline internal::NamedArg arg(StringRef name, const T &arg) { return internal::NamedArg(name, arg); } template -inline internal::NamedArg arg(WStringRef name, T const& arg) { +inline internal::NamedArg arg(WStringRef name, const T &arg) { return internal::NamedArg(name, arg); } } @@ -2827,22 +2855,28 @@ inline internal::NamedArg arg(WStringRef name, T const& arg) { const Args & ... args) { \ typename fmt::internal::ArgArray::Type array; \ const int count = fmt::internal::NamedArgsCounter::value; \ - fmt::BasicArgMap::value_type mapArray[count + 1]; \ + fmt::internal::BasicArgMap::value_type mapArray[count + 1]; \ fmt::internal::add_named_args<0>(mapArray, args...); \ - fmt::BasicArgMap map(mapArray, count); \ + fmt::internal::BasicArgMap map(mapArray, count); \ call(FMT_FOR_EACH(FMT_GET_ARG_NAME, __VA_ARGS__), \ - fmt::internal::make_arg_list(array, fmt::internal::strip_name(args)...), map); \ + fmt::internal::make_arg_list(array, &map, fmt::internal::strip_name(args)...)); \ } #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, ...) \ +# 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_MAKE_REF_##Char)}; \ + typedef Char_ Char; \ + typedef fmt::internal::BasicArgMap::value_type ArgMapValue; \ + fmt::internal::ArgArray::Type arr = {FMT_GEN(n, FMT_MAKE_REF)}; \ + ArgMapValue mapArray[n]; \ + ArgMapValue* mapPtr = mapArray; \ + FMT_GEN(n, FMT_ADD_NAMED_ARG); \ + fmt::internal::BasicArgMap map(mapArray, unsigned(mapPtr - mapArray)); \ call(FMT_FOR_EACH(FMT_GET_ARG_NAME, __VA_ARGS__), fmt::ArgList( \ - fmt::internal::make_type(FMT_GEN(n, FMT_MAKE_REF2)), arr)); \ + fmt::internal::make_type(FMT_GEN(n, FMT_MAKE_REF2)), arr, &map)); \ } # define FMT_VARIADIC_(Char, ReturnType, func, call, ...) \ @@ -2901,6 +2935,20 @@ inline internal::NamedArg arg(WStringRef name, T const& arg) { #define FMT_CAPTURE_ARG_(id, index) ::fmt::arg(#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__) namespace fmt { diff --git a/posix.h b/posix.h index 00928e11..70a0db1a 100644 --- a/posix.h +++ b/posix.h @@ -197,8 +197,8 @@ public: // of MinGW that define fileno as a macro. int (fileno)() const; - void print(fmt::StringRef format_str, const ArgList &args, const ArgMap &map) { - fmt::print(file_, format_str, args, map); + void print(fmt::StringRef format_str, const ArgList &args) { + fmt::print(file_, format_str, args); } FMT_VARIADIC(void, print, fmt::StringRef) }; diff --git a/test/format-test.cc b/test/format-test.cc index 0c641d3c..99472fb9 100644 --- a/test/format-test.cc +++ b/test/format-test.cc @@ -606,6 +606,7 @@ TEST(FormatterTest, ManyArgs) { EXPECT_THROW_MSG(TestFormat::format(format_str), FormatError, "argument index out of range"); } +#endif TEST(FormatterTest, NamedArg) { char a = 'A', b = 'B', c = 'C'; @@ -620,7 +621,6 @@ TEST(FormatterTest, NamedArg) { EXPECT_EQ(" -42", format("{0:{width}}", -42, fmt::arg("width", 4))); EXPECT_EQ("st", format("{0:.{precision}}", "str", fmt::arg("precision", 2))); } -#endif TEST(FormatterTest, AutoArgIndex) { EXPECT_EQ("abc", format("{}{}{}", 'a', 'b', 'c')); @@ -1564,10 +1564,10 @@ TEST(StrTest, Convert) { } std::string format_message(int id, const char *format, - const fmt::ArgList &args, const fmt::ArgMap &map) { + const fmt::ArgList &args) { MemoryWriter w; w.write("[{}] ", id); - w.write(format, args, map); + w.write(format, args); return w.str(); }