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) diff --git a/ChangeLog.rst b/ChangeLog.rst index 5fa7b9c5..8cd24414 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,48 @@ }; } - 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"); +* Added `iterator support + `_: + + .. code:: c++ + + #include + #include + + 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 `_: + + .. 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,30 +115,45 @@ 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++ + + 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. -* Added a section on `formatting user-defined types - `_ to the docs - (`#393 `_). - Thanks `@pwm1234 (Phil) `_. +* Disallowed formatting of multibyte strings into a wide character target + (`#606 `_). * Added a section describing `the use of header-only target with CMake `_ to the docs (`#515 `_). Thanks `@ibell (Ian Bell) `_. -* Implemented thread-safe time formatting ( - `#395 `_, - `#396 `_). - Thanks `@codicodi `_. +* Added a `note about errno `_ to the + documentation ( + `#614 `_, + `#617 `_). + Thanks `@mihaitodor (Mihai Todor) `_. * 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) `_. @@ -111,75 +161,17 @@ * 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 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) `_. +* Fixed a name conflict with the macro ``CHAR_WIDTH`` in glibc + (`#616 `_). + Thanks `@aroig (Abdó Roig-Maranges) `_. * 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) `_. 4.1.0 - 2017-12-20 ------------------ diff --git a/doc/api.rst b/doc/api.rst index b65a8fc6..0eeab744 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 --------- +.. doxygenfunction:: fmt::formatted_size(string_view, const Args&...) + .. doxygenfunction:: fmt::to_string(const T&) .. doxygenfunction:: fmt::to_wstring(const T&) 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 diff --git a/include/fmt/core.h b/include/fmt/core.h index 66597eed..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 @@ -193,13 +194,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 +237,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 +324,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 +356,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 +886,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) @@ -986,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. @@ -1000,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 07c644aa..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: @@ -3391,9 +3393,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) { @@ -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) { @@ -3524,7 +3535,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) { diff --git a/include/fmt/ranges.h b/include/fmt/ranges.h index ae14907e..3e8480a1 100644 --- a/include/fmt/ranges.h +++ b/include/fmt/ranges.h @@ -17,7 +17,7 @@ // output only up to N items from the range. #ifndef FMT_RANGE_OUTPUT_LENGTH_LIMIT -#define FMT_RANGE_OUTPUT_LENGTH_LIMIT 256 +# define FMT_RANGE_OUTPUT_LENGTH_LIMIT 256 #endif FMT_BEGIN_NAMESPACE @@ -72,23 +72,20 @@ void copy(char ch, OutputIterator out) { *out++ = ch; } -} // namespace internal - -namespace internal { - /// 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()); + 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; + static FMT_CONSTEXPR_DECL const bool value = + !std::is_void(nullptr))>::value; }; - template struct conditional_helper {}; @@ -104,30 +101,31 @@ struct is_range_ struct is_range { - static FMT_CONSTEXPR_DECL const bool value = is_range_::value && !is_like_std_string::value; + 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()); + 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; + 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; + 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; @@ -135,21 +133,18 @@ void for_each(std::index_sequence, Tuple &&tup, F &&f) noexcept { 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> { @@ -193,7 +188,6 @@ template struct formatter< RangeT, Char, typename std::enable_if::value>::type> { - fmt::formatting_range formatting; template @@ -233,4 +227,5 @@ struct formatter< RangeT, Char, FMT_END_NAMESPACE -#endif // FMT_RANGES_H_ \ No newline at end of file +#endif // FMT_RANGES_H_ + diff --git a/test/ranges-test.cc b/test/ranges-test.cc index b7519747..76c37a11 100644 --- a/test/ranges-test.cc +++ b/test/ranges-test.cc @@ -85,4 +85,4 @@ TEST(RangesTest, FormatStruct) { } #endif // (__cplusplus > 201402L) || (defined(_MSVC_LANG) && _MSVC_LANG > - // 201402L && _MSC_VER >= 1910) \ No newline at end of file + // 201402L && _MSC_VER >= 1910)