diff --git a/ChangeLog.rst b/ChangeLog.rst index 81ee76b1..d4fb516b 100644 --- a/ChangeLog.rst +++ b/ChangeLog.rst @@ -1,3 +1,69 @@ +7.0.0 - TBD + +* Reduced the library size. For example, on macOS the stripped binary + statically linked with {fmt} shrinked from ~368k to less than 100k: + http://www.zverovich.net/2020/05/21/reducing-library-size.html + +* Named arguments are now stored on stack (no dynamic memory allocations) and + the generated binary code is more compact and efficient. For example + + .. code:: c++ + + #include + + int main() { + fmt::print("The answer is {answer}\n", fmt::arg("answer", 42)); + } + + compiles to just (`godbolt `__) + + .. code:: asm + + .LC0: + .string "answer" + .LC1: + .string "The answer is {answer}\n" + main: + sub rsp, 56 + mov edi, OFFSET FLAT:.LC1 + mov esi, 23 + movabs rdx, 4611686018427387905 + lea rax, [rsp+32] + lea rcx, [rsp+16] + mov QWORD PTR [rsp+8], 1 + mov QWORD PTR [rsp], rax + mov DWORD PTR [rsp+16], 42 + mov QWORD PTR [rsp+32], OFFSET FLAT:.LC0 + mov DWORD PTR [rsp+40], 0 + call fmt::v6::vprint(fmt::v6::basic_string_view, fmt::v6::format_args) + xor eax, eax + add rsp, 56 + ret + + .L.str.1: + .asciz "answer" + +* Implemented the ``'L'`` specifier for locale-specific formatting of + floating-point numbers to improve compatibility with ``std::format`` + (`#1624 `_). + +* Improved documentation + (`#1643 `_). + Thanks `@senior7515 (Alexander Gallego) `_, + +* Fixed various warnings and compilation issues + (`#1616 `_, + `#1622 `_, + `#1627 `_, + `#1628 `_, + `#1629 `_ + `#1631 `_, + `#1633 `_). + Thanks `@gsjaardema (Greg Sjaardema) `_, + `@gabime (Gabi Melman) `_, + `@johnor (Johan) `_, + `@gabime (Dmitry Kurkin) `_. + 6.2.1 - 2020-05-09 ------------------ diff --git a/include/fmt/core.h b/include/fmt/core.h index 08a96330..c780811f 100644 --- a/include/fmt/core.h +++ b/include/fmt/core.h @@ -332,7 +332,9 @@ enum char8_type : unsigned char {}; #endif } // namespace detail +#ifdef FMT_USE_INTERNAL namespace internal = detail; // DEPRECATED +#endif /** An implementation of ``std::basic_string_view`` for pre-C++17. It provides a @@ -1592,7 +1594,7 @@ class dynamic_format_arg_store void clear() { data_.clear(); named_info_.clear(); - dynamic_args_ = internal::dynamic_arg_list(); + dynamic_args_ = detail::dynamic_arg_list(); } /** diff --git a/include/fmt/format-inl.h b/include/fmt/format-inl.h index 44a1f661..95afbebf 100644 --- a/include/fmt/format-inl.h +++ b/include/fmt/format-inl.h @@ -1373,7 +1373,7 @@ struct stringifier { } std::string operator()(basic_format_arg::handle h) const { memory_buffer buf; - internal::buffer& base = buf; + detail::buffer& base = buf; format_parse_context parse_ctx({}); format_context format_ctx(std::back_inserter(base), {}, {}); h.format(parse_ctx, format_ctx); diff --git a/test/custom-formatter-test.cc b/test/custom-formatter-test.cc index 68d32906..c5d748e8 100644 --- a/test/custom-formatter-test.cc +++ b/test/custom-formatter-test.cc @@ -39,7 +39,7 @@ class custom_arg_formatter std::string custom_vformat(fmt::string_view format_str, fmt::format_args args) { fmt::memory_buffer buffer; - fmt::internal::buffer& base = buffer; + fmt::detail::buffer& base = buffer; // Pass custom argument formatter as a template arg to vwrite. fmt::vformat_to(std::back_inserter(base), format_str, args); diff --git a/test/format b/test/format index 2701ed06..11c58b96 100644 --- a/test/format +++ b/test/format @@ -38,9 +38,9 @@ namespace std { template class basic_format_context; using format_context = basic_format_context< - /* unspecified */ std::back_insert_iterator>, char>; + /* unspecified */ std::back_insert_iterator>, char>; using wformat_context = basic_format_context< - /* unspecified */ std::back_insert_iterator>, wchar_t>; + /* unspecified */ std::back_insert_iterator>, wchar_t>; template struct formatter { formatter() = delete; @@ -219,7 +219,7 @@ namespace std { // Implementation details: using format_arg = basic_format_arg; - basic_format_context(Out out, basic_format_args args, fmt::internal::locale_ref) + basic_format_context(Out out, basic_format_args args, fmt::detail::locale_ref) : args_(args), out_(out) {} detail::error_handler error_handler() const { return {}; } basic_format_arg arg(fmt::basic_string_view) const { @@ -490,10 +490,10 @@ namespace detail { template class arg_formatter - : public fmt::internal::arg_formatter_base { + : public fmt::detail::arg_formatter_base { private: using char_type = Char; - using base = fmt::internal::arg_formatter_base; + using base = fmt::detail::arg_formatter_base; using format_context = std::basic_format_context; using parse_context = basic_format_parse_context; @@ -528,36 +528,36 @@ class arg_formatter }; template -inline fmt::internal::type get_type(basic_format_arg arg) { +inline fmt::detail::type get_type(basic_format_arg arg) { return visit_format_arg([&] (auto val) { using char_type = typename Context::char_type; using T = decltype(val); if (std::is_same_v) - return fmt::internal::type::none_type; + return fmt::detail::type::none_type; if (std::is_same_v) - return fmt::internal::type::bool_type; + return fmt::detail::type::bool_type; if (std::is_same_v) - return fmt::internal::type::char_type; + return fmt::detail::type::char_type; if (std::is_same_v) - return fmt::internal::type::int_type; + return fmt::detail::type::int_type; if (std::is_same_v) - return fmt::internal::type::uint_type; + return fmt::detail::type::uint_type; if (std::is_same_v) - return fmt::internal::type::long_long_type; + return fmt::detail::type::long_long_type; if (std::is_same_v) - return fmt::internal::type::ulong_long_type; + return fmt::detail::type::ulong_long_type; if (std::is_same_v) - return fmt::internal::type::double_type; + return fmt::detail::type::double_type; if (std::is_same_v) - return fmt::internal::type::long_double_type; + return fmt::detail::type::long_double_type; if (std::is_same_v) - return fmt::internal::type::cstring_type; + return fmt::detail::type::cstring_type; if (std::is_same_v>) - return fmt::internal::type::string_type; + return fmt::detail::type::string_type; if (std::is_same_v) - return fmt::internal::type::pointer_type; + return fmt::detail::type::pointer_type; assert(get_value(arg).index() == 12); - return fmt::internal::type::custom_type; + return fmt::detail::type::custom_type; }, arg); } @@ -585,13 +585,13 @@ struct format_handler : detail::error_handler { format_handler(iterator out, basic_string_view str, basic_format_args format_args, - fmt::internal::locale_ref loc) + fmt::detail::locale_ref loc) : parse_ctx(str), context(out, format_args, loc) {} void on_text(const Char* begin, const Char* end) { - auto size = fmt::internal::to_unsigned(end - begin); + auto size = fmt::detail::to_unsigned(end - begin); auto out = context.out(); - auto&& it = fmt::internal::reserve(out, size); + auto&& it = fmt::detail::reserve(out, size); it = std::copy_n(begin, size, it); context.advance_to(out); } @@ -614,9 +614,9 @@ struct format_handler : detail::error_handler { custom_formatter f(parse_ctx, context); if (visit_format_arg(f, arg)) return &*parse_ctx.begin(); fmt::basic_format_specs specs; - using fmt::internal::specs_handler; + using fmt::detail::specs_handler; using parse_context = basic_format_parse_context; - fmt::internal::specs_checker> handler( + fmt::detail::specs_checker> handler( specs_handler(specs, parse_ctx, context), get_type(arg)); begin = parse_format_specs(begin, end, handler); if (begin == end || *begin != '}') on_error("missing '}' in format string"); @@ -635,45 +635,45 @@ struct formatter { // terminating '}'. template FMT_CONSTEXPR typename ParseContext::iterator parse(ParseContext& ctx) { - namespace internal = fmt::internal; - typedef internal::dynamic_specs_handler handler_type; - auto type = internal::mapped_type_constant>::value; - internal::specs_checker handler(handler_type(specs_, ctx), + namespace detail = fmt::detail; + typedef detail::dynamic_specs_handler handler_type; + auto type = detail::mapped_type_constant>::value; + detail::specs_checker handler(handler_type(specs_, ctx), type); auto it = parse_format_specs(ctx.begin(), ctx.end(), handler); auto type_spec = specs_.type; auto eh = ctx.error_handler(); switch (type) { - case internal::type::none_type: + case detail::type::none_type: FMT_ASSERT(false, "invalid argument type"); break; - case internal::type::int_type: - case internal::type::uint_type: - case internal::type::long_long_type: - case internal::type::ulong_long_type: - case internal::type::bool_type: + case detail::type::int_type: + case detail::type::uint_type: + case detail::type::long_long_type: + case detail::type::ulong_long_type: + case detail::type::bool_type: handle_int_type_spec(type_spec, - internal::int_type_checker(eh)); + detail::int_type_checker(eh)); break; - case internal::type::char_type: + case detail::type::char_type: handle_char_specs( - &specs_, internal::char_specs_checker(type_spec, eh)); + &specs_, detail::char_specs_checker(type_spec, eh)); break; - case internal::type::double_type: - case internal::type::long_double_type: - internal::parse_float_type_spec(specs_, eh); + case detail::type::double_type: + case detail::type::long_double_type: + detail::parse_float_type_spec(specs_, eh); break; - case internal::type::cstring_type: - internal::handle_cstring_type_spec( - type_spec, internal::cstring_type_checker(eh)); + case detail::type::cstring_type: + detail::handle_cstring_type_spec( + type_spec, detail::cstring_type_checker(eh)); break; - case internal::type::string_type: - internal::check_string_type_spec(type_spec, eh); + case detail::type::string_type: + detail::check_string_type_spec(type_spec, eh); break; - case internal::type::pointer_type: - internal::check_pointer_type_spec(type_spec, eh); + case detail::type::pointer_type: + detail::check_pointer_type_spec(type_spec, eh); break; - case internal::type::custom_type: + case detail::type::custom_type: // Custom format specifiers should be checked in parse functions of // formatter specializations. break; @@ -683,9 +683,9 @@ struct formatter { template auto format(const T& val, FormatContext& ctx) -> decltype(ctx.out()) { - fmt::internal::handle_dynamic_spec( + fmt::detail::handle_dynamic_spec( specs_.width, specs_.width_ref, ctx); - fmt::internal::handle_dynamic_spec( + fmt::detail::handle_dynamic_spec( specs_.precision, specs_.precision_ref, ctx); using af = arg_formatter; @@ -694,7 +694,7 @@ struct formatter { } private: - fmt::internal::dynamic_format_specs specs_; + fmt::detail::dynamic_format_specs specs_; }; } // namespace detail @@ -711,11 +711,11 @@ template string vformat(string_view fmt, format_args args) { fmt::memory_buffer mbuf; - fmt::internal::buffer& buf = mbuf; + fmt::detail::buffer& buf = mbuf; using af = detail::arg_formatter; detail::format_handler h(std::back_inserter(buf), fmt, args, {}); - fmt::internal::parse_format_string(fmt::to_string_view(fmt), h); + fmt::detail::parse_format_string(fmt::to_string_view(fmt), h); return to_string(mbuf); } @@ -738,7 +738,7 @@ template using af = detail::arg_formatter; detail::format_handler> h(out, fmt, args, {}); - fmt::internal::parse_format_string(fmt::to_string_view(fmt), h); + fmt::detail::parse_format_string(fmt::to_string_view(fmt), h); return h.context.out(); } diff --git a/test/format-test.cc b/test/format-test.cc index 8108992d..87e5b8cc 100644 --- a/test/format-test.cc +++ b/test/format-test.cc @@ -1846,7 +1846,7 @@ class mock_arg_formatter static void custom_vformat(fmt::string_view format_str, fmt::format_args args) { fmt::memory_buffer buffer; - fmt::internal::buffer& base = buffer; + fmt::detail::buffer& base = buffer; fmt::vformat_to(std::back_inserter(base), format_str, args); }