From 78677e3fcf09a954718509d1229c33cbe638350a Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sun, 13 May 2018 12:42:55 -0700 Subject: [PATCH 1/7] Update ChangeLog and docs --- ChangeLog.rst | 57 ++++++++++++++++++++++++++++++++++++++++++--------- doc/index.rst | 47 +++++++++++++++++++++++++++++++++--------- 2 files changed, 84 insertions(+), 20 deletions(-) diff --git a/ChangeLog.rst b/ChangeLog.rst index 5fa7b9c5..d3fd26da 100644 --- a/ChangeLog.rst +++ b/ChangeLog.rst @@ -1,18 +1,21 @@ 5.0.0 - TBD ----------- -* Added a requirement for compiler support for variadic templates and dropped - ``FMT_VARIADIC_*`` emulation macros. Variadic templates are available since - GCC 4.4, Clang 2.9 and MSVC 18.0 (2013). For older compilers use `version 4.x +* Added a requirement for partial C++11 support, most importantly variadic + templates and type traits, and dropped ``FMT_VARIADIC_*`` emulation macros. + Variadic templates are available since GCC 4.4, Clang 2.9 and MSVC 18.0 (2013). + For older compilers use {fmt} `version 4.x `_ which continues to be - maintained. + maintained and works with C++98 compilers. * Renamed symbols to follow standard C++ naming conventions and proposed a subset of the library for standardization in `P0645R2 Text Formatting `_. -* Swparated format string parsing and formatting in the extension API to enable - compile-time format-string processing. For example +* Implemented ``constexpr`` parsing of format strings. + +* Separated format string parsing and formatting in the extension API to enable + compile-time format string processing. For example .. code:: c++ @@ -26,8 +29,7 @@ spec = *it; if (spec != 'd' && spec != 's') throw format_error("invalid specifier"); - ++it; - return it; + return ++it; } template @@ -41,15 +43,27 @@ }; } - std::string s = fmt::format(fmt("{:x}"), S()); + std::string s = format(fmt("{:x}"), S()); will give a compile-time error due to invalid format specifier (`godbolt - `_):: + `_):: ... :12:45: error: expression '' is not a constant expression throw format_error("invalid specifier"); +* Improved compile times by reducing dependencies on standard headers and + providing a lightweight `core API `_: + + .. code:: c++ + + #include + + fmt::print("The answer is {}.", 42); + + See `Compile time and code bloat + `_. + * Added the `make_format_args `_ function for capturing formatting arguments: @@ -80,10 +94,19 @@ in the format API and provided ``fmt::string_view`` which implements a subset of ``std::string_view`` API for pre-C++17 systems. +* Allowed mixing named and automatic arguments: + + .. code:: c++ + + fmt::format("{} {two}", 1, fmt::arg("two", 2)); + * Removed the write API in favor of the `format API `_ with compile-time handling of format strings. +* Disallowed formatting of multibyte strings into a wide character target + (`#606 `_). + * Added a section on `formatting user-defined types `_ to the docs (`#393 `_). @@ -94,6 +117,12 @@ (`#515 `_). Thanks `@ibell (Ian Bell) `_. +* Added a `note about errno `_ to the + documentation ( + `#614 `_, + `#617 `_). + Thanks `@mihaitodor (Mihai Todor) `_. + * Implemented thread-safe time formatting ( `#395 `_, `#396 `_). @@ -163,6 +192,10 @@ * Fixed a name conflict with Xlib (`#483 `_). +* Fixed a name conflict with the macro ``CHAR_WIDTH`` in glibc + (`#616 `_). + Thanks `@aroig (Abdó Roig-Maranges) `_. + * Fixed signbit detection (`#423 `_). * Fixed missing intrinsic when included from C++/CLI @@ -181,6 +214,10 @@ (`#469 `_). Thanks `@richardeakin (Richard Eakin) `_. +* Added a missing ``inline`` in the header-only mode + (`#626 `_). + Thanks `@aroig (Abdó Roig-Maranges) `_. + 4.1.0 - 2017-12-20 ------------------ diff --git a/doc/index.rst b/doc/index.rst index fa5701a4..ac463062 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -33,13 +33,13 @@ in Python: fmt::format("The answer is {}", 42); The ``fmt::format`` function returns a string "The answer is 42". You can use -``fmt::MemoryWriter`` to avoid constructing ``std::string``: +``fmt::memory_buffer`` to avoid constructing ``std::string``: .. code:: c++ - fmt::MemoryWriter w; - w.write("Look, a {} string", 'C'); - w.c_str(); // returns a C string (const char*) + fmt::memory_buffer out; + format_to(out, "For a moment, {} happened.", "nothing"); + out.data(); // returns a pointer to the formatted data The ``fmt::print`` function performs formatting and writes the result to a file: @@ -54,11 +54,6 @@ The file argument can be omitted in which case the function prints to fmt::print("Don't {}\n", "panic"); -If your compiler supports C++11, then the formatting functions are implemented -with variadic templates. Otherwise variadic functions are emulated by generating -a set of lightweight wrappers. This ensures compatibility with older compilers -while providing a natural API. - The Format API also supports positional arguments useful for localization: .. code:: c++ @@ -106,7 +101,7 @@ the code fmt::format("The answer is {:d}", "forty-two"); -throws a ``FormatError`` exception with description +throws a ``format_error`` exception with description "unknown format code 'd' for string", because the argument ``"forty-two"`` is a string while the format code ``d`` only applies to integers. @@ -135,6 +130,38 @@ fmt does not attempt to preserve the value of ``errno``, users should not make any assumptions about it and always set it to ``0`` before making any system calls that convey error information via ``errno``. +Compact binary code +------------------- + +Each call to a formatting function results in a compact binary code. For example +(`godbolt `_), + +.. code:: c++ + + #include + + int main() { + fmt::print("The answer is {}.", 42); + } + +compiles to just + +.. code:: asm + + main: # @main + sub rsp, 24 + mov qword ptr [rsp], 42 + mov rcx, rsp + mov edi, offset .L.str + mov esi, 17 + mov edx, 2 + call fmt::v5::vprint(fmt::v5::basic_string_view, fmt::v5::format_args) + xor eax, eax + add rsp, 24 + ret + .L.str: + .asciz "The answer is {}." + .. _portability: Portability From 984232db152768555fee75795b7d7e87975b1d3a Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Sun, 13 May 2018 13:14:28 -0700 Subject: [PATCH 2/7] Remove duplicate ChangeLog entries --- ChangeLog.rst | 79 --------------------------------------------------- 1 file changed, 79 deletions(-) diff --git a/ChangeLog.rst b/ChangeLog.rst index d3fd26da..4e1356a3 100644 --- a/ChangeLog.rst +++ b/ChangeLog.rst @@ -107,11 +107,6 @@ * Disallowed formatting of multibyte strings into a wide character target (`#606 `_). -* Added a section on `formatting user-defined types - `_ to the docs - (`#393 `_). - Thanks `@pwm1234 (Phil) `_. - * Added a section describing `the use of header-only target with CMake `_ to the docs (`#515 `_). @@ -123,16 +118,8 @@ `#617 `_). Thanks `@mihaitodor (Mihai Todor) `_. -* Implemented thread-safe time formatting ( - `#395 `_, - `#396 `_). - Thanks `@codicodi `_. - * Implemented more efficient handling of large number of format arguments. -* Added a version macro ``FMT_VERSION`` - (`#411 `_). - * Removed unnecessary ``fmt/`` prefix in includes (`#397 `_). Thanks `@chronoxor (Ivan Shynkarenka) `_. @@ -140,80 +127,14 @@ * Renamed ``CHAR_WIDTH`` to ``CHAR_SIZE`` to avoid collision with ISO/IEC TS 18661-1:2014 macro. -* Replaced literal 0 with ``nullptr`` in pointer contexts - (`#409 `_). - Thanks `@alabuzhev (Alex Alabuzhev) `_. - -* Added ``std::basic_string`` allocator support to ``fmt::string_view`` - (`#441 `_). - Thanks `@glebov-andrey (Andrey Glebov) `_. - -* Stopped exporting the ``-std=c++11`` flag from the ``fmt`` target - (`#445 `_). - Thanks `@EricWF (Eric) `_. - -* Made ``%s`` a generic format specifier that works with any argument type in - ``fmt::printf`` (`#453 `_). - Thanks `@mojoBrendan `_: - - .. code:: c++ - - fmt::printf("%s", 42); - -* Placed CMake imported targets in the `fmt` namespace ( - `#511 `_, - `#513 `_). - Thanks `@bjoernthiel (Bjoern Thiel) `_ and - `@niosHD (Mario Werner) `_. - -* Fixed minimal supported library subset ( - `#418 `_, - `#419 `_, - `#420 `_). - Thanks `@alabuzhev (Alex Alabuzhev) `_. - -* Fixed compilation on Android - (`#381 `_). - Thanks `@hghwng (Hugh Wang) `_. - -* Fixed compilation with ``-fno-exceptions`` ( - `#402 `_, - `#405 `_). - Thanks `@JanHellwig (Jan Hellwig) `_. - -* Fixed compilation as a shared library with Clang - (`#413 `_). - Thanks `@foonathan (Jonathan Müller) `_. - -* Fixed test compilation on FreeBSD - (`#433 `_). - Thanks `@WscriChy `_. - -* Fixed a name conflict with Xlib - (`#483 `_). - * Fixed a name conflict with the macro ``CHAR_WIDTH`` in glibc (`#616 `_). Thanks `@aroig (Abdó Roig-Maranges) `_. -* Fixed signbit detection (`#423 `_). - -* Fixed missing intrinsic when included from C++/CLI - (`#457 `_). - Thanks `@calumr (Calum Robinson) `_. - -* Fixed Android not being detected with NDK 13b toolchain - (`#458 `_). - Thanks `@Gachapen (Magnus Bjerke Vik) `_. - * Added ``SOURCELINK_SUFFIX`` for compatibility with Sphinx 1.5 (`#497 `_). Thanks `@ginggs (Graham Inggs) `_. -* Added ``FMT_API`` declarations where needed for building a DLL - (`#469 `_). - Thanks `@richardeakin (Richard Eakin) `_. - * Added a missing ``inline`` in the header-only mode (`#626 `_). Thanks `@aroig (Abdó Roig-Maranges) `_. From e3f7f3a2e9544ec2db3d6997c78b77f498948ff8 Mon Sep 17 00:00:00 2001 From: Remotion Date: Thu, 10 May 2018 16:11:00 +0200 Subject: [PATCH 3/7] Add support for ranges, containers and tuple-like types in fmt/ranges.h --- include/fmt/ranges.h | 231 +++++++++++++++++++++++++++++++++++++++++++ test/CMakeLists.txt | 1 + test/ranges-test.cc | 88 +++++++++++++++++ 3 files changed, 320 insertions(+) create mode 100644 include/fmt/ranges.h create mode 100644 test/ranges-test.cc diff --git a/include/fmt/ranges.h b/include/fmt/ranges.h new file mode 100644 index 00000000..3e8480a1 --- /dev/null +++ b/include/fmt/ranges.h @@ -0,0 +1,231 @@ +// Formatting library for C++ - the core API +// +// Copyright (c) 2012 - present, Victor Zverovich +// All rights reserved. +// +// For the license information refer to format.h. +// +// Copyright (c) 2018 - present, Remotion (Igor Schulz) +// All Rights Reserved +// {fmt} support for ranges, containers and types tuple interface. + +#ifndef FMT_RANGES_H_ +#define FMT_RANGES_H_ + +#include "format.h" +#include + +// output only up to N items from the range. +#ifndef FMT_RANGE_OUTPUT_LENGTH_LIMIT +# define FMT_RANGE_OUTPUT_LENGTH_LIMIT 256 +#endif + +FMT_BEGIN_NAMESPACE + +template +struct formatting_base { + template + FMT_CONSTEXPR auto parse(ParseContext &ctx) -> decltype(ctx.begin()) { + return ctx.begin(); + } +}; + +template +struct formatting_range : formatting_base { + static FMT_CONSTEXPR_DECL const std::size_t range_length_limit = + FMT_RANGE_OUTPUT_LENGTH_LIMIT; // output only up to N items from the range. + Char prefix = '{'; + Char delimiter = ','; + Char postfix = '}'; + static FMT_CONSTEXPR_DECL const bool add_delimiter_spaces = true; + static FMT_CONSTEXPR_DECL const bool add_prepostfix_space = false; +}; + +template +struct formatting_tuple : formatting_base { + Char prefix = '('; + Char delimiter = ','; + Char postfix = ')'; + static FMT_CONSTEXPR_DECL const bool add_delimiter_spaces = true; + static FMT_CONSTEXPR_DECL const bool add_prepostfix_space = false; +}; + +namespace internal { + +template +void copy(const RangeT &range, OutputIterator out) { + for (const auto &it : range) { + *out++ = it; + } +} + +template +void copy(const char *str, OutputIterator out) { + const char *p_curr = str; + while (*p_curr) { + *out++ = *p_curr++; + } +} + +template +void copy(char ch, OutputIterator out) { + *out++ = ch; +} + +/// Return true value if T has std::string interface, like std::string_view. +template +class is_like_std_string { + template + static auto check(U *p) -> + decltype(p->find('a'), p->length(), p->data(), int()); + template + static void check(...); + + public: + static FMT_CONSTEXPR_DECL const bool value = + !std::is_void(nullptr))>::value; +}; + +template +struct conditional_helper {}; + +template +struct is_range_ : std::false_type {}; + +template +struct is_range_().begin()), + decltype(std::declval().end())>, + void>::type> : std::true_type {}; + +template +struct is_range { + static FMT_CONSTEXPR_DECL const bool value = + is_range_::value && !is_like_std_string::value; +}; + +/// tuple_size and tuple_element check. +template +class is_tuple_like_ { + template + static auto check(U *p) -> + decltype(std::tuple_size::value, + std::declval::type>(), int()); + template + static void check(...); + + public: + static FMT_CONSTEXPR_DECL const bool value = + !std::is_void(nullptr))>::value; +}; + +template +struct is_tuple_like { + static FMT_CONSTEXPR_DECL const bool value = + is_tuple_like_::value && !is_range_::value; +}; + +template +void for_each(std::index_sequence, Tuple &&tup, F &&f) noexcept { + using std::get; + // using free function get(T) now. + const int _[] = {0, ((void)f(get(tup)), 0)...}; + (void)_; // blocks warnings +} + +template +FMT_CONSTEXPR std::make_index_sequence::value> +get_indexes(T const &) { return {}; } + +template +void for_each(Tuple &&tup, F &&f) { + const auto indexes = get_indexes(tup); + for_each(indexes, std::forward(tup), std::forward(f)); +} +} // namespace internal + +template +struct formatter::value>::type> { + + fmt::formatting_tuple formatting; + + template + FMT_CONSTEXPR auto parse(ParseContext &ctx) -> decltype(ctx.begin()) { + return formatting.parse(ctx); + } + + template + auto format(const TupleT &values, FormatContext &ctx) -> decltype(ctx.out()) { + auto out = ctx.out(); + std::size_t i = 0; + internal::copy(formatting.prefix, out); + internal::for_each(values, [&](const auto &v) { + if (i > 0) { + if (formatting.add_prepostfix_space) { + *out++ = ' '; + } + internal::copy(formatting.delimiter, out); + } + if (formatting.add_delimiter_spaces && i > 0) { + format_to(out, " {}", v); + } else { + format_to(out, "{}", v); + } + ++i; + }); + if (formatting.add_prepostfix_space) { + *out++ = ' '; + } + internal::copy(formatting.postfix, out); + + return ctx.out(); + } +}; + +template +struct formatter< RangeT, Char, + typename std::enable_if::value>::type> { + + fmt::formatting_range formatting; + + template + FMT_CONSTEXPR auto parse(ParseContext &ctx) -> decltype(ctx.begin()) { + return formatting.parse(ctx); + } + + template + auto format(const RangeT &values, FormatContext &ctx) -> decltype(ctx.out()) { + auto out = ctx.out(); + internal::copy(formatting.prefix, out); + std::size_t i = 0; + for (const auto &it : values) { + if (i > 0) { + if (formatting.add_prepostfix_space) { + *out++ = ' '; + } + internal::copy(formatting.delimiter, out); + } + if (formatting.add_delimiter_spaces && i > 0) { + format_to(out, " {}", it); + } else { + format_to(out, "{}", it); + } + if (++i > formatting.range_length_limit) { + format_to(out, " ... "); + break; + } + } + if (formatting.add_prepostfix_space) { + *out++ = ' '; + } + internal::copy(formatting.postfix, out); + return ctx.out(); + } +}; + +FMT_END_NAMESPACE + +#endif // FMT_RANGES_H_ + diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index b0c479cb..07b10a0a 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -92,6 +92,7 @@ add_fmt_test(printf-test) add_fmt_test(time-test) add_fmt_test(util-test mock-allocator.h) add_fmt_test(custom-formatter-test) +add_fmt_test(ranges-test) # Enable stricter options for one test to make sure that the header is free of # warnings. diff --git a/test/ranges-test.cc b/test/ranges-test.cc new file mode 100644 index 00000000..76c37a11 --- /dev/null +++ b/test/ranges-test.cc @@ -0,0 +1,88 @@ +// Formatting library for C++ - the core API +// +// Copyright (c) 2012 - present, Victor Zverovich +// All rights reserved. +// +// For the license information refer to format.h. +// +// Copyright (c) 2018 - present, Remotion (Igor Schulz) +// All Rights Reserved +// {fmt} support for ranges, containers and types tuple interface. + +#include "fmt/ranges.h" + +#include "gtest/gtest.h" + +#include +#include +#include +#include + +TEST(RangesTest, FormatVector) { + std::vector iv{1, 2, 3, 5, 7, 11}; + auto ivf = fmt::format("{}", iv); + EXPECT_EQ("{1, 2, 3, 5, 7, 11}", ivf); +} + +TEST(RangesTest, FormatVector2) { + std::vector> ivv{{1, 2}, {3, 5}, {7, 11}}; + auto ivf = fmt::format("{}", ivv); + EXPECT_EQ("{{1, 2}, {3, 5}, {7, 11}}", ivf); +} + +TEST(RangesTest, FormatMap) { + std::map simap{{"one", 1}, {"two", 2}}; + EXPECT_EQ("{(one, 1), (two, 2)}", fmt::format("{}", simap)); +} + +TEST(RangesTest, FormatPair) { + std::pair pa1{42, 3.14159265358979f}; + EXPECT_EQ("(42, 3.14159)", fmt::format("{}", pa1)); +} + +TEST(RangesTest, FormatTuple) { + std::tuple tu1{42, 3.14159265358979f, + "this is tuple"}; + EXPECT_EQ("(42, 3.14159, this is tuple)", fmt::format("{}", tu1)); +} + +/// check if 'if constexpr' is supported. +#if (__cplusplus > 201402L) || \ + (defined(_MSVC_LANG) && _MSVC_LANG > 201402L && _MSC_VER >= 1910) + +struct my_struct { + int32_t i; + std::string str; // can throw + template + decltype(auto) get() const noexcept { + if constexpr (N == 0) + return i; + else if constexpr (N == 1) + return fmt::string_view{str}; + } +}; + +template +decltype(auto) get(const my_struct& s) noexcept { + return s.get(); +} + +namespace std { + +template <> +struct tuple_size : std::integral_constant {}; + +template +struct tuple_element { + using type = decltype(std::declval().get()); +}; + +} // namespace std + +TEST(RangesTest, FormatStruct) { + my_struct mst{13, "my struct"}; + EXPECT_EQ("(13, my struct)", fmt::format("{}", mst)); +} + +#endif // (__cplusplus > 201402L) || (defined(_MSVC_LANG) && _MSVC_LANG > + // 201402L && _MSC_VER >= 1910) From a68fd44eccba060df65dfa344a43af648106d704 Mon Sep 17 00:00:00 2001 From: sv1990 Date: Mon, 14 May 2018 14:16:30 +0200 Subject: [PATCH 4/7] Add ranges.h to FMT_HEADERS in CMakeLists.txt (#738) --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 045004a2..639dc7fc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -96,7 +96,7 @@ endfunction() # Define the fmt library, its includes and the needed defines. add_headers(FMT_HEADERS core.h format.h format-inl.h locale.h ostream.h printf.h - time.h) + time.h ranges.h) set(FMT_SOURCES src/format.cc) if (HAVE_OPEN) add_headers(FMT_HEADERS posix.h) From 8c2557710d531fc04b17239ba1994661a7dd9092 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Wed, 16 May 2018 07:58:43 -0700 Subject: [PATCH 5/7] Update docs and changelog --- ChangeLog.rst | 24 ++++++++++++++++++++++++ doc/api.rst | 2 ++ include/fmt/format.h | 11 +++++++++++ 3 files changed, 37 insertions(+) diff --git a/ChangeLog.rst b/ChangeLog.rst index 4e1356a3..982c1117 100644 --- a/ChangeLog.rst +++ b/ChangeLog.rst @@ -52,6 +52,17 @@ :12:45: error: expression '' is not a constant expression throw format_error("invalid specifier"); +* Added `iterator support + `_: + + .. code:: c++ + + #include + #include + + std::vector out; + fmt::format_to(std::back_inserter(out), "{}", 42); + * Improved compile times by reducing dependencies on standard headers and providing a lightweight `core API `_: @@ -94,6 +105,19 @@ in the format API and provided ``fmt::string_view`` which implements a subset of ``std::string_view`` API for pre-C++17 systems. +* Added support for ``std::experimental::string_view`` + (`#607 `_): + + .. code:: c++ + + #include + #include + + fmt::print("{}", std::experimental::string_view("foo")); + + Thanks `@virgiliofornazin (Virgilio Alexandre Fornazin) + `_. + * Allowed mixing named and automatic arguments: .. code:: c++ diff --git a/doc/api.rst b/doc/api.rst index b65a8fc6..2a380a16 100644 --- a/doc/api.rst +++ b/doc/api.rst @@ -151,6 +151,8 @@ The following user-defined literals are defined in ``fmt/format.h``. Utilities --------- +.. dosygenfunction:: fmt::formatted_size(string_view, const Args&...) + .. doxygenfunction:: fmt::to_string(const T&) .. doxygenfunction:: fmt::to_wstring(const T&) diff --git a/include/fmt/format.h b/include/fmt/format.h index 07c644aa..6e273e84 100644 --- a/include/fmt/format.h +++ b/include/fmt/format.h @@ -3450,6 +3450,17 @@ inline OutputIt vformat_to(OutputIt out, string_view format_str, return vformat_to>(range(out), format_str, args); } +/** + \rst + Formats arguments, writes the result to the output iterator ``out`` and returns + the iterator past the end of the output range. + + **Example**:: + + std::vector out; + fmt::format_to(std::back_inserter(out), "{}", 42); + \endrst + */ template inline OutputIt format_to(OutputIt out, string_view format_str, const Args & ... args) { From 728e4f5a8dea29b6b68c1a7519141e3e7128be25 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Wed, 16 May 2018 08:19:26 -0700 Subject: [PATCH 6/7] Fix docs --- ChangeLog.rst | 10 ++++++++++ doc/api.rst | 2 +- include/fmt/core.h | 22 +++------------------- include/fmt/format.h | 13 +++++++------ 4 files changed, 21 insertions(+), 26 deletions(-) diff --git a/ChangeLog.rst b/ChangeLog.rst index 982c1117..8cd24414 100644 --- a/ChangeLog.rst +++ b/ChangeLog.rst @@ -63,6 +63,16 @@ std::vector out; fmt::format_to(std::back_inserter(out), "{}", 42); +* Added the `formatted_size + `_ function for + computing output size: + + .. code:: c++ + + #include + + auto size = fmt::formatted_size("{}", 12345); // size == 5 + * Improved compile times by reducing dependencies on standard headers and providing a lightweight `core API `_: diff --git a/doc/api.rst b/doc/api.rst index 2a380a16..0eeab744 100644 --- a/doc/api.rst +++ b/doc/api.rst @@ -151,7 +151,7 @@ The following user-defined literals are defined in ``fmt/format.h``. Utilities --------- -.. dosygenfunction:: fmt::formatted_size(string_view, const Args&...) +.. doxygenfunction:: fmt::formatted_size(string_view, const Args&...) .. doxygenfunction:: fmt::to_string(const T&) diff --git a/include/fmt/core.h b/include/fmt/core.h index 66597eed..7a654e2b 100644 --- a/include/fmt/core.h +++ b/include/fmt/core.h @@ -193,13 +193,11 @@ typename std::add_rvalue_reference::type declval() FMT_NOEXCEPT; } /** - \rst An implementation of ``std::basic_string_view`` for pre-C++17. It provides a subset of the API. ``fmt::basic_string_view`` is used for format strings even if ``std::string_view`` is available to prevent issues when a library is compiled with a different ``-std`` option than the client code (which is not recommended). - \endrst */ template class basic_string_view { @@ -238,11 +236,7 @@ class basic_string_view { basic_string_view(const Char *s) : data_(s), size_(std::char_traits::length(s)) {} - /** - \rst - Constructs a string reference from a ``std::basic_string`` object. - \endrst - */ + /** Constructs a string reference from a ``std::basic_string`` object. */ template FMT_CONSTEXPR basic_string_view( const std::basic_string &s) FMT_NOEXCEPT @@ -329,11 +323,7 @@ class basic_buffer { capacity_ = capacity; } - /** - \rst - Increases the buffer capacity to hold at least *capacity* elements. - \endrst - */ + /** Increases the buffer capacity to hold at least *capacity* elements. */ virtual void grow(std::size_t capacity) = 0; public: @@ -365,11 +355,7 @@ class basic_buffer { size_ = new_size; } - /** - \rst - Reserves space to store at least *capacity* elements. - \endrst - */ + /** Reserves space to store at least *capacity* elements. */ void reserve(std::size_t capacity) { if (capacity > capacity_) grow(capacity); @@ -899,10 +885,8 @@ class basic_format_context : using typename base::iterator; /** - \rst Constructs a ``basic_format_context`` object. References to the arguments are stored in the object so make sure they have appropriate lifetimes. - \endrst */ basic_format_context(OutputIt out, basic_string_view format_str, basic_format_args args) diff --git a/include/fmt/format.h b/include/fmt/format.h index 6e273e84..e9c16b1f 100644 --- a/include/fmt/format.h +++ b/include/fmt/format.h @@ -3391,9 +3391,7 @@ std::string to_string(const T &value) { } /** - \rst Converts *value* to ``std::wstring`` using the default format for type *T*. - \endrst */ template std::wstring to_wstring(const T &value) { @@ -3455,10 +3453,10 @@ inline OutputIt vformat_to(OutputIt out, string_view format_str, Formats arguments, writes the result to the output iterator ``out`` and returns the iterator past the end of the output range. - **Example**:: + **Example**:: - std::vector out; - fmt::format_to(std::back_inserter(out), "{}", 42); + std::vector out; + fmt::format_to(std::back_inserter(out), "{}", 42); \endrst */ template @@ -3535,7 +3533,10 @@ inline typename std::enable_if::value>::type return vprint(format_str.data(), make_format_args(args...)); } -// Counts the number of characters in the output of format(format_str, args...). +/** + Returns the number of characters in the output of + ``format(format_str, args...)``. + */ template inline std::size_t formatted_size(string_view format_str, const Args & ... args) { From 550ef1d29d68c761194c884e33f3db8fe2faf21c Mon Sep 17 00:00:00 2001 From: Michael Winterberg Date: Thu, 17 May 2018 18:03:43 -0700 Subject: [PATCH 7/7] MSVC improvements and data truncation cleanup. MSVC is timid about evaluating constexpr functions unless it has to, so the "TYPES" variables end up in read-write memory even though the optimizer removes the initializer. Making TYPES constexpr causes MSVC to try harder to initialize these variables at compile time, which also ends up completely removing the (named) variable from the final compiled binary. Fixed a data truncation warning being reported in ostream-test. --- include/fmt/core.h | 18 ++++++++++++++---- include/fmt/format.h | 12 +++++++----- 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/include/fmt/core.h b/include/fmt/core.h index 7a654e2b..2625d86b 100644 --- a/include/fmt/core.h +++ b/include/fmt/core.h @@ -73,7 +73,8 @@ # endif #endif -#if FMT_HAS_FEATURE(cxx_explicit_conversions) +#if FMT_HAS_FEATURE(cxx_explicit_conversions) || \ + FMT_MSC_VER >= 1800 # define FMT_EXPLICIT explicit #else # define FMT_EXPLICIT @@ -970,8 +971,17 @@ class format_arg_store { friend class basic_format_args; + static FMT_CONSTEXPR uint64_t get_types() { + return IS_PACKED ? internal::get_types() + : -static_cast(NUM_ARGS); + } + public: +#if FMT_USE_CONSTEXPR + static constexpr uint64_t TYPES = get_types(); +#else static const uint64_t TYPES; +#endif #if FMT_GCC_VERSION && FMT_GCC_VERSION <= 405 // Workaround an array initialization bug in gcc 4.5 and earlier. @@ -984,10 +994,10 @@ class format_arg_store { #endif }; +#if !FMT_USE_CONSTEXPR template -const uint64_t format_arg_store::TYPES = IS_PACKED ? - internal::get_types() : - -static_cast(NUM_ARGS); +const uint64_t format_arg_store::TYPES = get_types(); +#endif /** \rst diff --git a/include/fmt/format.h b/include/fmt/format.h index e9c16b1f..3d35a18c 100644 --- a/include/fmt/format.h +++ b/include/fmt/format.h @@ -1381,13 +1381,13 @@ class float_type_checker : private ErrorHandler { } }; -template +template class char_specs_checker : public ErrorHandler { private: - char type_; + CharType type_; public: - FMT_CONSTEXPR char_specs_checker(char type, ErrorHandler eh) + FMT_CONSTEXPR char_specs_checker(CharType type, ErrorHandler eh) : ErrorHandler(eh), type_(type) {} FMT_CONSTEXPR void on_int() { @@ -3110,8 +3110,10 @@ struct formatter< type_spec, internal::int_type_checker(eh)); break; case internal::char_type: - handle_char_specs(specs_, internal::char_specs_checker( - type_spec, eh)); + handle_char_specs( + specs_, + internal::char_specs_checker( + type_spec, eh)); break; case internal::double_type: case internal::long_double_type: