summaryrefslogtreecommitdiff
path: root/deps
diff options
context:
space:
mode:
Diffstat (limited to 'deps')
-rw-r--r--deps/fmt/CMakeLists.txt39
-rw-r--r--deps/fmt/ChangeLog.rst700
-rw-r--r--deps/fmt/README.rst10
-rw-r--r--deps/fmt/include/fmt/chrono.h271
-rw-r--r--deps/fmt/include/fmt/color.h8
-rw-r--r--deps/fmt/include/fmt/compile.h45
-rw-r--r--deps/fmt/include/fmt/core.h1490
-rw-r--r--deps/fmt/include/fmt/format-inl.h78
-rw-r--r--deps/fmt/include/fmt/format.h2013
-rw-r--r--deps/fmt/include/fmt/locale.h69
-rw-r--r--deps/fmt/include/fmt/os.h39
-rw-r--r--deps/fmt/include/fmt/printf.h389
-rw-r--r--deps/fmt/include/fmt/ranges.h81
-rw-r--r--deps/fmt/include/fmt/xchar.h236
-rw-r--r--deps/fmt/src/fmt.cc20
-rw-r--r--deps/fmt/src/format.cc39
-rw-r--r--deps/fmt/src/os.cc10
17 files changed, 3104 insertions, 2433 deletions
diff --git a/deps/fmt/CMakeLists.txt b/deps/fmt/CMakeLists.txt
index 464dfde771..447d8e8a34 100644
--- a/deps/fmt/CMakeLists.txt
+++ b/deps/fmt/CMakeLists.txt
@@ -28,27 +28,34 @@ else()
check_symbol_exists(strtod_l "${strtod_l_headers}" HAVE_STRTOD_L)
endif()
-set(FMT_HEADERS
- include/fmt/args.h
- include/fmt/chrono.h
- include/fmt/color.h
- include/fmt/compile.h
- include/fmt/core.h
- include/fmt/format.h
- include/fmt/format-inl.h
- include/fmt/locale.h
- include/fmt/os.h
- include/fmt/ostream.h
- include/fmt/printf.h
- include/fmt/ranges.h)
+function(add_headers VAR)
+ set(headers ${${VAR}})
+ foreach (header ${ARGN})
+ set(headers ${headers} include/fmt/${header})
+ endforeach()
+ set(${VAR} ${headers} PARENT_SCOPE)
+endfunction()
+
+# Define the fmt library, its includes and the needed defines.
+add_headers(FMT_HEADERS
+ args.h
+ chrono.h
+ color.h
+ compile.h
+ core.h
+ format.h
+ format-inl.h
+ locale.h os.h
+ ostream.h
+ printf.h
+ ranges.h
+ xchar.h)
set(FMT_SOURCES
src/format.cc
src/os.cc)
-add_library(fmt STATIC
- ${FMT_SOURCES}
- ${FMT_HEADERS})
+add_library(fmt STATIC ${FMT_SOURCES} ${FMT_HEADERS})
if (HAVE_STRTOD_L)
target_compile_definitions(fmt
diff --git a/deps/fmt/ChangeLog.rst b/deps/fmt/ChangeLog.rst
index 9c171af050..1988283caf 100644
--- a/deps/fmt/ChangeLog.rst
+++ b/deps/fmt/ChangeLog.rst
@@ -1,3 +1,699 @@
+8.0.1 - 2021-07-02
+------------------
+
+* Fixed the version number in the inline namespace
+ (`#2374 <https://github.com/fmtlib/fmt/issues/2374>`_).
+
+* Added a missing presentation type check for ``std::string``
+ (`#2402 <https://github.com/fmtlib/fmt/issues/2402>`_).
+
+* Fixed a linkage error when mixing code built with clang and gcc
+ (`#2377 <https://github.com/fmtlib/fmt/issues/2377>`_).
+
+* Fixed documentation issues
+ (`#2396 <https://github.com/fmtlib/fmt/pull/2396>`_,
+ `#2403 <https://github.com/fmtlib/fmt/issues/2403>`_,
+ `#2406 <https://github.com/fmtlib/fmt/issues/2406>`_).
+ Thanks `@mkurdej (Marek Kurdej) <https://github.com/mkurdej>`_.
+
+* Removed dead code in FP formatter (
+ `#2398 <https://github.com/fmtlib/fmt/pull/2398>`_).
+ Thanks `@javierhonduco (Javier Honduvilla Coto)
+ <https://github.com/javierhonduco>`_.
+
+* Fixed various warnings and compilation issues
+ (`#2351 <https://github.com/fmtlib/fmt/issues/2351>`_,
+ `#2359 <https://github.com/fmtlib/fmt/issues/2359>`_,
+ `#2365 <https://github.com/fmtlib/fmt/pull/2365>`_,
+ `#2368 <https://github.com/fmtlib/fmt/issues/2368>`_,
+ `#2370 <https://github.com/fmtlib/fmt/pull/2370>`_,
+ `#2376 <https://github.com/fmtlib/fmt/pull/2376>`_,
+ `#2381 <https://github.com/fmtlib/fmt/pull/2381>`_,
+ `#2382 <https://github.com/fmtlib/fmt/pull/2382>`_,
+ `#2386 <https://github.com/fmtlib/fmt/issues/2386>`_,
+ `#2389 <https://github.com/fmtlib/fmt/pull/2389>`_,
+ `#2395 <https://github.com/fmtlib/fmt/pull/2395>`_,
+ `#2397 <https://github.com/fmtlib/fmt/pull/2397>`_,
+ `#2400 <https://github.com/fmtlib/fmt/issues/2400>`_
+ `#2401 <https://github.com/fmtlib/fmt/issues/2401>`_,
+ `#2407 <https://github.com/fmtlib/fmt/pull/2407>`_).
+ Thanks `@zx2c4 (Jason A. Donenfeld) <https://github.com/zx2c4>`_,
+ `@AidanSun05 (Aidan Sun) <https://github.com/AidanSun05>`_,
+ `@mattiasljungstrom (Mattias Ljungström)
+ <https://github.com/mattiasljungstrom>`_,
+ `@joemmett (Jonathan Emmett) <https://github.com/joemmett>`_,
+ `@erengy (Eren Okka) <https://github.com/erengy>`_,
+ `@patlkli (Patrick Geltinger) <https://github.com/patlkli>`_,
+ `@gsjaardema (Greg Sjaardema) <https://github.com/gsjaardema>`_,
+ `@phprus (Vladislav Shchapov) <https://github.com/phprus>`_.
+
+8.0.0 - 2021-06-21
+------------------
+
+* Enabled compile-time format string check by default.
+ For example (`godbolt <https://godbolt.org/z/sMxcohGjz>`__):
+
+ .. code:: c++
+
+ #include <fmt/core.h>
+
+ int main() {
+ fmt::print("{:d}", "I am not a number");
+ }
+
+ gives a compile-time error on compilers with C++20 ``consteval`` support
+ (gcc 10+, clang 11+) because ``d`` is not a valid format specifier for a
+ string.
+
+ To pass a runtime string wrap it in ``fmt::runtime``:
+
+ .. code:: c++
+
+ fmt::print(fmt::runtime("{:d}"), "I am not a number");
+
+* Added compile-time formatting
+ (`#2019 <https://github.com/fmtlib/fmt/pull/2019>`_,
+ `#2044 <https://github.com/fmtlib/fmt/pull/2044>`_,
+ `#2056 <https://github.com/fmtlib/fmt/pull/2056>`_,
+ `#2072 <https://github.com/fmtlib/fmt/pull/2072>`_,
+ `#2075 <https://github.com/fmtlib/fmt/pull/2075>`_,
+ `#2078 <https://github.com/fmtlib/fmt/issues/2078>`_,
+ `#2129 <https://github.com/fmtlib/fmt/pull/2129>`_,
+ `#2326 <https://github.com/fmtlib/fmt/pull/2326>`_).
+ For example (`godbolt <https://godbolt.org/z/Mxx9d89jM>`__):
+
+ .. code:: c++
+
+ #include <fmt/compile.h>
+
+ consteval auto compile_time_itoa(int value) -> std::array<char, 10> {
+ auto result = std::array<char, 10>();
+ fmt::format_to(result.data(), FMT_COMPILE("{}"), value);
+ return result;
+ }
+
+ constexpr auto answer = compile_time_itoa(42);
+
+ Most of the formatting functionality is available at compile time with a
+ notable exception of floating-point numbers and pointers.
+ Thanks `@alexezeder (Alexey Ochapov) <https://github.com/alexezeder>`_.
+
+* Optimized handling of format specifiers during format string compilation.
+ For example, hexadecimal formatting (``"{:x}"``) is now 3-7x faster than
+ before when using ``format_to`` with format string compilation and a
+ stack-allocated buffer (`#1944 <https://github.com/fmtlib/fmt/issues/1944>`_).
+
+ Before (7.1.3)::
+
+ ----------------------------------------------------------------------------
+ Benchmark Time CPU Iterations
+ ----------------------------------------------------------------------------
+ FMTCompileOld/0 15.5 ns 15.5 ns 43302898
+ FMTCompileOld/42 16.6 ns 16.6 ns 43278267
+ FMTCompileOld/273123 18.7 ns 18.6 ns 37035861
+ FMTCompileOld/9223372036854775807 19.4 ns 19.4 ns 35243000
+ ----------------------------------------------------------------------------
+
+ After (8.x)::
+
+ ----------------------------------------------------------------------------
+ Benchmark Time CPU Iterations
+ ----------------------------------------------------------------------------
+ FMTCompileNew/0 1.99 ns 1.99 ns 360523686
+ FMTCompileNew/42 2.33 ns 2.33 ns 279865664
+ FMTCompileNew/273123 3.72 ns 3.71 ns 190230315
+ FMTCompileNew/9223372036854775807 5.28 ns 5.26 ns 130711631
+ ----------------------------------------------------------------------------
+
+ It is even faster than ``std::to_chars`` from libc++ compiled with clang on
+ macOS::
+
+ ----------------------------------------------------------------------------
+ Benchmark Time CPU Iterations
+ ----------------------------------------------------------------------------
+ ToChars/0 4.42 ns 4.41 ns 160196630
+ ToChars/42 5.00 ns 4.98 ns 140735201
+ ToChars/273123 7.26 ns 7.24 ns 95784130
+ ToChars/9223372036854775807 8.77 ns 8.75 ns 75872534
+ ----------------------------------------------------------------------------
+
+ In other cases, especially involving ``std::string`` construction, the
+ speed up is usually lower because handling format specifiers takes a smaller
+ fraction of the total time.
+
+* Added the ``_cf`` user-defined literal to represent a compiled format string.
+ It can be used instead of the ``FMT_COMPILE`` macro
+ (`#2043 <https://github.com/fmtlib/fmt/pull/2043>`_,
+ `#2242 <https://github.com/fmtlib/fmt/pull/2242>`_):
+
+ .. code:: c++
+
+ #include <fmt/compile.h>
+
+ using namespace fmt::literals;
+ auto s = fmt::format(FMT_COMPILE("{}"), 42); // 🙁 not modern
+ auto s = fmt::format("{}"_cf, 42); // 🙂 modern as hell
+
+ It requires compiler support for class types in non-type template parameters
+ (a C++20 feature) which is available in GCC 9.3+.
+ Thanks `@alexezeder (Alexey Ochapov) <https://github.com/alexezeder>`_.
+
+* Format string compilation now requires ``format`` functions of ``formatter``
+ specializations for user-defined types to be ``const``:
+
+ .. code:: c++
+
+ template <> struct fmt::formatter<my_type>: formatter<string_view> {
+ template <typename FormatContext>
+ auto format(my_type obj, FormatContext& ctx) const { // Note const here.
+ // ...
+ }
+ };
+
+* Added UDL-based named argument support to format string compilation
+ (`#2243 <https://github.com/fmtlib/fmt/pull/2243>`_,
+ `#2281 <https://github.com/fmtlib/fmt/pull/2281>`_). For example:
+
+ .. code:: c++
+
+ #include <fmt/compile.h>
+
+ using namespace fmt::literals;
+ auto s = fmt::format(FMT_COMPILE("{answer}"), "answer"_a = 42);
+
+ Here the argument named "answer" is resolved at compile time with no
+ runtime overhead.
+ Thanks `@alexezeder (Alexey Ochapov) <https://github.com/alexezeder>`_.
+
+* Added format string compilation support to ``fmt::print``
+ (`#2280 <https://github.com/fmtlib/fmt/issues/2280>`_,
+ `#2304 <https://github.com/fmtlib/fmt/pull/2304>`_).
+ Thanks `@alexezeder (Alexey Ochapov) <https://github.com/alexezeder>`_.
+
+* Added initial support for compiling {fmt} as a C++20 module
+ (`#2235 <https://github.com/fmtlib/fmt/pull/2235>`_,
+ `#2240 <https://github.com/fmtlib/fmt/pull/2240>`_,
+ `#2260 <https://github.com/fmtlib/fmt/pull/2260>`_,
+ `#2282 <https://github.com/fmtlib/fmt/pull/2282>`_,
+ `#2283 <https://github.com/fmtlib/fmt/pull/2283>`_,
+ `#2288 <https://github.com/fmtlib/fmt/pull/2288>`_,
+ `#2298 <https://github.com/fmtlib/fmt/pull/2298>`_,
+ `#2306 <https://github.com/fmtlib/fmt/pull/2306>`_,
+ `#2307 <https://github.com/fmtlib/fmt/pull/2307>`_,
+ `#2309 <https://github.com/fmtlib/fmt/pull/2309>`_,
+ `#2318 <https://github.com/fmtlib/fmt/pull/2318>`_,
+ `#2324 <https://github.com/fmtlib/fmt/pull/2324>`_,
+ `#2332 <https://github.com/fmtlib/fmt/pull/2332>`_,
+ `#2340 <https://github.com/fmtlib/fmt/pull/2340>`_).
+ Thanks `@DanielaE (Daniela Engert) <https://github.com/DanielaE>`_.
+
+* Made symbols private by default reducing shared library size
+ (`#2301 <https://github.com/fmtlib/fmt/pull/2301>`_). For example there was
+ a ~15% reported reduction on one platform.
+ Thanks `@sergiud (Sergiu Deitsch) <https://github.com/sergiud>`_.
+
+* Optimized includes making the result of preprocessing ``fmt/format.h``
+ ~20% smaller with libstdc++/C++20 and slightly improving build times
+ (`#1998 <https://github.com/fmtlib/fmt/issues/1998>`_).
+
+* Added support of ranges with non-const ``begin`` / ``end``
+ (`#1953 <https://github.com/fmtlib/fmt/pull/1953>`_).
+ Thanks `@kitegi (sarah) <https://github.com/kitegi>`_.
+
+* Added support of ``std::byte`` and other formattable types to ``fmt::join``
+ (`#1981 <https://github.com/fmtlib/fmt/issues/1981>`_,
+ `#2040 <https://github.com/fmtlib/fmt/issues/2040>`_,
+ `#2050 <https://github.com/fmtlib/fmt/pull/2050>`_,
+ `#2262 <https://github.com/fmtlib/fmt/issues/2262>`_). For example:
+
+ .. code:: c++
+
+ #include <fmt/format.h>
+ #include <cstddef>
+ #include <vector>
+
+ int main() {
+ auto bytes = std::vector{std::byte(4), std::byte(2)};
+ fmt::print("{}", fmt::join(bytes, ""));
+ }
+
+ prints "42".
+
+ Thanks `@kamibo (Camille Bordignon) <https://github.com/kamibo>`_.
+
+* Implemented the default format for ``std::chrono::system_clock``
+ (`#2319 <https://github.com/fmtlib/fmt/issues/2319>`_,
+ `#2345 <https://github.com/fmtlib/fmt/pull/2345>`_). For example:
+
+ .. code:: c++
+
+ #include <fmt/chrono.h>
+
+ int main() {
+ fmt::print("{}", std::chrono::system_clock::now());
+ }
+
+ prints "2021-06-18 15:22:00" (the output depends on the current date and
+ time). Thanks `@sunmy2019 <https://github.com/sunmy2019>`_.
+
+* Made more chrono specifiers locale independent by default. Use the ``'L'``
+ specifier to get localized formatting. For example:
+
+ .. code:: c++
+
+ #include <fmt/chrono.h>
+
+ int main() {
+ std::locale::global(std::locale("ru_RU.UTF-8"));
+ auto monday = std::chrono::weekday(1);
+ fmt::print("{}\n", monday); // prints "Mon"
+ fmt::print("{:L}\n", monday); // prints "пн"
+ }
+
+* Improved locale handling in chrono formatting
+ (`#2337 <https://github.com/fmtlib/fmt/issues/2337>`_,
+ `#2349 <https://github.com/fmtlib/fmt/pull/2349>`_,
+ `#2350 <https://github.com/fmtlib/fmt/pull/2350>`_).
+ Thanks `@phprus (Vladislav Shchapov) <https://github.com/phprus>`_.
+
+* Deprecated ``fmt/locale.h`` moving the formatting functions that take a
+ locale to ``fmt/format.h`` (``char``) and ``fmt/xchar`` (other overloads).
+ This doesn't introduce a dependency on ``<locale>`` so there is virtually no
+ compile time effect.
+
+* Made parameter order in ``vformat_to`` consistent with ``format_to``
+ (`#2327 <https://github.com/fmtlib/fmt/issues/2327>`_).
+
+* Added support for time points with arbitrary durations
+ (`#2208 <https://github.com/fmtlib/fmt/issues/2208>`_). For example:
+
+ .. code:: c++
+
+ #include <fmt/chrono.h>
+
+ int main() {
+ using tp = std::chrono::time_point<
+ std::chrono::system_clock, std::chrono::seconds>;
+ fmt::print("{:%S}", tp(std::chrono::seconds(42)));
+ }
+
+ prints "42".
+
+* Formatting floating-point numbers no longer produces trailing zeros by default
+ for consistency with ``std::format``. For example:
+
+ .. code:: c++
+
+ #include <fmt/core.h>
+
+ int main() {
+ fmt::print("{0:.3}", 1.1);
+ }
+
+ prints "1.1". Use the ``'#'`` specifier to keep trailing zeros.
+
+* Dropped a limit on the number of elements in a range and replaced ``{}`` with
+ ``[]`` as range delimiters for consistency with Python's ``str.format``.
+
+* The ``'L'`` specifier for locale-specific numeric formatting can now be
+ combined with presentation specifiers as in ``std::format``. For example:
+
+ .. code:: c++
+
+ #include <fmt/core.h>
+ #include <locale>
+
+ int main() {
+ std::locale::global(std::locale("fr_FR.UTF-8"));
+ fmt::print("{0:.2Lf}", 0.42);
+ }
+
+ prints "0,42". The deprecated ``'n'`` specifier has been removed.
+
+* Made the ``0`` specifier ignored for infinity and NaN
+ (`#2305 <https://github.com/fmtlib/fmt/issues/2305>`_,
+ `#2310 <https://github.com/fmtlib/fmt/pull/2310>`_).
+ Thanks `@Liedtke (Matthias Liedtke) <https://github.com/Liedtke>`_.
+
+* Made the hexfloat formatting use the right alignment by default
+ (`#2308 <https://github.com/fmtlib/fmt/issues/2308>`_,
+ `#2317 <https://github.com/fmtlib/fmt/pull/2317>`_).
+ Thanks `@Liedtke (Matthias Liedtke) <https://github.com/Liedtke>`_.
+
+* Removed the deprecated numeric alignment (``'='``). Use the ``'0'`` specifier
+ instead.
+
+* Removed the deprecated ``fmt/posix.h`` header that has been replaced with
+ ``fmt/os.h``.
+
+* Removed the deprecated ``format_to_n_context``, ``format_to_n_args`` and
+ ``make_format_to_n_args``. They have been replaced with ``format_context``,
+ ``format_args` and ``make_format_args`` respectively.
+
+* Moved ``wchar_t``-specific functions and types to ``fmt/xchar.h``.
+ You can define ``FMT_DEPRECATED_INCLUDE_XCHAR`` to automatically include
+ ``fmt/xchar.h`` from ``fmt/format.h`` but this will be disabled in the next
+ major release.
+
+* Fixed handling of the ``'+'`` specifier in localized formatting
+ (`#2133 <https://github.com/fmtlib/fmt/issues/2133>`_).
+
+* Added support for the ``'s'`` format specifier that gives textual
+ representation of ``bool``
+ (`#2094 <https://github.com/fmtlib/fmt/issues/2094>`_,
+ `#2109 <https://github.com/fmtlib/fmt/pull/2109>`_). For example:
+
+ .. code:: c++
+
+ #include <fmt/core.h>
+
+ int main() {
+ fmt::print("{:s}", true);
+ }
+
+ prints "true".
+ Thanks `@powercoderlol (Ivan Polyakov) <https://github.com/powercoderlol>`_.
+
+* Made ``fmt::ptr`` work with function pointers
+ (`#2131 <https://github.com/fmtlib/fmt/pull/2131>`_). For example:
+
+ .. code:: c++
+
+ #include <fmt/format.h>
+
+ int main() {
+ fmt::print("My main: {}\n", fmt::ptr(main));
+ }
+
+ Thanks `@mikecrowe (Mike Crowe) <https://github.com/mikecrowe>`_.
+
+* Fixed ``fmt::formatted_size`` with format string compilation
+ (`#2141 <https://github.com/fmtlib/fmt/pull/2141>`_,
+ `#2161 <https://github.com/fmtlib/fmt/pull/2161>`_).
+ Thanks `@alexezeder (Alexey Ochapov) <https://github.com/alexezeder>`_.
+
+* Fixed handling of empty format strings during format string compilation
+ (`#2042 <https://github.com/fmtlib/fmt/issues/2042>`_):
+
+ .. code:: c++
+
+ auto s = fmt::format(FMT_COMPILE(""));
+
+ Thanks `@alexezeder (Alexey Ochapov) <https://github.com/alexezeder>`_.
+
+* Fixed handling of enums in ``fmt::to_string``
+ (`#2036 <https://github.com/fmtlib/fmt/issues/2036>`_).
+
+* Improved width computation
+ (`#2033 <https://github.com/fmtlib/fmt/issues/2033>`_,
+ `#2091 <https://github.com/fmtlib/fmt/issues/2091>`_). For example:
+
+ .. code:: c++
+
+ #include <fmt/core.h>
+
+ int main() {
+ fmt::print("{:-<10}{}\n", "你好", "世界");
+ fmt::print("{:-<10}{}\n", "hello", "world");
+ }
+
+ prints
+
+ .. image:: https://user-images.githubusercontent.com/576385/
+ 119840373-cea3ca80-beb9-11eb-91e0-54266c48e181.png
+
+ on a modern terminal.
+
+* The experimental fast output stream (``fmt::ostream``) is now truncated by
+ default for consistency with ``fopen``
+ (`#2018 <https://github.com/fmtlib/fmt/issues/2018>`_). For example:
+
+ .. code:: c++
+
+ #include <fmt/os.h>
+
+ int main() {
+ fmt::ostream out1 = fmt::output_file("guide");
+ out1.print("Zaphod");
+ out1.close();
+ fmt::ostream out2 = fmt::output_file("guide");
+ out2.print("Ford");
+ }
+
+ writes "Ford" to the file "guide". To preserve the old file content if any
+ pass ``fmt::file::WRONLY | fmt::file::CREATE`` flags to ``fmt::output_file``.
+
+* Fixed moving of ``fmt::ostream`` that holds buffered data
+ (`#2197 <https://github.com/fmtlib/fmt/issues/2197>`_,
+ `#2198 <https://github.com/fmtlib/fmt/pull/2198>`_).
+ Thanks `@vtta <https://github.com/vtta>`_.
+
+* Replaced the ``fmt::system_error`` exception with a function of the same
+ name that constructs ``std::system_error``
+ (`#2266 <https://github.com/fmtlib/fmt/issues/2266>`_).
+
+* Replaced the ``fmt::windows_error`` exception with a function of the same
+ name that constructs ``std::system_error`` with the category returned by
+ ``fmt::system_category()``
+ (`#2274 <https://github.com/fmtlib/fmt/issues/2274>`_,
+ `#2275 <https://github.com/fmtlib/fmt/pull/2275>`_).
+ The latter is similar to ``std::sytem_category`` but correctly handles UTF-8.
+ Thanks `@phprus (Vladislav Shchapov) <https://github.com/phprus>`_.
+
+* Replaced ``fmt::error_code`` with ``std::error_code`` and made it formattable
+ (`#2269 <https://github.com/fmtlib/fmt/issues/2269>`_,
+ `#2270 <https://github.com/fmtlib/fmt/pull/2270>`_,
+ `#2273 <https://github.com/fmtlib/fmt/pull/2273>`_).
+ Thanks `@phprus (Vladislav Shchapov) <https://github.com/phprus>`_.
+
+* Added speech synthesis support
+ (`#2206 <https://github.com/fmtlib/fmt/pull/2206>`_).
+
+* Made ``format_to`` work with a memory buffer that has a custom allocator
+ (`#2300 <https://github.com/fmtlib/fmt/pull/2300>`_).
+ Thanks `@voxmea <https://github.com/voxmea>`_.
+
+* Added ``Allocator::max_size`` support to ``basic_memory_buffer``.
+ (`#1960 <https://github.com/fmtlib/fmt/pull/1960>`_).
+ Thanks `@phprus (Vladislav Shchapov) <https://github.com/phprus>`_.
+
+* Added wide string support to ``fmt::join``
+ (`#2236 <https://github.com/fmtlib/fmt/pull/2236>`_).
+ Thanks `@crbrz <https://github.com/crbrz>`_.
+
+* Made iterators passed to ``formatter`` specializations via a format context
+ satisfy C++20 ``std::output_iterator`` requirements
+ (`#2156 <https://github.com/fmtlib/fmt/issues/2156>`_,
+ `#2158 <https://github.com/fmtlib/fmt/pull/2158>`_,
+ `#2195 <https://github.com/fmtlib/fmt/issues/2195>`_,
+ `#2204 <https://github.com/fmtlib/fmt/pull/2204>`_).
+ Thanks `@randomnetcat (Jason Cobb) <https://github.com/randomnetcat>`_.
+
+* Optimized the ``printf`` implementation
+ (`#1982 <https://github.com/fmtlib/fmt/pull/1982>`_,
+ `#1984 <https://github.com/fmtlib/fmt/pull/1984>`_,
+ `#2016 <https://github.com/fmtlib/fmt/pull/2016>`_,
+ `#2164 <https://github.com/fmtlib/fmt/pull/2164>`_).
+ Thanks `@rimathia <https://github.com/rimathia>`_ and
+ `@moiwi <https://github.com/moiwi>`_.
+
+* Improved detection of ``constexpr`` ``char_traits``
+ (`#2246 <https://github.com/fmtlib/fmt/pull/2246>`_,
+ `#2257 <https://github.com/fmtlib/fmt/pull/2257>`_).
+ Thanks `@phprus (Vladislav Shchapov) <https://github.com/phprus>`_.
+
+* Fixed writing to ``stdout`` when it is redirected to ``NUL`` on Windows
+ (`#2080 <https://github.com/fmtlib/fmt/issues/2080>`_).
+
+* Fixed exception propagation from iterators
+ (`#2097 <https://github.com/fmtlib/fmt/issues/2097>`_).
+
+* Improved ``strftime`` error handling
+ (`#2238 <https://github.com/fmtlib/fmt/issues/2238>`_,
+ `#2244 <https://github.com/fmtlib/fmt/pull/2244>`_).
+ Thanks `@yumeyao <https://github.com/yumeyao>`_.
+
+* Stopped using deprecated GCC UDL template extension.
+
+* Added ``fmt/args.h`` to the install target
+ (`#2096 <https://github.com/fmtlib/fmt/issues/2096>`_).
+
+* Error messages are now passed to assert when exceptions are disabled
+ (`#2145 <https://github.com/fmtlib/fmt/pull/2145>`_).
+ Thanks `@NobodyXu (Jiahao XU) <https://github.com/NobodyXu>`_.
+
+* Added the ``FMT_MASTER_PROJECT`` CMake option to control build and install
+ targets when {fmt} is included via ``add_subdirectory``
+ (`#2098 <https://github.com/fmtlib/fmt/issues/2098>`_,
+ `#2100 <https://github.com/fmtlib/fmt/pull/2100>`_).
+ Thanks `@randomizedthinking <https://github.com/randomizedthinking>`_.
+
+* Improved build configuration
+ (`#2026 <https://github.com/fmtlib/fmt/pull/2026>`_,
+ `#2122 <https://github.com/fmtlib/fmt/pull/2122>`_).
+ Thanks `@luncliff (Park DongHa) <https://github.com/luncliff>`_ and
+ `@ibaned (Dan Ibanez) <https://github.com/ibaned>`_.
+
+* Fixed various warnings and compilation issues
+ (`#1947 <https://github.com/fmtlib/fmt/issues/1947>`_,
+ `#1959 <https://github.com/fmtlib/fmt/pull/1959>`_,
+ `#1963 <https://github.com/fmtlib/fmt/pull/1963>`_,
+ `#1965 <https://github.com/fmtlib/fmt/pull/1965>`_,
+ `#1966 <https://github.com/fmtlib/fmt/issues/1966>`_,
+ `#1974 <https://github.com/fmtlib/fmt/pull/1974>`_,
+ `#1975 <https://github.com/fmtlib/fmt/pull/1975>`_,
+ `#1990 <https://github.com/fmtlib/fmt/pull/1990>`_,
+ `#2000 <https://github.com/fmtlib/fmt/issues/2000>`_,
+ `#2001 <https://github.com/fmtlib/fmt/pull/2001>`_,
+ `#2002 <https://github.com/fmtlib/fmt/issues/2002>`_,
+ `#2004 <https://github.com/fmtlib/fmt/issues/2004>`_,
+ `#2006 <https://github.com/fmtlib/fmt/pull/2006>`_,
+ `#2009 <https://github.com/fmtlib/fmt/pull/2009>`_,
+ `#2010 <https://github.com/fmtlib/fmt/pull/2010>`_,
+ `#2038 <https://github.com/fmtlib/fmt/issues/2038>`_,
+ `#2039 <https://github.com/fmtlib/fmt/issues/2039>`_,
+ `#2047 <https://github.com/fmtlib/fmt/issues/2047>`_,
+ `#2053 <https://github.com/fmtlib/fmt/pull/2053>`_,
+ `#2059 <https://github.com/fmtlib/fmt/issues/2059>`_,
+ `#2065 <https://github.com/fmtlib/fmt/pull/2065>`_,
+ `#2067 <https://github.com/fmtlib/fmt/pull/2067>`_,
+ `#2068 <https://github.com/fmtlib/fmt/pull/2068>`_,
+ `#2073 <https://github.com/fmtlib/fmt/pull/2073>`_,
+ `#2103 <https://github.com/fmtlib/fmt/issues/2103>`_
+ `#2105 <https://github.com/fmtlib/fmt/issues/2105>`_
+ `#2106 <https://github.com/fmtlib/fmt/pull/2106>`_,
+ `#2107 <https://github.com/fmtlib/fmt/pull/2107>`_,
+ `#2116 <https://github.com/fmtlib/fmt/issues/2116>`_
+ `#2117 <https://github.com/fmtlib/fmt/pull/2117>`_,
+ `#2118 <https://github.com/fmtlib/fmt/issues/2118>`_
+ `#2119 <https://github.com/fmtlib/fmt/pull/2119>`_,
+ `#2127 <https://github.com/fmtlib/fmt/issues/2127>`_,
+ `#2128 <https://github.com/fmtlib/fmt/pull/2128>`_,
+ `#2140 <https://github.com/fmtlib/fmt/issues/2140>`_,
+ `#2142 <https://github.com/fmtlib/fmt/issues/2142>`_,
+ `#2143 <https://github.com/fmtlib/fmt/pull/2143>`_,
+ `#2144 <https://github.com/fmtlib/fmt/pull/2144>`_,
+ `#2147 <https://github.com/fmtlib/fmt/issues/2147>`_,
+ `#2148 <https://github.com/fmtlib/fmt/issues/2148>`_,
+ `#2149 <https://github.com/fmtlib/fmt/issues/2149>`_,
+ `#2152 <https://github.com/fmtlib/fmt/pull/2152>`_,
+ `#2160 <https://github.com/fmtlib/fmt/pull/2160>`_,
+ `#2170 <https://github.com/fmtlib/fmt/issues/2170>`_,
+ `#2175 <https://github.com/fmtlib/fmt/issues/2175>`_,
+ `#2176 <https://github.com/fmtlib/fmt/issues/2176>`_,
+ `#2177 <https://github.com/fmtlib/fmt/pull/2177>`_,
+ `#2178 <https://github.com/fmtlib/fmt/issues/2178>`_,
+ `#2179 <https://github.com/fmtlib/fmt/pull/2179>`_,
+ `#2180 <https://github.com/fmtlib/fmt/issues/2180>`_,
+ `#2181 <https://github.com/fmtlib/fmt/issues/2181>`_,
+ `#2183 <https://github.com/fmtlib/fmt/pull/2183>`_,
+ `#2184 <https://github.com/fmtlib/fmt/issues/2184>`_,
+ `#2185 <https://github.com/fmtlib/fmt/issues/2185>`_,
+ `#2186 <https://github.com/fmtlib/fmt/pull/2186>`_,
+ `#2187 <https://github.com/fmtlib/fmt/pull/2187>`_,
+ `#2190 <https://github.com/fmtlib/fmt/pull/2190>`_,
+ `#2192 <https://github.com/fmtlib/fmt/pull/2192>`_,
+ `#2194 <https://github.com/fmtlib/fmt/pull/2194>`_,
+ `#2205 <https://github.com/fmtlib/fmt/pull/2205>`_,
+ `#2210 <https://github.com/fmtlib/fmt/issues/2210>`_,
+ `#2211 <https://github.com/fmtlib/fmt/pull/2211>`_,
+ `#2215 <https://github.com/fmtlib/fmt/pull/2215>`_,
+ `#2216 <https://github.com/fmtlib/fmt/pull/2216>`_,
+ `#2218 <https://github.com/fmtlib/fmt/pull/2218>`_,
+ `#2220 <https://github.com/fmtlib/fmt/pull/2220>`_,
+ `#2228 <https://github.com/fmtlib/fmt/issues/2228>`_,
+ `#2229 <https://github.com/fmtlib/fmt/pull/2229>`_,
+ `#2230 <https://github.com/fmtlib/fmt/pull/2230>`_,
+ `#2233 <https://github.com/fmtlib/fmt/issues/2233>`_,
+ `#2239 <https://github.com/fmtlib/fmt/pull/2239>`_,
+ `#2248 <https://github.com/fmtlib/fmt/issues/2248>`_,
+ `#2252 <https://github.com/fmtlib/fmt/issues/2252>`_,
+ `#2253 <https://github.com/fmtlib/fmt/pull/2253>`_,
+ `#2255 <https://github.com/fmtlib/fmt/pull/2255>`_,
+ `#2261 <https://github.com/fmtlib/fmt/issues/2261>`_,
+ `#2278 <https://github.com/fmtlib/fmt/issues/2278>`_,
+ `#2284 <https://github.com/fmtlib/fmt/issues/2284>`_,
+ `#2287 <https://github.com/fmtlib/fmt/pull/2287>`_,
+ `#2289 <https://github.com/fmtlib/fmt/pull/2289>`_,
+ `#2290 <https://github.com/fmtlib/fmt/pull/2290>`_,
+ `#2293 <https://github.com/fmtlib/fmt/pull/2293>`_,
+ `#2295 <https://github.com/fmtlib/fmt/issues/2295>`_,
+ `#2296 <https://github.com/fmtlib/fmt/pull/2296>`_,
+ `#2297 <https://github.com/fmtlib/fmt/pull/2297>`_,
+ `#2311 <https://github.com/fmtlib/fmt/issues/2311>`_,
+ `#2313 <https://github.com/fmtlib/fmt/pull/2313>`_,
+ `#2315 <https://github.com/fmtlib/fmt/pull/2315>`_,
+ `#2320 <https://github.com/fmtlib/fmt/issues/2320>`_,
+ `#2321 <https://github.com/fmtlib/fmt/pull/2321>`_,
+ `#2323 <https://github.com/fmtlib/fmt/pull/2323>`_,
+ `#2328 <https://github.com/fmtlib/fmt/issues/2328>`_,
+ `#2329 <https://github.com/fmtlib/fmt/pull/2329>`_,
+ `#2333 <https://github.com/fmtlib/fmt/pull/2333>`_,
+ `#2338 <https://github.com/fmtlib/fmt/pull/2338>`_,
+ `#2341 <https://github.com/fmtlib/fmt/pull/2341>`_).
+ Thanks `@darklukee <https://github.com/darklukee>`_,
+ `@fagg (Ashton Fagg) <https://github.com/fagg>`_,
+ `@killerbot242 (Lieven de Cock) <https://github.com/killerbot242>`_,
+ `@jgopel (Jonathan Gopel) <https://github.com/jgopel>`_,
+ `@yeswalrus (Walter Gray) <https://github.com/yeswalrus>`_,
+ `@Finkman <https://github.com/Finkman>`_,
+ `@HazardyKnusperkeks (Björn Schäpers) <https://github.com/HazardyKnusperkeks>`_,
+ `@dkavolis (Daumantas Kavolis) <https://github.com/dkavolis>`_
+ `@concatime (Issam Maghni) <https://github.com/concatime>`_,
+ `@chronoxor (Ivan Shynkarenka) <https://github.com/chronoxor>`_,
+ `@summivox (Yin Zhong) <https://github.com/summivox>`_,
+ `@yNeo <https://github.com/yNeo>`_,
+ `@Apache-HB (Elliot) <https://github.com/Apache-HB>`_,
+ `@alexezeder (Alexey Ochapov) <https://github.com/alexezeder>`_,
+ `@toojays (John Steele Scott) <https://github.com/toojays>`_,
+ `@Brainy0207 <https://github.com/Brainy0207>`_,
+ `@vadz (VZ) <https://github.com/vadz>`_,
+ `@imsherlock (Ryan Sherlock) <https://github.com/imsherlock>`_,
+ `@phprus (Vladislav Shchapov) <https://github.com/phprus>`_,
+ `@white238 (Chris White) <https://github.com/white238>`_,
+ `@yafshar (Yaser Afshar) <https://github.com/yafshar>`_,
+ `@BillyDonahue (Billy Donahue) <https://github.com/BillyDonahue>`_,
+ `@jstaahl <https://github.com/jstaahl>`_,
+ `@denchat <https://github.com/denchat>`_,
+ `@DanielaE (Daniela Engert) <https://github.com/DanielaE>`_,
+ `@ilyakurdyukov (Ilya Kurdyukov) <https://github.com/ilyakurdyukov>`_,
+ `@ilmai <https://github.com/ilmai>`_,
+ `@JessyDL (Jessy De Lannoit) <https://github.com/JessyDL>`_,
+ `@sergiud (Sergiu Deitsch) <https://github.com/sergiud>`_,
+ `@mwinterb <https://github.com/mwinterb>`_,
+ `@sven-herrmann <https://github.com/sven-herrmann>`_,
+ `@jmelas (John Melas) <https://github.com/jmelas>`_,
+ `@twoixter (Jose Miguel Pérez) <https://github.com/twoixter>`_,
+ `@crbrz <https://github.com/crbrz>`_,
+ `@upsj (Tobias Ribizel) <https://github.com/upsj>`_.
+
+* Improved documentation
+ (`#1986 <https://github.com/fmtlib/fmt/issues/1986>`_,
+ `#2051 <https://github.com/fmtlib/fmt/pull/2051>`_,
+ `#2057 <https://github.com/fmtlib/fmt/issues/2057>`_,
+ `#2081 <https://github.com/fmtlib/fmt/pull/2081>`_,
+ `#2084 <https://github.com/fmtlib/fmt/issues/2084>`_,
+ `#2312 <https://github.com/fmtlib/fmt/pull/2312>`_).
+ Thanks `@imba-tjd (谭九鼎) <https://github.com/imba-tjd>`_,
+ `@0x416c69 (AlιAѕѕaѕѕιN) <https://github.com/0x416c69>`_,
+ `@mordante <https://github.com/mordante>`_.
+
+* Continuous integration and test improvements
+ (`#1969 <https://github.com/fmtlib/fmt/issues/1969>`_,
+ `#1991 <https://github.com/fmtlib/fmt/pull/1991>`_,
+ `#2020 <https://github.com/fmtlib/fmt/pull/2020>`_,
+ `#2110 <https://github.com/fmtlib/fmt/pull/2110>`_,
+ `#2114 <https://github.com/fmtlib/fmt/pull/2114>`_,
+ `#2196 <https://github.com/fmtlib/fmt/issues/2196>`_,
+ `#2217 <https://github.com/fmtlib/fmt/pull/2217>`_,
+ `#2247 <https://github.com/fmtlib/fmt/pull/2247>`_,
+ `#2256 <https://github.com/fmtlib/fmt/pull/2256>`_,
+ `#2336 <https://github.com/fmtlib/fmt/pull/2336>`_,
+ `#2346 <https://github.com/fmtlib/fmt/pull/2346>`_).
+ Thanks `@jgopel (Jonathan Gopel) <https://github.com/jgopel>`_,
+ `@alexezeder (Alexey Ochapov) <https://github.com/alexezeder>`_ and
+ `@DanielaE (Daniela Engert) <https://github.com/DanielaE>`_.
+
7.1.3 - 2020-11-24
------------------
@@ -269,8 +965,8 @@
Thanks `@Naios (Denis Blank) <https://github.com/Naios>`_.
-* Made the ``#`` specifier emit trailing zeros in addition to the decimal point
- (`#1797 <https://github.com/fmtlib/fmt/issues/1797>`_). For example
+* Made the ``'#'`` specifier emit trailing zeros in addition to the decimal
+ point (`#1797 <https://github.com/fmtlib/fmt/issues/1797>`_). For example
(`godbolt <https://godbolt.org/z/bhdcW9>`__):
.. code:: c++
diff --git a/deps/fmt/README.rst b/deps/fmt/README.rst
index 7cf794e4ac..02c849c78f 100644
--- a/deps/fmt/README.rst
+++ b/deps/fmt/README.rst
@@ -26,9 +26,9 @@
**{fmt}** is an open-source formatting library providing a fast and safe
alternative to C stdio and C++ iostreams.
-If you like this project, please consider donating to BY_Help,
-an initiative to help victims of political repressions in Belarus:
-https://www.facebook.com/donate/199475051809330/.
+If you like this project, please consider donating to the BYSOL
+Foundation that helps victims of political repressions in Belarus:
+https://bysol.org/en/bs/general/.
`Documentation <https://fmt.dev>`__
@@ -341,6 +341,10 @@ Projects using this library
* `Folly <https://github.com/facebook/folly>`_: Facebook open-source library
+* `Grand Mountain Adventure
+ <https://store.steampowered.com/app/1247360/Grand_Mountain_Adventure/>`_:
+ A beautiful open-world ski & snowboarding game
+
* `HarpyWar/pvpgn <https://github.com/pvpgn/pvpgn-server>`_:
Player vs Player Gaming Network with tweaks
diff --git a/deps/fmt/include/fmt/chrono.h b/deps/fmt/include/fmt/chrono.h
index e26e519039..c024fd710c 100644
--- a/deps/fmt/include/fmt/chrono.h
+++ b/deps/fmt/include/fmt/chrono.h
@@ -15,7 +15,6 @@
#include <sstream>
#include "format.h"
-#include "locale.h"
FMT_BEGIN_NAMESPACE
@@ -283,10 +282,80 @@ To safe_duration_cast(std::chrono::duration<FromRep, FromPeriod> from,
#define FMT_NOMACRO
namespace detail {
+template <typename T = void> struct null {};
inline null<> localtime_r FMT_NOMACRO(...) { return null<>(); }
inline null<> localtime_s(...) { return null<>(); }
inline null<> gmtime_r(...) { return null<>(); }
inline null<> gmtime_s(...) { return null<>(); }
+
+inline auto do_write(const std::tm& time, const std::locale& loc, char format,
+ char modifier) -> std::string {
+ auto&& os = std::ostringstream();
+ os.imbue(loc);
+ using iterator = std::ostreambuf_iterator<char>;
+ const auto& facet = std::use_facet<std::time_put<char, iterator>>(loc);
+ auto end = facet.put(os, os, ' ', &time, format, modifier);
+ if (end.failed()) FMT_THROW(format_error("failed to format time"));
+ auto str = os.str();
+ if (!detail::is_utf8() || loc == std::locale::classic()) return str;
+ // char16_t and char32_t codecvts are broken in MSVC (linkage errors) and
+ // gcc-4.
+#if FMT_MSC_VER != 0 || \
+ (defined(__GLIBCXX__) && !defined(_GLIBCXX_USE_DUAL_ABI))
+ // The _GLIBCXX_USE_DUAL_ABI macro is always defined in libstdc++ from gcc-5
+ // and newer.
+ using code_unit = wchar_t;
+#else
+ using code_unit = char32_t;
+#endif
+ auto& f = std::use_facet<std::codecvt<code_unit, char, std::mbstate_t>>(loc);
+ auto mb = std::mbstate_t();
+ const char* from_next = nullptr;
+ code_unit* to_next = nullptr;
+ constexpr size_t buf_size = 32;
+ code_unit buf[buf_size] = {};
+ auto result = f.in(mb, str.data(), str.data() + str.size(), from_next, buf,
+ buf + buf_size, to_next);
+ if (result != std::codecvt_base::ok)
+ FMT_THROW(format_error("failed to format time"));
+ str.clear();
+ for (code_unit* p = buf; p != to_next; ++p) {
+ uint32_t c = static_cast<uint32_t>(*p);
+ if (sizeof(code_unit) == 2 && c >= 0xd800 && c <= 0xdfff) {
+ // surrogate pair
+ ++p;
+ if (p == to_next || (c & 0xfc00) != 0xd800 || (*p & 0xfc00) != 0xdc00) {
+ FMT_THROW(format_error("failed to format time"));
+ }
+ c = (c << 10) + static_cast<uint32_t>(*p) - 0x35fdc00;
+ }
+ if (c < 0x80) {
+ str.push_back(static_cast<char>(c));
+ } else if (c < 0x800) {
+ str.push_back(static_cast<char>(0xc0 | (c >> 6)));
+ str.push_back(static_cast<char>(0x80 | (c & 0x3f)));
+ } else if ((c >= 0x800 && c <= 0xd7ff) || (c >= 0xe000 && c <= 0xffff)) {
+ str.push_back(static_cast<char>(0xe0 | (c >> 12)));
+ str.push_back(static_cast<char>(0x80 | ((c & 0xfff) >> 6)));
+ str.push_back(static_cast<char>(0x80 | (c & 0x3f)));
+ } else if (c >= 0x10000 && c <= 0x10ffff) {
+ str.push_back(static_cast<char>(0xf0 | (c >> 18)));
+ str.push_back(static_cast<char>(0x80 | ((c & 0x3ffff) >> 12)));
+ str.push_back(static_cast<char>(0x80 | ((c & 0xfff) >> 6)));
+ str.push_back(static_cast<char>(0x80 | (c & 0x3f)));
+ } else {
+ FMT_THROW(format_error("failed to format time"));
+ }
+ }
+ return str;
+}
+
+template <typename OutputIt>
+auto write(OutputIt out, const std::tm& time, const std::locale& loc,
+ char format, char modifier = 0) -> OutputIt {
+ auto str = do_write(time, loc, format, modifier);
+ return std::copy(str.begin(), str.end(), out);
+}
} // namespace detail
FMT_MODULE_EXPORT_BEGIN
@@ -408,14 +477,37 @@ FMT_END_DETAIL_NAMESPACE
template <typename Char, typename Duration>
struct formatter<std::chrono::time_point<std::chrono::system_clock, Duration>,
Char> : formatter<std::tm, Char> {
+ FMT_CONSTEXPR formatter() {
+ this->specs = {default_specs, sizeof(default_specs) / sizeof(Char)};
+ }
+
+ template <typename ParseContext>
+ FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
+ auto it = ctx.begin();
+ if (it != ctx.end() && *it == ':') ++it;
+ auto end = it;
+ while (end != ctx.end() && *end != '}') ++end;
+ if (end != it) this->specs = {it, detail::to_unsigned(end - it)};
+ return end;
+ }
+
template <typename FormatContext>
auto format(std::chrono::time_point<std::chrono::system_clock> val,
FormatContext& ctx) -> decltype(ctx.out()) {
std::tm time = localtime(val);
return formatter<std::tm, Char>::format(time, ctx);
}
+
+ static constexpr Char default_specs[] = {'%', 'Y', '-', '%', 'm', '-',
+ '%', 'd', ' ', '%', 'H', ':',
+ '%', 'M', ':', '%', 'S'};
};
+template <typename Char, typename Duration>
+constexpr Char
+ formatter<std::chrono::time_point<std::chrono::system_clock, Duration>,
+ Char>::default_specs[];
+
template <typename Char> struct formatter<std::tm, Char> {
template <typename ParseContext>
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
@@ -458,66 +550,28 @@ template <typename Char> struct formatter<std::tm, Char> {
FMT_BEGIN_DETAIL_NAMESPACE
-template <typename Period> FMT_CONSTEXPR const char* get_units() {
+template <typename Period> FMT_CONSTEXPR inline const char* get_units() {
+ if (std::is_same<Period, std::atto>::value) return "as";
+ if (std::is_same<Period, std::femto>::value) return "fs";
+ if (std::is_same<Period, std::pico>::value) return "ps";
+ if (std::is_same<Period, std::nano>::value) return "ns";
+ if (std::is_same<Period, std::micro>::value) return "µs";
+ if (std::is_same<Period, std::milli>::value) return "ms";
+ if (std::is_same<Period, std::centi>::value) return "cs";
+ if (std::is_same<Period, std::deci>::value) return "ds";
+ if (std::is_same<Period, std::ratio<1>>::value) return "s";
+ if (std::is_same<Period, std::deca>::value) return "das";
+ if (std::is_same<Period, std::hecto>::value) return "hs";
+ if (std::is_same<Period, std::kilo>::value) return "ks";
+ if (std::is_same<Period, std::mega>::value) return "Ms";
+ if (std::is_same<Period, std::giga>::value) return "Gs";
+ if (std::is_same<Period, std::tera>::value) return "Ts";
+ if (std::is_same<Period, std::peta>::value) return "Ps";
+ if (std::is_same<Period, std::exa>::value) return "Es";
+ if (std::is_same<Period, std::ratio<60>>::value) return "m";
+ if (std::is_same<Period, std::ratio<3600>>::value) return "h";
return nullptr;
}
-template <> FMT_CONSTEXPR inline const char* get_units<std::atto>() {
- return "as";
-}
-template <> FMT_CONSTEXPR inline const char* get_units<std::femto>() {
- return "fs";
-}
-template <> FMT_CONSTEXPR inline const char* get_units<std::pico>() {
- return "ps";
-}
-template <> FMT_CONSTEXPR inline const char* get_units<std::nano>() {
- return "ns";
-}
-template <> FMT_CONSTEXPR inline const char* get_units<std::micro>() {
- return "µs";
-}
-template <> FMT_CONSTEXPR inline const char* get_units<std::milli>() {
- return "ms";
-}
-template <> FMT_CONSTEXPR inline const char* get_units<std::centi>() {
- return "cs";
-}
-template <> FMT_CONSTEXPR inline const char* get_units<std::deci>() {
- return "ds";
-}
-template <> FMT_CONSTEXPR inline const char* get_units<std::ratio<1>>() {
- return "s";
-}
-template <> FMT_CONSTEXPR inline const char* get_units<std::deca>() {
- return "das";
-}
-template <> FMT_CONSTEXPR inline const char* get_units<std::hecto>() {
- return "hs";
-}
-template <> FMT_CONSTEXPR inline const char* get_units<std::kilo>() {
- return "ks";
-}
-template <> FMT_CONSTEXPR inline const char* get_units<std::mega>() {
- return "Ms";
-}
-template <> FMT_CONSTEXPR inline const char* get_units<std::giga>() {
- return "Gs";
-}
-template <> FMT_CONSTEXPR inline const char* get_units<std::tera>() {
- return "Ts";
-}
-template <> FMT_CONSTEXPR inline const char* get_units<std::peta>() {
- return "Ps";
-}
-template <> FMT_CONSTEXPR inline const char* get_units<std::exa>() {
- return "Es";
-}
-template <> FMT_CONSTEXPR inline const char* get_units<std::ratio<60>>() {
- return "m";
-}
-template <> FMT_CONSTEXPR inline const char* get_units<std::ratio<3600>>() {
- return "h";
-}
enum class numeric_system {
standard,
@@ -683,34 +737,50 @@ FMT_CONSTEXPR const Char* parse_chrono_format(const Char* begin,
return ptr;
}
-struct chrono_format_checker {
- FMT_NORETURN void report_no_date() { FMT_THROW(format_error("no date")); }
+template <typename Derived> struct null_chrono_spec_handler {
+ FMT_CONSTEXPR void unsupported() {
+ static_cast<Derived*>(this)->unsupported();
+ }
+ FMT_CONSTEXPR void on_abbr_weekday() { unsupported(); }
+ FMT_CONSTEXPR void on_full_weekday() { unsupported(); }
+ FMT_CONSTEXPR void on_dec0_weekday(numeric_system) { unsupported(); }
+ FMT_CONSTEXPR void on_dec1_weekday(numeric_system) { unsupported(); }
+ FMT_CONSTEXPR void on_abbr_month() { unsupported(); }
+ FMT_CONSTEXPR void on_full_month() { unsupported(); }
+ FMT_CONSTEXPR void on_24_hour(numeric_system) { unsupported(); }
+ FMT_CONSTEXPR void on_12_hour(numeric_system) { unsupported(); }
+ FMT_CONSTEXPR void on_minute(numeric_system) { unsupported(); }
+ FMT_CONSTEXPR void on_second(numeric_system) { unsupported(); }
+ FMT_CONSTEXPR void on_datetime(numeric_system) { unsupported(); }
+ FMT_CONSTEXPR void on_loc_date(numeric_system) { unsupported(); }
+ FMT_CONSTEXPR void on_loc_time(numeric_system) { unsupported(); }
+ FMT_CONSTEXPR void on_us_date() { unsupported(); }
+ FMT_CONSTEXPR void on_iso_date() { unsupported(); }
+ FMT_CONSTEXPR void on_12_hour_time() { unsupported(); }
+ FMT_CONSTEXPR void on_24_hour_time() { unsupported(); }
+ FMT_CONSTEXPR void on_iso_time() { unsupported(); }
+ FMT_CONSTEXPR void on_am_pm() { unsupported(); }
+ FMT_CONSTEXPR void on_duration_value() { unsupported(); }
+ FMT_CONSTEXPR void on_duration_unit() { unsupported(); }
+ FMT_CONSTEXPR void on_utc_offset() { unsupported(); }
+ FMT_CONSTEXPR void on_tz_name() { unsupported(); }
+};
+
+struct chrono_format_checker : null_chrono_spec_handler<chrono_format_checker> {
+ FMT_NORETURN void unsupported() { FMT_THROW(format_error("no date")); }
template <typename Char>
FMT_CONSTEXPR void on_text(const Char*, const Char*) {}
- FMT_NORETURN void on_abbr_weekday() { report_no_date(); }
- FMT_NORETURN void on_full_weekday() { report_no_date(); }
- FMT_NORETURN void on_dec0_weekday(numeric_system) { report_no_date(); }
- FMT_NORETURN void on_dec1_weekday(numeric_system) { report_no_date(); }
- FMT_NORETURN void on_abbr_month() { report_no_date(); }
- FMT_NORETURN void on_full_month() { report_no_date(); }
FMT_CONSTEXPR void on_24_hour(numeric_system) {}
FMT_CONSTEXPR void on_12_hour(numeric_system) {}
FMT_CONSTEXPR void on_minute(numeric_system) {}
FMT_CONSTEXPR void on_second(numeric_system) {}
- FMT_NORETURN void on_datetime(numeric_system) { report_no_date(); }
- FMT_NORETURN void on_loc_date(numeric_system) { report_no_date(); }
- FMT_NORETURN void on_loc_time(numeric_system) { report_no_date(); }
- FMT_NORETURN void on_us_date() { report_no_date(); }
- FMT_NORETURN void on_iso_date() { report_no_date(); }
FMT_CONSTEXPR void on_12_hour_time() {}
FMT_CONSTEXPR void on_24_hour_time() {}
FMT_CONSTEXPR void on_iso_time() {}
FMT_CONSTEXPR void on_am_pm() {}
FMT_CONSTEXPR void on_duration_value() {}
FMT_CONSTEXPR void on_duration_unit() {}
- FMT_NORETURN void on_utc_offset() { report_no_date(); }
- FMT_NORETURN void on_tz_name() { report_no_date(); }
};
template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
@@ -957,14 +1027,9 @@ struct chrono_formatter {
void format_localized(const tm& time, char format, char modifier = 0) {
if (isnan(val)) return write_nan();
- auto locale = localized ? context.locale().template get<std::locale>()
- : std::locale::classic();
- auto& facet = std::use_facet<std::time_put<char_type>>(locale);
- std::basic_ostringstream<char_type> os;
- os.imbue(locale);
- facet.put(os, os, ' ', &time, format, modifier);
- auto str = os.str();
- std::copy(str.begin(), str.end(), out);
+ const auto& loc = localized ? context.locale().template get<std::locale>()
+ : std::locale::classic();
+ out = detail::write(out, time, loc, format, modifier);
}
void on_text(const char_type* begin, const char_type* end) {
@@ -1080,6 +1145,46 @@ struct chrono_formatter {
FMT_END_DETAIL_NAMESPACE
+#if defined(__cpp_lib_chrono) && __cpp_lib_chrono >= 201907
+using weekday = std::chrono::weekday;
+#else
+// A fallback version of weekday.
+class weekday {
+ private:
+ unsigned char value;
+
+ public:
+ weekday() = default;
+ explicit constexpr weekday(unsigned wd) noexcept
+ : value(static_cast<unsigned char>(wd != 7 ? wd : 0)) {}
+ constexpr unsigned c_encoding() const noexcept { return value; }
+};
+#endif
+
+// A rudimentary weekday formatter.
+template <> struct formatter<weekday> {
+ private:
+ bool localized = false;
+
+ public:
+ FMT_CONSTEXPR auto parse(format_parse_context& ctx) -> decltype(ctx.begin()) {
+ auto begin = ctx.begin(), end = ctx.end();
+ if (begin != end && *begin == 'L') {
+ ++begin;
+ localized = true;
+ }
+ return begin;
+ }
+
+ auto format(weekday wd, format_context& ctx) -> decltype(ctx.out()) {
+ auto time = std::tm();
+ time.tm_wday = static_cast<int>(wd.c_encoding());
+ const auto& loc = localized ? ctx.locale().template get<std::locale>()
+ : std::locale::classic();
+ return detail::write(ctx.out(), time, loc, 'a');
+ }
+};
+
template <typename Rep, typename Period, typename Char>
struct formatter<std::chrono::duration<Rep, Period>, Char> {
private:
@@ -1190,7 +1295,7 @@ struct formatter<std::chrono::duration<Rep, Period>, Char> {
ctx, out, d);
f.precision = precision_copy;
f.localized = localized;
- parse_chrono_format(begin, end, f);
+ detail::parse_chrono_format(begin, end, f);
}
return detail::write(
ctx.out(), basic_string_view<Char>(buf.data(), buf.size()), specs_copy);
diff --git a/deps/fmt/include/fmt/color.h b/deps/fmt/include/fmt/color.h
index 8cddbfe192..3d5490e87f 100644
--- a/deps/fmt/include/fmt/color.h
+++ b/deps/fmt/include/fmt/color.h
@@ -507,7 +507,7 @@ void vformat_to(buffer<Char>& buf, const text_style& ts,
auto background = detail::make_background_color<Char>(ts.get_background());
buf.append(background.begin(), background.end());
}
- detail::vformat_to(buf, format_str, args);
+ detail::vformat_to(buf, format_str, args, {});
if (has_style) detail::reset_color<Char>(buf);
}
@@ -582,8 +582,8 @@ inline std::basic_string<Char> vformat(
template <typename S, typename... Args, typename Char = char_t<S>>
inline std::basic_string<Char> format(const text_style& ts, const S& format_str,
const Args&... args) {
- return vformat(ts, to_string_view(format_str),
- fmt::make_args_checked<Args...>(format_str, args...));
+ return fmt::vformat(ts, to_string_view(format_str),
+ fmt::make_args_checked<Args...>(format_str, args...));
}
/**
@@ -594,7 +594,7 @@ template <typename OutputIt, typename Char,
OutputIt vformat_to(
OutputIt out, const text_style& ts, basic_string_view<Char> format_str,
basic_format_args<buffer_context<type_identity_t<Char>>> args) {
- decltype(detail::get_buffer<Char>(out)) buf(detail::get_buffer_init(out));
+ auto&& buf = detail::get_buffer<Char>(out);
detail::vformat_to(buf, ts, format_str, args);
return detail::get_iterator(buf);
}
diff --git a/deps/fmt/include/fmt/compile.h b/deps/fmt/include/fmt/compile.h
index 128004bc5a..00000c92e3 100644
--- a/deps/fmt/include/fmt/compile.h
+++ b/deps/fmt/include/fmt/compile.h
@@ -157,13 +157,15 @@ struct is_compiled_string : std::is_base_of<compiled_string, S> {};
\endrst
*/
#ifdef __cpp_if_constexpr
-# define FMT_COMPILE(s) FMT_STRING_IMPL(s, fmt::detail::compiled_string)
+# define FMT_COMPILE(s) \
+ FMT_STRING_IMPL(s, fmt::detail::compiled_string, explicit)
#else
# define FMT_COMPILE(s) FMT_STRING(s)
#endif
#if FMT_USE_NONTYPE_TEMPLATE_PARAMETERS
-template <typename Char, size_t N, fixed_string<Char, N> Str>
+template <typename Char, size_t N,
+ fmt::detail_exported::fixed_string<Char, N> Str>
struct udl_compiled_string : compiled_string {
using char_type = Char;
constexpr operator basic_string_view<char_type>() const {
@@ -382,24 +384,22 @@ constexpr parse_specs_result<T, Char> parse_specs(basic_string_view<Char> str,
}
template <typename Char> struct arg_id_handler {
- constexpr void on_error(const char* message) { throw format_error(message); }
+ arg_ref<Char> arg_id;
- constexpr int on_arg_id() {
+ constexpr int operator()() {
FMT_ASSERT(false, "handler cannot be used with automatic indexing");
return 0;
}
-
- constexpr int on_arg_id(int id) {
+ constexpr int operator()(int id) {
arg_id = arg_ref<Char>(id);
return 0;
}
-
- constexpr int on_arg_id(basic_string_view<Char> id) {
+ constexpr int operator()(basic_string_view<Char> id) {
arg_id = arg_ref<Char>(id);
return 0;
}
- arg_ref<Char> arg_id;
+ constexpr void on_error(const char* message) { throw format_error(message); }
};
template <typename Char> struct parse_arg_id_result {
@@ -410,8 +410,7 @@ template <typename Char> struct parse_arg_id_result {
template <int ID, typename Char>
constexpr auto parse_arg_id(const Char* begin, const Char* end) {
auto handler = arg_id_handler<Char>{arg_ref<Char>{}};
- auto adapter = id_adapter<arg_id_handler<Char>, Char>{handler, 0};
- auto arg_id_end = parse_arg_id(begin, end, adapter);
+ auto arg_id_end = parse_arg_id(begin, end, handler);
return parse_arg_id_result<Char>{handler.arg_id, arg_id_end};
}
@@ -428,7 +427,7 @@ template <typename T, typename Args, size_t END_POS, int ARG_INDEX, int NEXT_ID,
typename S>
constexpr auto parse_replacement_field_then_tail(S format_str) {
using char_type = typename S::char_type;
- constexpr basic_string_view<char_type> str = format_str;
+ constexpr auto str = basic_string_view<char_type>(format_str);
constexpr char_type c = END_POS != str.size() ? str[END_POS] : char_type();
if constexpr (c == '}') {
return parse_tail<Args, END_POS + 1, NEXT_ID>(
@@ -449,7 +448,7 @@ constexpr auto parse_replacement_field_then_tail(S format_str) {
template <typename Args, size_t POS, int ID, typename S>
constexpr auto compile_format_string(S format_str) {
using char_type = typename S::char_type;
- constexpr basic_string_view<char_type> str = format_str;
+ constexpr auto str = basic_string_view<char_type>(format_str);
if constexpr (str[POS] == '{') {
if constexpr (POS + 1 == str.size())
throw format_error("unmatched '{' in format string");
@@ -518,7 +517,7 @@ constexpr auto compile_format_string(S format_str) {
template <typename... Args, typename S,
FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
constexpr auto compile(S format_str) {
- constexpr basic_string_view<typename S::char_type> str = format_str;
+ constexpr auto str = basic_string_view<typename S::char_type>(format_str);
if constexpr (str.size() == 0) {
return detail::make_text(str, 0, 0);
} else {
@@ -557,7 +556,7 @@ template <typename S, typename... Args,
FMT_INLINE std::basic_string<typename S::char_type> format(const S&,
Args&&... args) {
if constexpr (std::is_same<typename S::char_type, char>::value) {
- constexpr basic_string_view<typename S::char_type> str = S();
+ constexpr auto str = basic_string_view<typename S::char_type>(S());
if constexpr (str.size() == 2 && str[0] == '{' && str[1] == '}') {
const auto& first = detail::first(args...);
if constexpr (detail::is_named_arg<
@@ -608,9 +607,23 @@ size_t formatted_size(const S& format_str, const Args&... args) {
return format_to(detail::counting_iterator(), format_str, args...).count();
}
+template <typename S, typename... Args,
+ FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
+void print(std::FILE* f, const S& format_str, const Args&... args) {
+ memory_buffer buffer;
+ format_to(std::back_inserter(buffer), format_str, args...);
+ detail::print(f, {buffer.data(), buffer.size()});
+}
+
+template <typename S, typename... Args,
+ FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
+void print(const S& format_str, const Args&... args) {
+ print(stdout, format_str, args...);
+}
+
#if FMT_USE_NONTYPE_TEMPLATE_PARAMETERS
inline namespace literals {
-template <detail::fixed_string Str>
+template <detail_exported::fixed_string Str>
constexpr detail::udl_compiled_string<
remove_cvref_t<decltype(Str.data[0])>,
sizeof(Str.data) / sizeof(decltype(Str.data[0])), Str>
diff --git a/deps/fmt/include/fmt/core.h b/deps/fmt/include/fmt/core.h
index 293d824250..d058398ac9 100644
--- a/deps/fmt/include/fmt/core.h
+++ b/deps/fmt/include/fmt/core.h
@@ -1,4 +1,4 @@
-// Formatting library for C++ - the core API
+// Formatting library for C++ - the core API for char/UTF-8
//
// Copyright (c) 2012 - present, Victor Zverovich
// All rights reserved.
@@ -8,15 +8,15 @@
#ifndef FMT_CORE_H_
#define FMT_CORE_H_
-#include <climits> // INT_MAX
-#include <cstdio> // std::FILE
+#include <cstdio> // std::FILE
#include <cstring>
#include <iterator>
+#include <limits>
#include <string>
#include <type_traits>
// The fmt library version in the form major * 10000 + minor * 100 + patch.
-#define FMT_VERSION 70104
+#define FMT_VERSION 80001
#ifdef __clang__
# define FMT_CLANG_VERSION (__clang_major__ * 100 + __clang_minor__)
@@ -24,7 +24,7 @@
# define FMT_CLANG_VERSION 0
#endif
-#if defined(__GNUC__) && !defined(__clang__)
+#if defined(__GNUC__) && !defined(__clang__) && !defined(__INTEL_COMPILER)
# define FMT_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__)
# define FMT_GCC_PRAGMA(arg) _Pragma(arg)
#else
@@ -32,35 +32,16 @@
# define FMT_GCC_PRAGMA(arg)
#endif
-#if defined(__INTEL_COMPILER)
-# define FMT_ICC_VERSION __INTEL_COMPILER
-#else
-# define FMT_ICC_VERSION 0
-#endif
-
#if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__)
# define FMT_HAS_GXX_CXX11 FMT_GCC_VERSION
#else
# define FMT_HAS_GXX_CXX11 0
#endif
-// Check if constexpr std::char_traits<>::compare,length is supported.
-#if defined(__GLIBCXX__)
-# if __cplusplus >= 201703L && defined(_GLIBCXX_RELEASE) && \
- _GLIBCXX_RELEASE >= 7 // GCC 7+ libstdc++ has _GLIBCXX_RELEASE.
-# define FMT_CONSTEXPR_CHAR_TRAITS constexpr
-# endif
-#elif defined(_LIBCPP_VERSION)
-# if __cplusplus >= 201703L && _LIBCPP_VERSION >= 4000
-# define FMT_CONSTEXPR_CHAR_TRAITS constexpr
-# endif
-#elif defined(_MSC_VER)
-# if _MSVC_LANG >= 201703L && _MSC_VER >= 1914
-# define FMT_CONSTEXPR_CHAR_TRAITS constexpr
-# endif
-#endif
-#ifndef FMT_CONSTEXPR_CHAR_TRAITS
-# define FMT_CONSTEXPR_CHAR_TRAITS
+#if defined(__INTEL_COMPILER)
+# define FMT_ICC_VERSION __INTEL_COMPILER
+#else
+# define FMT_ICC_VERSION 0
#endif
#ifdef __NVCC__
@@ -83,7 +64,8 @@
# define FMT_HAS_FEATURE(x) 0
#endif
-#if defined(__has_include) && !defined(__INTELLISENSE__) && \
+#if defined(__has_include) && \
+ (!defined(__INTELLISENSE__) || FMT_MSC_VER > 1900) && \
(!FMT_ICC_VERSION || FMT_ICC_VERSION >= 1600)
# define FMT_HAS_INCLUDE(x) __has_include(x)
#else
@@ -118,6 +100,22 @@
# define FMT_CONSTEXPR_DECL
#endif
+// Check if constexpr std::char_traits<>::compare,length is supported.
+#if defined(__GLIBCXX__)
+# if __cplusplus >= 201703L && defined(_GLIBCXX_RELEASE) && \
+ _GLIBCXX_RELEASE >= 7 // GCC 7+ libstdc++ has _GLIBCXX_RELEASE.
+# define FMT_CONSTEXPR_CHAR_TRAITS constexpr
+# endif
+#elif defined(_LIBCPP_VERSION) && __cplusplus >= 201703L && \
+ _LIBCPP_VERSION >= 4000
+# define FMT_CONSTEXPR_CHAR_TRAITS constexpr
+#elif FMT_MSC_VER >= 1914 && _MSVC_LANG >= 201703L
+# define FMT_CONSTEXPR_CHAR_TRAITS constexpr
+#endif
+#ifndef FMT_CONSTEXPR_CHAR_TRAITS
+# define FMT_CONSTEXPR_CHAR_TRAITS
+#endif
+
#ifndef FMT_OVERRIDE
# if FMT_HAS_FEATURE(cxx_override_control) || \
(FMT_GCC_VERSION >= 408 && FMT_HAS_GXX_CXX11) || FMT_MSC_VER >= 1900
@@ -176,25 +174,32 @@
# endif
#endif
-#ifndef FMT_DEPRECATED
-# if FMT_HAS_CPP14_ATTRIBUTE(deprecated) || FMT_MSC_VER >= 1900
-# define FMT_DEPRECATED [[deprecated]]
+#if __cplusplus == 201103L || __cplusplus == 201402L
+# if defined(__INTEL_COMPILER) || defined(__PGI)
+# define FMT_FALLTHROUGH
+# elif defined(__clang__)
+# define FMT_FALLTHROUGH [[clang::fallthrough]]
+# elif FMT_GCC_VERSION >= 700 && \
+ (!defined(__EDG_VERSION__) || __EDG_VERSION__ >= 520)
+# define FMT_FALLTHROUGH [[gnu::fallthrough]]
# else
-# if (defined(__GNUC__) && !defined(__LCC__)) || defined(__clang__)
-# define FMT_DEPRECATED __attribute__((deprecated))
-# elif FMT_MSC_VER
-# define FMT_DEPRECATED __declspec(deprecated)
-# else
-# define FMT_DEPRECATED /* deprecated */
-# endif
+# define FMT_FALLTHROUGH
# endif
+#elif FMT_HAS_CPP17_ATTRIBUTE(fallthrough) || \
+ (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L)
+# define FMT_FALLTHROUGH [[fallthrough]]
+#else
+# define FMT_FALLTHROUGH
#endif
-// Workaround broken [[deprecated]] in the Intel, PGI and NVCC compilers.
-#if FMT_ICC_VERSION || defined(__PGI) || FMT_NVCC
-# define FMT_DEPRECATED_ALIAS
-#else
-# define FMT_DEPRECATED_ALIAS FMT_DEPRECATED
+#ifndef FMT_USE_FLOAT
+# define FMT_USE_FLOAT 1
+#endif
+#ifndef FMT_USE_DOUBLE
+# define FMT_USE_DOUBLE 1
+#endif
+#ifndef FMT_USE_LONG_DOUBLE
+# define FMT_USE_LONG_DOUBLE 1
#endif
#ifndef FMT_INLINE
@@ -224,30 +229,20 @@
# define FMT_INLINE_NAMESPACE namespace
# define FMT_END_NAMESPACE \
} \
- using namespace v7; \
+ using namespace v8; \
}
# endif
# define FMT_BEGIN_NAMESPACE \
namespace fmt { \
- FMT_INLINE_NAMESPACE v7 {
+ FMT_INLINE_NAMESPACE v8 {
#endif
#ifndef FMT_MODULE_EXPORT
# define FMT_MODULE_EXPORT
-#endif
-#ifndef FMT_MODULE_EXPORT_BEGIN
# define FMT_MODULE_EXPORT_BEGIN
-#endif
-#ifndef FMT_MODULE_EXPORT_END
# define FMT_MODULE_EXPORT_END
-#endif
-#ifndef FMT_BEGIN_DETAIL_NAMESPACE
-# define FMT_BEGIN_DETAIL_NAMESPACE \
- namespace detail {
-#endif
-#ifndef FMT_END_DETAIL_NAMESPACE
-# define FMT_END_DETAIL_NAMESPACE \
- }
+# define FMT_BEGIN_DETAIL_NAMESPACE namespace detail {
+# define FMT_END_DETAIL_NAMESPACE }
#endif
#if !defined(FMT_HEADER_ONLY) && defined(_WIN32)
@@ -259,6 +254,11 @@
# endif
#else
# define FMT_CLASS_API
+# if defined(FMT_EXPORT) || defined(FMT_SHARED)
+# if defined(__GNUC__) || defined(__clang__)
+# define FMT_API __attribute__((visibility("default")))
+# endif
+# endif
#endif
#ifndef FMT_API
# define FMT_API
@@ -285,8 +285,16 @@
# define FMT_UNICODE !FMT_MSC_VER
#endif
-#ifndef FMT_COMPILE_TIME_CHECKS
-# define FMT_COMPILE_TIME_CHECKS 0
+#ifndef FMT_CONSTEVAL
+# if ((FMT_GCC_VERSION >= 1000 || FMT_CLANG_VERSION >= 1101) && \
+ __cplusplus > 201703L) || \
+ (defined(__cpp_consteval) && \
+ !FMT_MSC_VER) // consteval is broken in MSVC.
+# define FMT_CONSTEVAL consteval
+# define FMT_HAS_CONSTEVAL
+# else
+# define FMT_CONSTEVAL
+# endif
#endif
#ifndef FMT_USE_NONTYPE_TEMPLATE_PARAMETERS
@@ -309,21 +317,26 @@ FMT_BEGIN_NAMESPACE
FMT_MODULE_EXPORT_BEGIN
// Implementations of enable_if_t and other metafunctions for older systems.
-template <bool B, class T = void>
+template <bool B, typename T = void>
using enable_if_t = typename std::enable_if<B, T>::type;
-template <bool B, class T, class F>
+template <bool B, typename T, typename F>
using conditional_t = typename std::conditional<B, T, F>::type;
template <bool B> using bool_constant = std::integral_constant<bool, B>;
template <typename T>
using remove_reference_t = typename std::remove_reference<T>::type;
template <typename T>
-using remove_const_t = typename std::remove_const<T>::type;
-template <typename T>
using remove_cvref_t = typename std::remove_cv<remove_reference_t<T>>::type;
template <typename T> struct type_identity { using type = T; };
template <typename T> using type_identity_t = typename type_identity<T>::type;
-struct monostate {};
+struct monostate {
+ constexpr monostate() {}
+};
+
+// Suppress "unused variable" warnings with the method described in
+// https://herbsutter.com/2009/10/18/mailbag-shutting-up-compiler-warnings/.
+// (void)var does not work on many Intel compilers.
+template <typename... T> FMT_CONSTEXPR void ignore_unused(const T&...) {}
// An enable_if helper to be used in template parameters which results in much
// shorter symbols: https://godbolt.org/z/sWw4vP. Extra parentheses are needed
@@ -336,7 +349,7 @@ struct monostate {};
FMT_BEGIN_DETAIL_NAMESPACE
-constexpr FMT_INLINE bool is_constant_evaluated() FMT_NOEXCEPT {
+constexpr FMT_INLINE auto is_constant_evaluated() FMT_NOEXCEPT -> bool {
#ifdef __cpp_lib_is_constant_evaluated
return std::is_constant_evaluated();
#else
@@ -344,8 +357,8 @@ constexpr FMT_INLINE bool is_constant_evaluated() FMT_NOEXCEPT {
#endif
}
-// A helper function to suppress "conditional expression is constant" warnings.
-template <typename T> constexpr T const_check(T value) { return value; }
+// A function to suppress "conditional expression is constant" warnings.
+template <typename T> constexpr auto const_check(T value) -> T { return value; }
FMT_NORETURN FMT_API void assert_fail(const char* file, int line,
const char* message);
@@ -353,7 +366,8 @@ FMT_NORETURN FMT_API void assert_fail(const char* file, int line,
#ifndef FMT_ASSERT
# ifdef NDEBUG
// FMT_ASSERT is not empty to avoid -Werror=empty-body.
-# define FMT_ASSERT(condition, message) ((void)0)
+# define FMT_ASSERT(condition, message) \
+ ::fmt::ignore_unused((condition), (message))
# else
# define FMT_ASSERT(condition, message) \
((condition) /* void() fails with -Winvalid-constexpr on clang 4.0.1 */ \
@@ -378,28 +392,38 @@ template <typename T> struct std_string_view {};
# define FMT_USE_INT128 1
using int128_t = __int128_t;
using uint128_t = __uint128_t;
+template <typename T> inline auto convert_for_visit(T value) -> T {
+ return value;
+}
#else
# define FMT_USE_INT128 0
#endif
#if !FMT_USE_INT128
-struct int128_t {};
-struct uint128_t {};
+enum class int128_t {};
+enum class uint128_t {};
+// Reduce template instantiations.
+template <typename T> inline auto convert_for_visit(T) -> monostate {
+ return {};
+}
#endif
// Casts a nonnegative integer to unsigned.
template <typename Int>
-FMT_CONSTEXPR typename std::make_unsigned<Int>::type to_unsigned(Int value) {
+FMT_CONSTEXPR auto to_unsigned(Int value) ->
+ typename std::make_unsigned<Int>::type {
FMT_ASSERT(value >= 0, "negative value");
return static_cast<typename std::make_unsigned<Int>::type>(value);
}
FMT_MSC_WARNING(suppress : 4566) constexpr unsigned char micro[] = "\u00B5";
-template <typename Char> constexpr bool is_unicode() {
- return FMT_UNICODE || sizeof(Char) != 1 ||
- (sizeof(micro) == 3 && micro[0] == 0xC2 && micro[1] == 0xB5);
+constexpr auto is_utf8() -> bool {
+ // Avoid buggy sign extensions in MSVC's constant evaluation mode.
+ // https://developercommunity.visualstudio.com/t/C-difference-in-behavior-for-unsigned/1233612
+ using uchar = unsigned char;
+ return FMT_UNICODE || (sizeof(micro) == 3 && uchar(micro[0]) == 0xC2 &&
+ uchar(micro[1]) == 0xB5);
}
-
FMT_END_DETAIL_NAMESPACE
/**
@@ -454,15 +478,17 @@ template <typename Char> class basic_string_view {
size_(s.size()) {}
/** Returns a pointer to the string data. */
- constexpr const Char* data() const { return data_; }
+ constexpr auto data() const -> const Char* { return data_; }
/** Returns the string size. */
- constexpr size_t size() const { return size_; }
+ constexpr auto size() const -> size_t { return size_; }
- constexpr iterator begin() const { return data_; }
- constexpr iterator end() const { return data_ + size_; }
+ constexpr auto begin() const -> iterator { return data_; }
+ constexpr auto end() const -> iterator { return data_ + size_; }
- constexpr const Char& operator[](size_t pos) const { return data_[pos]; }
+ constexpr auto operator[](size_t pos) const -> const Char& {
+ return data_[pos];
+ }
FMT_CONSTEXPR void remove_prefix(size_t n) {
data_ += n;
@@ -470,7 +496,7 @@ template <typename Char> class basic_string_view {
}
// Lexicographically compare this string reference to other.
- FMT_CONSTEXPR_CHAR_TRAITS int compare(basic_string_view other) const {
+ FMT_CONSTEXPR_CHAR_TRAITS auto compare(basic_string_view other) const -> int {
size_t str_size = size_ < other.size_ ? size_ : other.size_;
int result = std::char_traits<Char>::compare(data_, other.data_, str_size);
if (result == 0)
@@ -478,70 +504,53 @@ template <typename Char> class basic_string_view {
return result;
}
- FMT_CONSTEXPR_CHAR_TRAITS friend bool operator==(basic_string_view lhs,
- basic_string_view rhs) {
+ FMT_CONSTEXPR_CHAR_TRAITS friend auto operator==(basic_string_view lhs,
+ basic_string_view rhs)
+ -> bool {
return lhs.compare(rhs) == 0;
}
- friend bool operator!=(basic_string_view lhs, basic_string_view rhs) {
+ friend auto operator!=(basic_string_view lhs, basic_string_view rhs) -> bool {
return lhs.compare(rhs) != 0;
}
- friend bool operator<(basic_string_view lhs, basic_string_view rhs) {
+ friend auto operator<(basic_string_view lhs, basic_string_view rhs) -> bool {
return lhs.compare(rhs) < 0;
}
- friend bool operator<=(basic_string_view lhs, basic_string_view rhs) {
+ friend auto operator<=(basic_string_view lhs, basic_string_view rhs) -> bool {
return lhs.compare(rhs) <= 0;
}
- friend bool operator>(basic_string_view lhs, basic_string_view rhs) {
+ friend auto operator>(basic_string_view lhs, basic_string_view rhs) -> bool {
return lhs.compare(rhs) > 0;
}
- friend bool operator>=(basic_string_view lhs, basic_string_view rhs) {
+ friend auto operator>=(basic_string_view lhs, basic_string_view rhs) -> bool {
return lhs.compare(rhs) >= 0;
}
};
using string_view = basic_string_view<char>;
-using wstring_view = basic_string_view<wchar_t>;
/** Specifies if ``T`` is a character type. Can be specialized by users. */
template <typename T> struct is_char : std::false_type {};
template <> struct is_char<char> : std::true_type {};
-template <> struct is_char<wchar_t> : std::true_type {};
-
-/**
- \rst
- Returns a string view of `s`. In order to add custom string type support to
- {fmt} provide an overload of `to_string_view` for it in the same namespace as
- the type for the argument-dependent lookup to work.
- **Example**::
-
- namespace my_ns {
- inline string_view to_string_view(const my_string& s) {
- return {s.data(), s.length()};
- }
- }
- std::string message = fmt::format(my_string("The answer is {}"), 42);
- \endrst
- */
+// Returns a string view of `s`.
template <typename Char, FMT_ENABLE_IF(is_char<Char>::value)>
-FMT_INLINE basic_string_view<Char> to_string_view(const Char* s) {
+FMT_INLINE auto to_string_view(const Char* s) -> basic_string_view<Char> {
return s;
}
-
template <typename Char, typename Traits, typename Alloc>
-inline basic_string_view<Char> to_string_view(
- const std::basic_string<Char, Traits, Alloc>& s) {
+inline auto to_string_view(const std::basic_string<Char, Traits, Alloc>& s)
+ -> basic_string_view<Char> {
return s;
}
-
template <typename Char>
-constexpr basic_string_view<Char> to_string_view(basic_string_view<Char> s) {
+constexpr auto to_string_view(basic_string_view<Char> s)
+ -> basic_string_view<Char> {
return s;
}
-
template <typename Char,
FMT_ENABLE_IF(!std::is_empty<detail::std_string_view<Char>>::value)>
-inline basic_string_view<Char> to_string_view(detail::std_string_view<Char> s) {
+inline auto to_string_view(detail::std_string_view<Char> s)
+ -> basic_string_view<Char> {
return s;
}
@@ -553,14 +562,15 @@ template <typename S>
struct is_compile_string : std::is_base_of<compile_string, S> {};
template <typename S, FMT_ENABLE_IF(is_compile_string<S>::value)>
-constexpr basic_string_view<typename S::char_type> to_string_view(const S& s) {
- return s;
+constexpr auto to_string_view(const S& s)
+ -> basic_string_view<typename S::char_type> {
+ return basic_string_view<typename S::char_type>(s);
}
FMT_BEGIN_DETAIL_NAMESPACE
void to_string_view(...);
-using fmt::v7::to_string_view;
+using fmt::v8::to_string_view;
// Specifies whether S is a string type convertible to fmt::basic_string_view.
// It should be a constexpr function but MSVC 2017 fails to compile it in
@@ -594,7 +604,6 @@ struct error_handler {
// This function is intentionally not constexpr to give a compile-time error.
FMT_NORETURN FMT_API void on_error(const char* message);
};
-
FMT_END_DETAIL_NAMESPACE
/** String's character type. */
@@ -604,16 +613,7 @@ template <typename S> using char_t = typename detail::char_t_impl<S>::type;
\rst
Parsing context consisting of a format string range being parsed and an
argument counter for automatic indexing.
-
- You can use one of the following type aliases for common character types:
-
- +-----------------------+-------------------------------------+
- | Type | Definition |
- +=======================+=====================================+
- | format_parse_context | basic_format_parse_context<char> |
- +-----------------------+-------------------------------------+
- | wformat_parse_context | basic_format_parse_context<wchar_t> |
- +-----------------------+-------------------------------------+
+ You can use the ``format_parse_context`` type alias for ``char`` instead.
\endrst
*/
template <typename Char, typename ErrorHandler = detail::error_handler>
@@ -635,12 +635,16 @@ class basic_format_parse_context : private ErrorHandler {
Returns an iterator to the beginning of the format string range being
parsed.
*/
- constexpr iterator begin() const FMT_NOEXCEPT { return format_str_.begin(); }
+ constexpr auto begin() const FMT_NOEXCEPT -> iterator {
+ return format_str_.begin();
+ }
/**
Returns an iterator past the end of the format string range being parsed.
*/
- constexpr iterator end() const FMT_NOEXCEPT { return format_str_.end(); }
+ constexpr auto end() const FMT_NOEXCEPT -> iterator {
+ return format_str_.end();
+ }
/** Advances the begin iterator to ``it``. */
FMT_CONSTEXPR void advance_to(iterator it) {
@@ -651,7 +655,7 @@ class basic_format_parse_context : private ErrorHandler {
Reports an error if using the manual argument indexing; otherwise returns
the next argument index and switches to the automatic indexing.
*/
- FMT_CONSTEXPR int next_arg_id() {
+ FMT_CONSTEXPR auto next_arg_id() -> int {
// Don't check if the argument id is valid to avoid overhead and because it
// will be checked during formatting anyway.
if (next_arg_id_ >= 0) return next_arg_id_++;
@@ -676,11 +680,10 @@ class basic_format_parse_context : private ErrorHandler {
ErrorHandler::on_error(message);
}
- constexpr ErrorHandler error_handler() const { return *this; }
+ constexpr auto error_handler() const -> ErrorHandler { return *this; }
};
using format_parse_context = basic_format_parse_context<char>;
-using wformat_parse_context = basic_format_parse_context<wchar_t>;
template <typename Context> class basic_format_arg;
template <typename Context> class basic_format_args;
@@ -693,7 +696,6 @@ struct formatter {
formatter() = delete;
};
-// DEPRECATED!
// Specifies if T has an enabled formatter specialization. A type can be
// formattable even if it doesn't have a formatter e.g. via a conversion.
template <typename T, typename Context>
@@ -705,11 +707,14 @@ template <typename T> struct is_contiguous : std::false_type {};
template <typename Char>
struct is_contiguous<std::basic_string<Char>> : std::true_type {};
+class appender;
+
FMT_BEGIN_DETAIL_NAMESPACE
// Extracts a reference to the container from back_insert_iterator.
template <typename Container>
-inline Container& get_container(std::back_insert_iterator<Container> it) {
+inline auto get_container(std::back_insert_iterator<Container> it)
+ -> Container& {
using bi_iterator = std::back_insert_iterator<Container>;
struct accessor : bi_iterator {
accessor(bi_iterator iter) : bi_iterator(iter) {}
@@ -718,6 +723,23 @@ inline Container& get_container(std::back_insert_iterator<Container> it) {
return *accessor(it).container;
}
+template <typename Char, typename InputIt, typename OutputIt>
+FMT_CONSTEXPR auto copy_str(InputIt begin, InputIt end, OutputIt out)
+ -> OutputIt {
+ while (begin != end) *out++ = static_cast<Char>(*begin++);
+ return out;
+}
+
+template <typename Char, FMT_ENABLE_IF(std::is_same<Char, char>::value)>
+FMT_CONSTEXPR auto copy_str(const Char* begin, const Char* end, Char* out)
+ -> Char* {
+ if (is_constant_evaluated())
+ return copy_str<Char, const Char*, Char*>(begin, end, out);
+ auto size = to_unsigned(end - begin);
+ memcpy(out, begin, size);
+ return out + size;
+}
+
/**
\rst
A contiguous memory buffer with an optional growing ability. It is an internal
@@ -741,6 +763,7 @@ template <typename T> class buffer {
capacity_(cap) {}
~buffer() = default;
+ buffer(buffer&&) = default;
/** Sets the buffer data and capacity. */
void set(T* buf_data, size_t buf_capacity) FMT_NOEXCEPT {
@@ -758,23 +781,23 @@ template <typename T> class buffer {
buffer(const buffer&) = delete;
void operator=(const buffer&) = delete;
- T* begin() FMT_NOEXCEPT { return ptr_; }
- T* end() FMT_NOEXCEPT { return ptr_ + size_; }
+ auto begin() FMT_NOEXCEPT -> T* { return ptr_; }
+ auto end() FMT_NOEXCEPT -> T* { return ptr_ + size_; }
- const T* begin() const FMT_NOEXCEPT { return ptr_; }
- const T* end() const FMT_NOEXCEPT { return ptr_ + size_; }
+ auto begin() const FMT_NOEXCEPT -> const T* { return ptr_; }
+ auto end() const FMT_NOEXCEPT -> const T* { return ptr_ + size_; }
/** Returns the size of this buffer. */
- size_t size() const FMT_NOEXCEPT { return size_; }
+ auto size() const FMT_NOEXCEPT -> size_t { return size_; }
/** Returns the capacity of this buffer. */
- size_t capacity() const FMT_NOEXCEPT { return capacity_; }
+ auto capacity() const FMT_NOEXCEPT -> size_t { return capacity_; }
/** Returns a pointer to the buffer data. */
- T* data() FMT_NOEXCEPT { return ptr_; }
+ auto data() FMT_NOEXCEPT -> T* { return ptr_; }
/** Returns a pointer to the buffer data. */
- const T* data() const FMT_NOEXCEPT { return ptr_; }
+ auto data() const FMT_NOEXCEPT -> const T* { return ptr_; }
/** Clears this buffer. */
void clear() { size_ = 0; }
@@ -802,16 +825,16 @@ template <typename T> class buffer {
/** Appends data to the end of the buffer. */
template <typename U> void append(const U* begin, const U* end);
- template <typename I> T& operator[](I index) { return ptr_[index]; }
- template <typename I> const T& operator[](I index) const {
+ template <typename I> auto operator[](I index) -> T& { return ptr_[index]; }
+ template <typename I> auto operator[](I index) const -> const T& {
return ptr_[index];
}
};
struct buffer_traits {
explicit buffer_traits(size_t) {}
- size_t count() const { return 0; }
- size_t limit(size_t size) { return size; }
+ auto count() const -> size_t { return 0; }
+ auto limit(size_t size) -> size_t { return size; }
};
class fixed_buffer_traits {
@@ -821,8 +844,8 @@ class fixed_buffer_traits {
public:
explicit fixed_buffer_traits(size_t limit) : limit_(limit) {}
- size_t count() const { return count_; }
- size_t limit(size_t size) {
+ auto count() const -> size_t { return count_; }
+ auto limit(size_t size) -> size_t {
size_t n = limit_ > count_ ? limit_ - count_ : 0;
count_ += size;
return size < n ? size : n;
@@ -841,18 +864,25 @@ class iterator_buffer final : public Traits, public buffer<T> {
void grow(size_t) final FMT_OVERRIDE {
if (this->size() == buffer_size) flush();
}
- void flush();
+
+ void flush() {
+ auto size = this->size();
+ this->clear();
+ out_ = copy_str<T>(data_, data_ + this->limit(size), out_);
+ }
public:
explicit iterator_buffer(OutputIt out, size_t n = buffer_size)
: Traits(n), buffer<T>(data_, 0, buffer_size), out_(out) {}
+ iterator_buffer(iterator_buffer&& other)
+ : Traits(other), buffer<T>(data_, 0, buffer_size), out_(other.out_) {}
~iterator_buffer() { flush(); }
- OutputIt out() {
+ auto out() -> OutputIt {
flush();
return out_;
}
- size_t count() const { return Traits::count() + this->size(); }
+ auto count() const -> size_t { return Traits::count() + this->size(); }
};
template <typename T> class iterator_buffer<T*, T> final : public buffer<T> {
@@ -862,7 +892,7 @@ template <typename T> class iterator_buffer<T*, T> final : public buffer<T> {
public:
explicit iterator_buffer(T* out, size_t = 0) : buffer<T>(out, 0, ~size_t()) {}
- T* out() { return &*this->end(); }
+ auto out() -> T* { return &*this->end(); }
};
// A buffer that writes to a container with the contiguous storage.
@@ -885,7 +915,7 @@ class iterator_buffer<std::back_insert_iterator<Container>,
: buffer<typename Container::value_type>(c.size()), container_(c) {}
explicit iterator_buffer(std::back_insert_iterator<Container> out, size_t = 0)
: iterator_buffer(get_container(out)) {}
- std::back_insert_iterator<Container> out() {
+ auto out() -> std::back_insert_iterator<Container> {
return std::back_inserter(container_);
}
};
@@ -907,49 +937,24 @@ template <typename T = char> class counting_buffer final : public buffer<T> {
public:
counting_buffer() : buffer<T>(data_, 0, buffer_size) {}
- size_t count() { return count_ + this->size(); }
+ auto count() -> size_t { return count_ + this->size(); }
};
-// An output iterator that appends to the buffer.
-// It is used to reduce symbol sizes for the common case.
template <typename T>
-class buffer_appender : public std::back_insert_iterator<buffer<T>> {
- using base = std::back_insert_iterator<buffer<T>>;
-
- public:
- using std::back_insert_iterator<buffer<T>>::back_insert_iterator;
- buffer_appender(base it) : base(it) {}
- using _Unchecked_type = buffer_appender; // Mark iterator as checked.
-
- buffer_appender& operator++() {
- base::operator++();
- return *this;
- }
-
- buffer_appender operator++(int) {
- buffer_appender tmp = *this;
- ++*this;
- return tmp;
- }
-};
+using buffer_appender = conditional_t<std::is_same<T, char>::value, appender,
+ std::back_insert_iterator<buffer<T>>>;
-// Maps an output iterator into a buffer.
+// Maps an output iterator to a buffer.
template <typename T, typename OutputIt>
-iterator_buffer<OutputIt, T> get_buffer(OutputIt);
-template <typename T> buffer<T>& get_buffer(buffer_appender<T>);
-
-template <typename OutputIt> OutputIt get_buffer_init(OutputIt out) {
- return out;
-}
-template <typename T> buffer<T>& get_buffer_init(buffer_appender<T> out) {
- return get_container(out);
+auto get_buffer(OutputIt out) -> iterator_buffer<OutputIt, T> {
+ return iterator_buffer<OutputIt, T>(out);
}
template <typename Buffer>
auto get_iterator(Buffer& buf) -> decltype(buf.out()) {
return buf.out();
}
-template <typename T> buffer_appender<T> get_iterator(buffer<T>& buf) {
+template <typename T> auto get_iterator(buffer<T>& buf) -> buffer_appender<T> {
return buffer_appender<T>(buf);
}
@@ -986,8 +991,8 @@ struct arg_data {
template <typename... U>
arg_data(const U&... init) : args_{T(named_args_, NUM_NAMED_ARGS), init...} {}
arg_data(const arg_data& other) = delete;
- const T* args() const { return args_ + 1; }
- named_arg_info<Char>* named_args() { return named_args_; }
+ auto args() const -> const T* { return args_ + 1; }
+ auto named_args() -> named_arg_info<Char>* { return named_args_; }
};
template <typename T, typename Char, size_t NUM_ARGS>
@@ -997,8 +1002,10 @@ struct arg_data<T, Char, NUM_ARGS, 0> {
template <typename... U>
FMT_CONSTEXPR FMT_INLINE arg_data(const U&... init) : args_{init...} {}
- FMT_CONSTEXPR FMT_INLINE const T* args() const { return args_; }
- FMT_CONSTEXPR FMT_INLINE std::nullptr_t named_args() { return nullptr; }
+ FMT_CONSTEXPR FMT_INLINE auto args() const -> const T* { return args_; }
+ FMT_CONSTEXPR FMT_INLINE auto named_args() -> std::nullptr_t {
+ return nullptr;
+ }
};
template <typename Char>
@@ -1029,12 +1036,12 @@ template <typename... Args>
FMT_CONSTEXPR FMT_INLINE void init_named_args(std::nullptr_t, int, int,
const Args&...) {}
-template <bool B = false> constexpr size_t count() { return B ? 1 : 0; }
-template <bool B1, bool B2, bool... Tail> constexpr size_t count() {
+template <bool B = false> constexpr auto count() -> size_t { return B ? 1 : 0; }
+template <bool B1, bool B2, bool... Tail> constexpr auto count() -> size_t {
return (B1 ? 1 : 0) + count<B2, Tail...>();
}
-template <typename... Args> constexpr size_t count_named_args() {
+template <typename... Args> constexpr auto count_named_args() -> size_t {
return count<is_named_arg<Args>::value...>();
}
@@ -1115,6 +1122,7 @@ template <typename Context> class value {
using char_type = typename Context::char_type;
union {
+ monostate no_value;
int int_value;
unsigned uint_value;
long long long_long_value;
@@ -1132,7 +1140,8 @@ template <typename Context> class value {
named_arg_value<char_type> named_args;
};
- constexpr FMT_INLINE value(int val = 0) : int_value(val) {}
+ constexpr FMT_INLINE value() : no_value() {}
+ constexpr FMT_INLINE value(int val) : int_value(val) {}
constexpr FMT_INLINE value(unsigned val) : uint_value(val) {}
constexpr FMT_INLINE value(long long val) : long_long_value(val) {}
constexpr FMT_INLINE value(unsigned long long val) : ulong_long_value(val) {}
@@ -1155,7 +1164,7 @@ template <typename Context> class value {
FMT_INLINE value(const named_arg_info<char_type>* args, size_t size)
: named_args{args, size} {}
- template <typename T> FMT_INLINE value(const T& val) {
+ template <typename T> FMT_CONSTEXPR FMT_INLINE value(const T& val) {
custom.value = &val;
// Get the formatter type through the context to allow different contexts
// have different extension points, e.g. `formatter<T>` for `format` and
@@ -1179,7 +1188,7 @@ template <typename Context> class value {
};
template <typename Context, typename T>
-FMT_CONSTEXPR basic_format_arg<Context> make_arg(const T& value);
+FMT_CONSTEXPR auto make_arg(const T& value) -> basic_format_arg<Context>;
// To minimize the number of types we need to deal with, long is translated
// either to int or to long long depending on its size.
@@ -1193,40 +1202,52 @@ struct unformattable {};
template <typename Context> struct arg_mapper {
using char_type = typename Context::char_type;
- FMT_CONSTEXPR FMT_INLINE int map(signed char val) { return val; }
- FMT_CONSTEXPR FMT_INLINE unsigned map(unsigned char val) { return val; }
- FMT_CONSTEXPR FMT_INLINE int map(short val) { return val; }
- FMT_CONSTEXPR FMT_INLINE unsigned map(unsigned short val) { return val; }
- FMT_CONSTEXPR FMT_INLINE int map(int val) { return val; }
- FMT_CONSTEXPR FMT_INLINE unsigned map(unsigned val) { return val; }
- FMT_CONSTEXPR FMT_INLINE long_type map(long val) { return val; }
- FMT_CONSTEXPR FMT_INLINE ulong_type map(unsigned long val) { return val; }
- FMT_CONSTEXPR FMT_INLINE long long map(long long val) { return val; }
- FMT_CONSTEXPR FMT_INLINE unsigned long long map(unsigned long long val) {
+ FMT_CONSTEXPR FMT_INLINE auto map(signed char val) -> int { return val; }
+ FMT_CONSTEXPR FMT_INLINE auto map(unsigned char val) -> unsigned {
+ return val;
+ }
+ FMT_CONSTEXPR FMT_INLINE auto map(short val) -> int { return val; }
+ FMT_CONSTEXPR FMT_INLINE auto map(unsigned short val) -> unsigned {
+ return val;
+ }
+ FMT_CONSTEXPR FMT_INLINE auto map(int val) -> int { return val; }
+ FMT_CONSTEXPR FMT_INLINE auto map(unsigned val) -> unsigned { return val; }
+ FMT_CONSTEXPR FMT_INLINE auto map(long val) -> long_type { return val; }
+ FMT_CONSTEXPR FMT_INLINE auto map(unsigned long val) -> ulong_type {
+ return val;
+ }
+ FMT_CONSTEXPR FMT_INLINE auto map(long long val) -> long long { return val; }
+ FMT_CONSTEXPR FMT_INLINE auto map(unsigned long long val)
+ -> unsigned long long {
return val;
}
- FMT_CONSTEXPR FMT_INLINE int128_t map(int128_t val) { return val; }
- FMT_CONSTEXPR FMT_INLINE uint128_t map(uint128_t val) { return val; }
- FMT_CONSTEXPR FMT_INLINE bool map(bool val) { return val; }
+ FMT_CONSTEXPR FMT_INLINE auto map(int128_t val) -> int128_t { return val; }
+ FMT_CONSTEXPR FMT_INLINE auto map(uint128_t val) -> uint128_t { return val; }
+ FMT_CONSTEXPR FMT_INLINE auto map(bool val) -> bool { return val; }
template <typename T, FMT_ENABLE_IF(is_char<T>::value)>
- FMT_CONSTEXPR FMT_INLINE char_type map(T val) {
+ FMT_CONSTEXPR FMT_INLINE auto map(T val) -> char_type {
static_assert(
std::is_same<T, char>::value || std::is_same<T, char_type>::value,
"mixing character types is disallowed");
return val;
}
- FMT_CONSTEXPR FMT_INLINE float map(float val) { return val; }
- FMT_CONSTEXPR FMT_INLINE double map(double val) { return val; }
- FMT_CONSTEXPR FMT_INLINE long double map(long double val) { return val; }
+ FMT_CONSTEXPR FMT_INLINE auto map(float val) -> float { return val; }
+ FMT_CONSTEXPR FMT_INLINE auto map(double val) -> double { return val; }
+ FMT_CONSTEXPR FMT_INLINE auto map(long double val) -> long double {
+ return val;
+ }
- FMT_CONSTEXPR FMT_INLINE const char_type* map(char_type* val) { return val; }
- FMT_CONSTEXPR FMT_INLINE const char_type* map(const char_type* val) {
+ FMT_CONSTEXPR FMT_INLINE auto map(char_type* val) -> const char_type* {
+ return val;
+ }
+ FMT_CONSTEXPR FMT_INLINE auto map(const char_type* val) -> const char_type* {
return val;
}
template <typename T, FMT_ENABLE_IF(is_string<T>::value)>
- FMT_CONSTEXPR FMT_INLINE basic_string_view<char_type> map(const T& val) {
+ FMT_CONSTEXPR FMT_INLINE auto map(const T& val)
+ -> basic_string_view<char_type> {
static_assert(std::is_same<char_type, char_t<T>>::value,
"mixing character types is disallowed");
return to_string_view(val);
@@ -1236,7 +1257,8 @@ template <typename Context> struct arg_mapper {
std::is_constructible<basic_string_view<char_type>, T>::value &&
!is_string<T>::value && !has_formatter<T, Context>::value &&
!has_fallback_formatter<T, char_type>::value)>
- FMT_CONSTEXPR FMT_INLINE basic_string_view<char_type> map(const T& val) {
+ FMT_CONSTEXPR FMT_INLINE auto map(const T& val)
+ -> basic_string_view<char_type> {
return basic_string_view<char_type>(val);
}
template <
@@ -1246,29 +1268,34 @@ template <typename Context> struct arg_mapper {
!std::is_constructible<basic_string_view<char_type>, T>::value &&
!is_string<T>::value && !has_formatter<T, Context>::value &&
!has_fallback_formatter<T, char_type>::value)>
- FMT_CONSTEXPR FMT_INLINE basic_string_view<char_type> map(const T& val) {
+ FMT_CONSTEXPR FMT_INLINE auto map(const T& val)
+ -> basic_string_view<char_type> {
return std_string_view<char_type>(val);
}
- FMT_CONSTEXPR FMT_INLINE const char* map(const signed char* val) {
+ FMT_CONSTEXPR FMT_INLINE auto map(const signed char* val) -> const char* {
static_assert(std::is_same<char_type, char>::value, "invalid string type");
return reinterpret_cast<const char*>(val);
}
- FMT_CONSTEXPR FMT_INLINE const char* map(const unsigned char* val) {
+ FMT_CONSTEXPR FMT_INLINE auto map(const unsigned char* val) -> const char* {
static_assert(std::is_same<char_type, char>::value, "invalid string type");
return reinterpret_cast<const char*>(val);
}
- FMT_CONSTEXPR FMT_INLINE const char* map(signed char* val) {
+ FMT_CONSTEXPR FMT_INLINE auto map(signed char* val) -> const char* {
const auto* const_val = val;
return map(const_val);
}
- FMT_CONSTEXPR FMT_INLINE const char* map(unsigned char* val) {
+ FMT_CONSTEXPR FMT_INLINE auto map(unsigned char* val) -> const char* {
const auto* const_val = val;
return map(const_val);
}
- FMT_CONSTEXPR FMT_INLINE const void* map(void* val) { return val; }
- FMT_CONSTEXPR FMT_INLINE const void* map(const void* val) { return val; }
- FMT_CONSTEXPR FMT_INLINE const void* map(std::nullptr_t val) { return val; }
+ FMT_CONSTEXPR FMT_INLINE auto map(void* val) -> const void* { return val; }
+ FMT_CONSTEXPR FMT_INLINE auto map(const void* val) -> const void* {
+ return val;
+ }
+ FMT_CONSTEXPR FMT_INLINE auto map(std::nullptr_t val) -> const void* {
+ return val;
+ }
// We use SFINAE instead of a const T* parameter to avoid conflicting with
// the C array overload.
@@ -1300,7 +1327,7 @@ template <typename Context> struct arg_mapper {
FMT_ENABLE_IF(!is_string<T>::value && !is_char<T>::value &&
(has_formatter<T, Context>::value ||
has_fallback_formatter<T, char_type>::value))>
- FMT_CONSTEXPR FMT_INLINE const T& map(const T& val) {
+ FMT_CONSTEXPR FMT_INLINE auto map(const T& val) -> const T& {
return val;
}
@@ -1310,7 +1337,7 @@ template <typename Context> struct arg_mapper {
return map(named_arg.value);
}
- unformattable map(...) { return {}; }
+ auto map(...) -> unformattable { return {}; }
};
// A type constant after applying arg_mapper<Context>.
@@ -1327,6 +1354,33 @@ enum : unsigned long long { has_named_args_bit = 1ULL << 62 };
FMT_END_DETAIL_NAMESPACE
+// An output iterator that appends to a buffer.
+// It is used to reduce symbol sizes for the common case.
+class appender : public std::back_insert_iterator<detail::buffer<char>> {
+ using base = std::back_insert_iterator<detail::buffer<char>>;
+
+ template <typename T>
+ friend auto get_buffer(appender out) -> detail::buffer<char>& {
+ return detail::get_container(out);
+ }
+
+ public:
+ using std::back_insert_iterator<detail::buffer<char>>::back_insert_iterator;
+ appender(base it) : base(it) {}
+ using _Unchecked_type = appender; // Mark iterator as checked.
+
+ auto operator++() -> appender& {
+ base::operator++();
+ return *this;
+ }
+
+ auto operator++(int) -> appender {
+ auto tmp = *this;
+ ++*this;
+ return tmp;
+ }
+};
+
// A formatting argument. It is a trivially copyable/constructible type to
// allow storage in basic_memory_buffer.
template <typename Context> class basic_format_arg {
@@ -1335,8 +1389,8 @@ template <typename Context> class basic_format_arg {
detail::type type_;
template <typename ContextType, typename T>
- friend FMT_CONSTEXPR basic_format_arg<ContextType> detail::make_arg(
- const T& value);
+ friend FMT_CONSTEXPR auto detail::make_arg(const T& value)
+ -> basic_format_arg<ContextType>;
template <typename Visitor, typename Ctx>
friend FMT_CONSTEXPR auto visit_format_arg(Visitor&& vis,
@@ -1374,10 +1428,12 @@ template <typename Context> class basic_format_arg {
return type_ != detail::type::none_type;
}
- detail::type type() const { return type_; }
+ auto type() const -> detail::type { return type_; }
- bool is_integral() const { return detail::is_integral_type(type_); }
- bool is_arithmetic() const { return detail::is_arithmetic_type(type_); }
+ auto is_integral() const -> bool { return detail::is_integral_type(type_); }
+ auto is_arithmetic() const -> bool {
+ return detail::is_arithmetic_type(type_);
+ }
};
/**
@@ -1388,9 +1444,8 @@ template <typename Context> class basic_format_arg {
\endrst
*/
template <typename Visitor, typename Context>
-FMT_CONSTEXPR_DECL FMT_INLINE auto visit_format_arg(
+FMT_CONSTEXPR FMT_INLINE auto visit_format_arg(
Visitor&& vis, const basic_format_arg<Context>& arg) -> decltype(vis(0)) {
- using char_type = typename Context::char_type;
switch (arg.type_) {
case detail::type::none_type:
break;
@@ -1402,16 +1457,10 @@ FMT_CONSTEXPR_DECL FMT_INLINE auto visit_format_arg(
return vis(arg.value_.long_long_value);
case detail::type::ulong_long_type:
return vis(arg.value_.ulong_long_value);
-#if FMT_USE_INT128
- case detail::type::int128_type:
- return vis(arg.value_.int128_value);
- case detail::type::uint128_type:
- return vis(arg.value_.uint128_value);
-#else
case detail::type::int128_type:
+ return vis(detail::convert_for_visit(arg.value_.int128_value));
case detail::type::uint128_type:
- break;
-#endif
+ return vis(detail::convert_for_visit(arg.value_.uint128_value));
case detail::type::bool_type:
return vis(arg.value_.bool_value);
case detail::type::char_type:
@@ -1425,8 +1474,8 @@ FMT_CONSTEXPR_DECL FMT_INLINE auto visit_format_arg(
case detail::type::cstring_type:
return vis(arg.value_.string.data);
case detail::type::string_type:
- return vis(basic_string_view<char_type>(arg.value_.string.data,
- arg.value_.string.size));
+ using sv = basic_string_view<typename Context::char_type>;
+ return vis(sv(arg.value_.string.data, arg.value_.string.size));
case detail::type::pointer_type:
return vis(arg.value_.pointer);
case detail::type::custom_type:
@@ -1437,6 +1486,12 @@ FMT_CONSTEXPR_DECL FMT_INLINE auto visit_format_arg(
FMT_BEGIN_DETAIL_NAMESPACE
+template <typename Char, typename InputIt>
+auto copy_str(InputIt begin, InputIt end, appender out) -> appender {
+ get_container(out).append(begin, end);
+ return out;
+}
+
#if FMT_GCC_VERSION && FMT_GCC_VERSION < 500
// A workaround for gcc 4.8 to make void_t work in a SFINAE context.
template <typename... Ts> struct void_t_impl { using type = void; };
@@ -1467,9 +1522,8 @@ struct is_contiguous_back_insert_iterator : std::false_type {};
template <typename Container>
struct is_contiguous_back_insert_iterator<std::back_insert_iterator<Container>>
: is_contiguous<Container> {};
-template <typename Char>
-struct is_contiguous_back_insert_iterator<buffer_appender<Char>>
- : std::true_type {};
+template <>
+struct is_contiguous_back_insert_iterator<appender> : std::true_type {};
// A type-erased reference to an std::locale to avoid heavy <locale> include.
class locale_ref {
@@ -1482,19 +1536,21 @@ class locale_ref {
explicit operator bool() const FMT_NOEXCEPT { return locale_ != nullptr; }
- template <typename Locale> Locale get() const;
+ template <typename Locale> auto get() const -> Locale;
};
-template <typename> constexpr unsigned long long encode_types() { return 0; }
+template <typename> constexpr auto encode_types() -> unsigned long long {
+ return 0;
+}
template <typename Context, typename Arg, typename... Args>
-constexpr unsigned long long encode_types() {
+constexpr auto encode_types() -> unsigned long long {
return static_cast<unsigned>(mapped_type_constant<Arg, Context>::value) |
(encode_types<Context, Args...>() << packed_arg_bits);
}
template <typename Context, typename T>
-FMT_CONSTEXPR basic_format_arg<Context> make_arg(const T& value) {
+FMT_CONSTEXPR auto make_arg(const T& value) -> basic_format_arg<Context> {
basic_format_arg<Context> arg;
arg.type_ = mapped_type_constant<T, Context>::value;
arg.value_ = arg_mapper<Context>().map(value);
@@ -1506,21 +1562,20 @@ FMT_CONSTEXPR basic_format_arg<Context> make_arg(const T& value) {
// another (not recommended).
template <bool IS_PACKED, typename Context, type, typename T,
FMT_ENABLE_IF(IS_PACKED)>
-FMT_CONSTEXPR FMT_INLINE value<Context> make_arg(const T& val) {
+FMT_CONSTEXPR FMT_INLINE auto make_arg(const T& val) -> value<Context> {
const auto& arg = arg_mapper<Context>().map(val);
static_assert(
!std::is_same<decltype(arg), const unformattable&>::value,
"Cannot format an argument. To make type T formattable provide a "
"formatter<T> specialization: https://fmt.dev/latest/api.html#udt");
- return arg;
+ return {arg};
}
template <bool IS_PACKED, typename Context, type, typename T,
FMT_ENABLE_IF(!IS_PACKED)>
-inline basic_format_arg<Context> make_arg(const T& value) {
+inline auto make_arg(const T& value) -> basic_format_arg<Context> {
return make_arg<Context>(value);
}
-
FMT_END_DETAIL_NAMESPACE
// Formatting context.
@@ -1552,32 +1607,35 @@ template <typename OutputIt, typename Char> class basic_format_context {
detail::locale_ref loc = detail::locale_ref())
: out_(out), args_(ctx_args), loc_(loc) {}
- constexpr format_arg arg(int id) const { return args_.get(id); }
- FMT_CONSTEXPR format_arg arg(basic_string_view<char_type> name) {
+ constexpr auto arg(int id) const -> format_arg { return args_.get(id); }
+ FMT_CONSTEXPR auto arg(basic_string_view<char_type> name) -> format_arg {
return args_.get(name);
}
- int arg_id(basic_string_view<char_type> name) { return args_.get_id(name); }
- const basic_format_args<basic_format_context>& args() const { return args_; }
+ FMT_CONSTEXPR auto arg_id(basic_string_view<char_type> name) -> int {
+ return args_.get_id(name);
+ }
+ auto args() const -> const basic_format_args<basic_format_context>& {
+ return args_;
+ }
- FMT_CONSTEXPR detail::error_handler error_handler() { return {}; }
+ FMT_CONSTEXPR auto error_handler() -> detail::error_handler { return {}; }
void on_error(const char* message) { error_handler().on_error(message); }
// Returns an iterator to the beginning of the output range.
- FMT_CONSTEXPR iterator out() { return out_; }
+ FMT_CONSTEXPR auto out() -> iterator { return out_; }
// Advances the begin iterator to ``it``.
void advance_to(iterator it) {
if (!detail::is_back_insert_iterator<iterator>()) out_ = it;
}
- FMT_CONSTEXPR detail::locale_ref locale() { return loc_; }
+ FMT_CONSTEXPR auto locale() -> detail::locale_ref { return loc_; }
};
template <typename Char>
using buffer_context =
basic_format_context<detail::buffer_appender<Char>, Char>;
using format_context = buffer_context<char>;
-using wformat_context = buffer_context<wchar_t>;
// Workaround an alias issue: https://stackoverflow.com/q/62767544/471164.
#define FMT_BUFFER_CONTEXT(Char) \
@@ -1647,29 +1705,8 @@ class format_arg_store
\endrst
*/
template <typename Context = format_context, typename... Args>
-constexpr format_arg_store<Context, Args...> make_format_args(
- const Args&... args) {
- return {args...};
-}
-
-/**
- \rst
- Constructs a `~fmt::format_arg_store` object that contains references
- to arguments and can be implicitly converted to `~fmt::format_args`.
- If ``format_str`` is a compile-time string then `make_args_checked` checks
- its validity at compile time.
- \endrst
- */
-template <typename... Args, typename S, typename Char = char_t<S>>
-FMT_INLINE auto make_args_checked(const S& format_str,
- const remove_reference_t<Args>&... args)
- -> format_arg_store<buffer_context<Char>, remove_reference_t<Args>...> {
- static_assert(
- detail::count<(
- std::is_base_of<detail::view, remove_reference_t<Args>>::value &&
- std::is_reference<Args>::value)...>() == 0,
- "passing views as lvalues is disallowed");
- detail::check_format_string<Args...>(format_str);
+constexpr auto make_format_args(const Args&... args)
+ -> format_arg_store<Context, Args...> {
return {args...};
}
@@ -1685,7 +1722,7 @@ FMT_INLINE auto make_args_checked(const S& format_str,
\endrst
*/
template <typename Char, typename T>
-inline detail::named_arg<Char, T> arg(const Char* name, const T& arg) {
+inline auto arg(const Char* name, const T& arg) -> detail::named_arg<Char, T> {
static_assert(!detail::is_named_arg<T>(), "nested named arguments");
return {name, arg};
}
@@ -1721,14 +1758,14 @@ template <typename Context> class basic_format_args {
const format_arg* args_;
};
- constexpr bool is_packed() const {
+ constexpr auto is_packed() const -> bool {
return (desc_ & detail::is_unpacked_bit) == 0;
}
- bool has_named_args() const {
+ auto has_named_args() const -> bool {
return (desc_ & detail::has_named_args_bit) != 0;
}
- FMT_CONSTEXPR detail::type type(int index) const {
+ FMT_CONSTEXPR auto type(int index) const -> detail::type {
int shift = index * detail::packed_arg_bits;
unsigned int mask = (1 << detail::packed_arg_bits) - 1;
return static_cast<detail::type>((desc_ >> shift) & mask);
@@ -1774,7 +1811,7 @@ template <typename Context> class basic_format_args {
args) {}
/** Returns the argument with the specified id. */
- FMT_CONSTEXPR format_arg get(int id) const {
+ FMT_CONSTEXPR auto get(int id) const -> format_arg {
format_arg arg;
if (!is_packed()) {
if (id < max_size()) arg = args_[id];
@@ -1787,12 +1824,14 @@ template <typename Context> class basic_format_args {
return arg;
}
- template <typename Char> format_arg get(basic_string_view<Char> name) const {
+ template <typename Char>
+ auto get(basic_string_view<Char> name) const -> format_arg {
int id = get_id(name);
return id >= 0 ? get(id) : format_arg();
}
- template <typename Char> int get_id(basic_string_view<Char> name) const {
+ template <typename Char>
+ auto get_id(basic_string_view<Char> name) const -> int {
if (!has_named_args()) return -1;
const auto& named_args =
(is_packed() ? values_[-1] : args_[-1].value_).named_args;
@@ -1802,7 +1841,7 @@ template <typename Context> class basic_format_args {
return -1;
}
- int max_size() const {
+ auto max_size() const -> int {
unsigned long long max_packed = detail::max_packed_args;
return static_cast<int>(is_packed() ? max_packed
: desc_ & ~detail::is_unpacked_bit);
@@ -1810,10 +1849,9 @@ template <typename Context> class basic_format_args {
};
/** An alias to ``basic_format_args<format_context>``. */
-// Separate types would result in shorter symbols but break ABI compatibility
+// A separate type would result in shorter symbols but break ABI compatibility
// between clang and gcc on ARM (#1919).
using format_args = basic_format_args<format_context>;
-using wformat_args = basic_format_args<wformat_context>;
// We cannot use enum classes as bit fields because of a gcc bug
// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61414.
@@ -1845,15 +1883,14 @@ template <typename Char> struct fill_t {
size_ = static_cast<unsigned char>(size);
}
- constexpr size_t size() const { return size_; }
- constexpr const Char* data() const { return data_; }
+ constexpr auto size() const -> size_t { return size_; }
+ constexpr auto data() const -> const Char* { return data_; }
- FMT_CONSTEXPR Char& operator[](size_t index) { return data_[index]; }
- FMT_CONSTEXPR const Char& operator[](size_t index) const {
+ FMT_CONSTEXPR auto operator[](size_t index) -> Char& { return data_[index]; }
+ FMT_CONSTEXPR auto operator[](size_t index) const -> const Char& {
return data_[index];
}
};
-
FMT_END_DETAIL_NAMESPACE
// Format specifiers for built-in and string types.
@@ -1892,7 +1929,7 @@ template <typename Char> struct arg_ref {
FMT_CONSTEXPR explicit arg_ref(basic_string_view<Char> name)
: kind(arg_id_kind::name), val(name) {}
- FMT_CONSTEXPR arg_ref& operator=(int idx) {
+ FMT_CONSTEXPR auto operator=(int idx) -> arg_ref& {
kind = arg_id_kind::index;
val.index = idx;
return *this;
@@ -1921,6 +1958,9 @@ struct auto_id {};
// A format specifier handler that sets fields in basic_format_specs.
template <typename Char> class specs_setter {
+ protected:
+ basic_format_specs<Char>& specs_;
+
public:
explicit FMT_CONSTEXPR specs_setter(basic_format_specs<Char>& specs)
: specs_(specs) {}
@@ -1932,14 +1972,12 @@ template <typename Char> class specs_setter {
FMT_CONSTEXPR void on_fill(basic_string_view<Char> fill) {
specs_.fill = fill;
}
- FMT_CONSTEXPR void on_plus() { specs_.sign = sign::plus; }
- FMT_CONSTEXPR void on_minus() { specs_.sign = sign::minus; }
- FMT_CONSTEXPR void on_space() { specs_.sign = sign::space; }
+ FMT_CONSTEXPR void on_sign(sign_t s) { specs_.sign = s; }
FMT_CONSTEXPR void on_hash() { specs_.alt = true; }
FMT_CONSTEXPR void on_localized() { specs_.localized = true; }
FMT_CONSTEXPR void on_zero() {
- specs_.align = align::numeric;
+ if (specs_.align == align::none) specs_.align = align::numeric;
specs_.fill[0] = Char('0');
}
@@ -1952,9 +1990,6 @@ template <typename Char> class specs_setter {
FMT_CONSTEXPR void on_type(Char type) {
specs_.type = static_cast<char>(type);
}
-
- protected:
- basic_format_specs<Char>& specs_;
};
// Format spec handler that saves references to arguments representing dynamic
@@ -1987,26 +2022,27 @@ class dynamic_specs_handler
}
private:
+ dynamic_format_specs<char_type>& specs_;
+ ParseContext& context_;
+
using arg_ref_type = arg_ref<char_type>;
- FMT_CONSTEXPR arg_ref_type make_arg_ref(int arg_id) {
+ FMT_CONSTEXPR auto make_arg_ref(int arg_id) -> arg_ref_type {
context_.check_arg_id(arg_id);
return arg_ref_type(arg_id);
}
- FMT_CONSTEXPR arg_ref_type make_arg_ref(auto_id) {
+ FMT_CONSTEXPR auto make_arg_ref(auto_id) -> arg_ref_type {
return arg_ref_type(context_.next_arg_id());
}
- FMT_CONSTEXPR arg_ref_type make_arg_ref(basic_string_view<char_type> arg_id) {
+ FMT_CONSTEXPR auto make_arg_ref(basic_string_view<char_type> arg_id)
+ -> arg_ref_type {
context_.check_arg_id(arg_id);
basic_string_view<char_type> format_str(
context_.begin(), to_unsigned(context_.end() - context_.begin()));
return arg_ref_type(arg_id);
}
-
- dynamic_format_specs<char_type>& specs_;
- ParseContext& context_;
};
template <typename Char> constexpr bool is_ascii_letter(Char c) {
@@ -2015,16 +2051,17 @@ template <typename Char> constexpr bool is_ascii_letter(Char c) {
// Converts a character to ASCII. Returns a number > 127 on conversion failure.
template <typename Char, FMT_ENABLE_IF(std::is_integral<Char>::value)>
-constexpr Char to_ascii(Char value) {
+constexpr auto to_ascii(Char value) -> Char {
return value;
}
template <typename Char, FMT_ENABLE_IF(std::is_enum<Char>::value)>
-constexpr typename std::underlying_type<Char>::type to_ascii(Char value) {
+constexpr auto to_ascii(Char value) ->
+ typename std::underlying_type<Char>::type {
return value;
}
template <typename Char>
-FMT_CONSTEXPR int code_point_length(const Char* begin) {
+FMT_CONSTEXPR auto code_point_length(const Char* begin) -> int {
if (const_check(sizeof(Char) != 1)) return 1;
constexpr char lengths[] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 3, 3, 4, 0};
@@ -2036,33 +2073,52 @@ FMT_CONSTEXPR int code_point_length(const Char* begin) {
return len + !len;
}
+// Return the result via the out param to workaround gcc bug 77539.
+template <bool IS_CONSTEXPR, typename T, typename Ptr = const T*>
+FMT_CONSTEXPR auto find(Ptr first, Ptr last, T value, Ptr& out) -> bool {
+ for (out = first; out != last; ++out) {
+ if (*out == value) return true;
+ }
+ return false;
+}
+
+template <>
+inline auto find<false, char>(const char* first, const char* last, char value,
+ const char*& out) -> bool {
+ out = static_cast<const char*>(
+ std::memchr(first, value, to_unsigned(last - first)));
+ return out != nullptr;
+}
+
// Parses the range [begin, end) as an unsigned integer. This function assumes
// that the range is non-empty and the first character is a digit.
-template <typename Char, typename ErrorHandler>
-FMT_CONSTEXPR int parse_nonnegative_int(const Char*& begin, const Char* end,
- ErrorHandler&& eh) {
+template <typename Char>
+FMT_CONSTEXPR auto parse_nonnegative_int(const Char*& begin, const Char* end,
+ int error_value) noexcept -> int {
FMT_ASSERT(begin != end && '0' <= *begin && *begin <= '9', "");
- unsigned value = 0;
- // Convert to unsigned to prevent a warning.
- const unsigned max_int = to_unsigned(INT_MAX);
- unsigned big = max_int / 10;
+ unsigned value = 0, prev = 0;
+ auto p = begin;
do {
- // Check for overflow.
- if (value > big) {
- value = max_int + 1;
- break;
- }
- value = value * 10 + unsigned(*begin - '0');
- ++begin;
- } while (begin != end && '0' <= *begin && *begin <= '9');
- if (value > max_int) eh.on_error("number is too big");
- return static_cast<int>(value);
+ prev = value;
+ value = value * 10 + unsigned(*p - '0');
+ ++p;
+ } while (p != end && '0' <= *p && *p <= '9');
+ auto num_digits = p - begin;
+ begin = p;
+ if (num_digits <= std::numeric_limits<int>::digits10)
+ return static_cast<int>(value);
+ // Check for overflow.
+ const unsigned max = to_unsigned((std::numeric_limits<int>::max)());
+ return num_digits == std::numeric_limits<int>::digits10 + 1 &&
+ prev * 10ull + unsigned(p[-1] - '0') <= max
+ ? static_cast<int>(value)
+ : error_value;
}
// Parses fill and alignment.
template <typename Char, typename Handler>
-FMT_CONSTEXPR const Char* parse_align(const Char* begin, const Char* end,
- Handler&& handler) {
+FMT_CONSTEXPR auto parse_align(const Char* begin, const Char* end,
+ Handler&& handler) -> const Char* {
FMT_ASSERT(begin != end, "");
auto align = align::none;
auto p = begin + code_point_length(begin);
@@ -2105,14 +2161,15 @@ template <typename Char> FMT_CONSTEXPR bool is_name_start(Char c) {
}
template <typename Char, typename IDHandler>
-FMT_CONSTEXPR const Char* do_parse_arg_id(const Char* begin, const Char* end,
- IDHandler&& handler) {
+FMT_CONSTEXPR auto do_parse_arg_id(const Char* begin, const Char* end,
+ IDHandler&& handler) -> const Char* {
FMT_ASSERT(begin != end, "");
Char c = *begin;
if (c >= '0' && c <= '9') {
int index = 0;
if (c != '0')
- index = parse_nonnegative_int(begin, end, handler);
+ index =
+ parse_nonnegative_int(begin, end, (std::numeric_limits<int>::max)());
else
++begin;
if (begin == end || (*begin != '}' && *begin != ':'))
@@ -2134,42 +2191,41 @@ FMT_CONSTEXPR const Char* do_parse_arg_id(const Char* begin, const Char* end,
}
template <typename Char, typename IDHandler>
-FMT_CONSTEXPR_DECL FMT_INLINE const Char* parse_arg_id(const Char* begin,
- const Char* end,
- IDHandler&& handler) {
+FMT_CONSTEXPR FMT_INLINE auto parse_arg_id(const Char* begin, const Char* end,
+ IDHandler&& handler) -> const Char* {
Char c = *begin;
if (c != '}' && c != ':') return do_parse_arg_id(begin, end, handler);
handler();
return begin;
}
-// Adapts SpecHandler to IDHandler API for dynamic width.
-template <typename SpecHandler, typename Char> struct width_adapter {
- explicit FMT_CONSTEXPR width_adapter(SpecHandler& h) : handler(h) {}
-
- FMT_CONSTEXPR void operator()() { handler.on_dynamic_width(auto_id()); }
- FMT_CONSTEXPR void operator()(int id) { handler.on_dynamic_width(id); }
- FMT_CONSTEXPR void operator()(basic_string_view<Char> id) {
- handler.on_dynamic_width(id);
- }
-
- FMT_CONSTEXPR void on_error(const char* message) {
- handler.on_error(message);
- }
-
- SpecHandler& handler;
-};
-
template <typename Char, typename Handler>
-FMT_CONSTEXPR const Char* parse_width(const Char* begin, const Char* end,
- Handler&& handler) {
+FMT_CONSTEXPR auto parse_width(const Char* begin, const Char* end,
+ Handler&& handler) -> const Char* {
+ using detail::auto_id;
+ struct width_adapter {
+ Handler& handler;
+
+ FMT_CONSTEXPR void operator()() { handler.on_dynamic_width(auto_id()); }
+ FMT_CONSTEXPR void operator()(int id) { handler.on_dynamic_width(id); }
+ FMT_CONSTEXPR void operator()(basic_string_view<Char> id) {
+ handler.on_dynamic_width(id);
+ }
+ FMT_CONSTEXPR void on_error(const char* message) {
+ if (message) handler.on_error(message);
+ }
+ };
+
FMT_ASSERT(begin != end, "");
if ('0' <= *begin && *begin <= '9') {
- handler.on_width(parse_nonnegative_int(begin, end, handler));
+ int width = parse_nonnegative_int(begin, end, -1);
+ if (width != -1)
+ handler.on_width(width);
+ else
+ handler.on_error("number is too big");
} else if (*begin == '{') {
++begin;
- if (begin != end)
- begin = parse_arg_id(begin, end, width_adapter<Handler, Char>(handler));
+ if (begin != end) begin = parse_arg_id(begin, end, width_adapter{handler});
if (begin == end || *begin != '}')
return handler.on_error("invalid format string"), begin;
++begin;
@@ -2177,36 +2233,35 @@ FMT_CONSTEXPR const Char* parse_width(const Char* begin, const Char* end,
return begin;
}
-// Adapts SpecHandler to IDHandler API for dynamic precision.
-template <typename SpecHandler, typename Char> struct precision_adapter {
- explicit FMT_CONSTEXPR precision_adapter(SpecHandler& h) : handler(h) {}
-
- FMT_CONSTEXPR void operator()() { handler.on_dynamic_precision(auto_id()); }
- FMT_CONSTEXPR void operator()(int id) { handler.on_dynamic_precision(id); }
- FMT_CONSTEXPR void operator()(basic_string_view<Char> id) {
- handler.on_dynamic_precision(id);
- }
-
- FMT_CONSTEXPR void on_error(const char* message) {
- handler.on_error(message);
- }
-
- SpecHandler& handler;
-};
-
template <typename Char, typename Handler>
-FMT_CONSTEXPR const Char* parse_precision(const Char* begin, const Char* end,
- Handler&& handler) {
+FMT_CONSTEXPR auto parse_precision(const Char* begin, const Char* end,
+ Handler&& handler) -> const Char* {
+ using detail::auto_id;
+ struct precision_adapter {
+ Handler& handler;
+
+ FMT_CONSTEXPR void operator()() { handler.on_dynamic_precision(auto_id()); }
+ FMT_CONSTEXPR void operator()(int id) { handler.on_dynamic_precision(id); }
+ FMT_CONSTEXPR void operator()(basic_string_view<Char> id) {
+ handler.on_dynamic_precision(id);
+ }
+ FMT_CONSTEXPR void on_error(const char* message) {
+ if (message) handler.on_error(message);
+ }
+ };
+
++begin;
auto c = begin != end ? *begin : Char();
if ('0' <= c && c <= '9') {
- handler.on_precision(parse_nonnegative_int(begin, end, handler));
+ auto precision = parse_nonnegative_int(begin, end, -1);
+ if (precision != -1)
+ handler.on_precision(precision);
+ else
+ handler.on_error("number is too big");
} else if (c == '{') {
++begin;
- if (begin != end) {
- begin =
- parse_arg_id(begin, end, precision_adapter<Handler, Char>(handler));
- }
+ if (begin != end)
+ begin = parse_arg_id(begin, end, precision_adapter{handler});
if (begin == end || *begin++ != '}')
return handler.on_error("invalid format string"), begin;
} else {
@@ -2219,8 +2274,10 @@ FMT_CONSTEXPR const Char* parse_precision(const Char* begin, const Char* end,
// Parses standard format specifiers and sends notifications about parsed
// components to handler.
template <typename Char, typename SpecHandler>
-FMT_CONSTEXPR_DECL FMT_INLINE const Char* parse_format_specs(
- const Char* begin, const Char* end, SpecHandler&& handler) {
+FMT_CONSTEXPR FMT_INLINE auto parse_format_specs(const Char* begin,
+ const Char* end,
+ SpecHandler&& handler)
+ -> const Char* {
if (begin + 1 < end && begin[1] == '}' && is_ascii_letter(*begin) &&
*begin != 'L') {
handler.on_type(*begin++);
@@ -2235,15 +2292,15 @@ FMT_CONSTEXPR_DECL FMT_INLINE const Char* parse_format_specs(
// Parse sign.
switch (to_ascii(*begin)) {
case '+':
- handler.on_plus();
+ handler.on_sign(sign::plus);
++begin;
break;
case '-':
- handler.on_minus();
+ handler.on_sign(sign::minus);
++begin;
break;
case ' ':
- handler.on_space();
+ handler.on_sign(sign::space);
++begin;
break;
default:
@@ -2281,41 +2338,23 @@ FMT_CONSTEXPR_DECL FMT_INLINE const Char* parse_format_specs(
return begin;
}
-// Return the result via the out param to workaround gcc bug 77539.
-template <bool IS_CONSTEXPR, typename T, typename Ptr = const T*>
-FMT_CONSTEXPR bool find(Ptr first, Ptr last, T value, Ptr& out) {
- for (out = first; out != last; ++out) {
- if (*out == value) return true;
- }
- return false;
-}
-
-template <>
-inline bool find<false, char>(const char* first, const char* last, char value,
- const char*& out) {
- out = static_cast<const char*>(
- std::memchr(first, value, to_unsigned(last - first)));
- return out != nullptr;
-}
-
-template <typename Handler, typename Char> struct id_adapter {
- Handler& handler;
- int arg_id;
-
- FMT_CONSTEXPR void operator()() { arg_id = handler.on_arg_id(); }
- FMT_CONSTEXPR void operator()(int id) { arg_id = handler.on_arg_id(id); }
- FMT_CONSTEXPR void operator()(basic_string_view<Char> id) {
- arg_id = handler.on_arg_id(id);
- }
- FMT_CONSTEXPR void on_error(const char* message) {
- handler.on_error(message);
- }
-};
-
template <typename Char, typename Handler>
-FMT_CONSTEXPR const Char* parse_replacement_field(const Char* begin,
- const Char* end,
- Handler&& handler) {
+FMT_CONSTEXPR auto parse_replacement_field(const Char* begin, const Char* end,
+ Handler&& handler) -> const Char* {
+ struct id_adapter {
+ Handler& handler;
+ int arg_id;
+
+ FMT_CONSTEXPR void operator()() { arg_id = handler.on_arg_id(); }
+ FMT_CONSTEXPR void operator()(int id) { arg_id = handler.on_arg_id(id); }
+ FMT_CONSTEXPR void operator()(basic_string_view<Char> id) {
+ arg_id = handler.on_arg_id(id);
+ }
+ FMT_CONSTEXPR void on_error(const char* message) {
+ if (message) handler.on_error(message);
+ }
+ };
+
++begin;
if (begin == end) return handler.on_error("invalid format string"), end;
if (*begin == '}') {
@@ -2323,7 +2362,7 @@ FMT_CONSTEXPR const Char* parse_replacement_field(const Char* begin,
} else if (*begin == '{') {
handler.on_text(begin, begin + 1);
} else {
- auto adapter = id_adapter<Handler, Char>{handler, 0};
+ auto adapter = id_adapter{handler, 0};
begin = parse_arg_id(begin, end, adapter);
Char c = begin != end ? *begin : Char();
if (c == '}') {
@@ -2340,7 +2379,7 @@ FMT_CONSTEXPR const Char* parse_replacement_field(const Char* begin,
}
template <bool IS_CONSTEXPR, typename Char, typename Handler>
-FMT_CONSTEXPR_DECL FMT_INLINE void parse_format_string(
+FMT_CONSTEXPR FMT_INLINE void parse_format_string(
basic_string_view<Char> format_str, Handler&& handler) {
// this is most likely a name-lookup defect in msvc's modules implementation
using detail::find;
@@ -2370,7 +2409,7 @@ FMT_CONSTEXPR_DECL FMT_INLINE void parse_format_string(
if (pbegin == pend) return;
for (;;) {
const Char* p = nullptr;
- if (!find<IS_CONSTEXPR>(pbegin, pend, '}', p))
+ if (!find<IS_CONSTEXPR>(pbegin, pend, Char('}'), p))
return handler_.on_text(pbegin, pend);
++p;
if (p == pend || *p != '}')
@@ -2385,7 +2424,7 @@ FMT_CONSTEXPR_DECL FMT_INLINE void parse_format_string(
// Doing two passes with memchr (one for '{' and another for '}') is up to
// 2.5x faster than the naive one-pass implementation on big format strings.
const Char* p = begin;
- if (*begin != '{' && !find<IS_CONSTEXPR>(begin + 1, end, '{', p))
+ if (*begin != '{' && !find<IS_CONSTEXPR>(begin + 1, end, Char('{'), p))
return write(begin, end);
write(begin, p);
begin = parse_replacement_field(p, end, handler);
@@ -2393,8 +2432,8 @@ FMT_CONSTEXPR_DECL FMT_INLINE void parse_format_string(
}
template <typename T, typename ParseContext>
-FMT_CONSTEXPR const typename ParseContext::char_type* parse_format_specs(
- ParseContext& ctx) {
+FMT_CONSTEXPR auto parse_format_specs(ParseContext& ctx)
+ -> decltype(ctx.begin()) {
using char_type = typename ParseContext::char_type;
using context = buffer_context<char_type>;
using mapped_type = conditional_t<
@@ -2419,11 +2458,11 @@ class compile_parse_context
public:
explicit FMT_CONSTEXPR compile_parse_context(
- basic_string_view<Char> format_str, int num_args = INT_MAX,
- ErrorHandler eh = {})
+ basic_string_view<Char> format_str,
+ int num_args = (std::numeric_limits<int>::max)(), ErrorHandler eh = {})
: base(format_str, eh), num_args_(num_args) {}
- FMT_CONSTEXPR int next_arg_id() {
+ FMT_CONSTEXPR auto next_arg_id() -> int {
int id = base::next_arg_id();
if (id >= num_args_) this->on_error("argument not found");
return id;
@@ -2436,32 +2475,212 @@ class compile_parse_context
using base::check_arg_id;
};
+template <typename ErrorHandler>
+FMT_CONSTEXPR void check_int_type_spec(char spec, ErrorHandler&& eh) {
+ switch (spec) {
+ case 0:
+ case 'd':
+ case 'x':
+ case 'X':
+ case 'b':
+ case 'B':
+ case 'o':
+ case 'c':
+ break;
+ default:
+ eh.on_error("invalid type specifier");
+ break;
+ }
+}
+
+// Checks char specs and returns true if the type spec is char (and not int).
+template <typename Char, typename ErrorHandler = error_handler>
+FMT_CONSTEXPR auto check_char_specs(const basic_format_specs<Char>& specs,
+ ErrorHandler&& eh = {}) -> bool {
+ if (specs.type && specs.type != 'c') {
+ check_int_type_spec(specs.type, eh);
+ return false;
+ }
+ if (specs.align == align::numeric || specs.sign != sign::none || specs.alt)
+ eh.on_error("invalid format specifier for char");
+ return true;
+}
+
+// A floating-point presentation format.
+enum class float_format : unsigned char {
+ general, // General: exponent notation or fixed point based on magnitude.
+ exp, // Exponent notation with the default precision of 6, e.g. 1.2e-3.
+ fixed, // Fixed point with the default precision of 6, e.g. 0.0012.
+ hex
+};
+
+struct float_specs {
+ int precision;
+ float_format format : 8;
+ sign_t sign : 8;
+ bool upper : 1;
+ bool locale : 1;
+ bool binary32 : 1;
+ bool use_grisu : 1;
+ bool showpoint : 1;
+};
+
+template <typename ErrorHandler = error_handler, typename Char>
+FMT_CONSTEXPR auto parse_float_type_spec(const basic_format_specs<Char>& specs,
+ ErrorHandler&& eh = {})
+ -> float_specs {
+ auto result = float_specs();
+ result.showpoint = specs.alt;
+ result.locale = specs.localized;
+ switch (specs.type) {
+ case 0:
+ result.format = float_format::general;
+ break;
+ case 'G':
+ result.upper = true;
+ FMT_FALLTHROUGH;
+ case 'g':
+ result.format = float_format::general;
+ break;
+ case 'E':
+ result.upper = true;
+ FMT_FALLTHROUGH;
+ case 'e':
+ result.format = float_format::exp;
+ result.showpoint |= specs.precision != 0;
+ break;
+ case 'F':
+ result.upper = true;
+ FMT_FALLTHROUGH;
+ case 'f':
+ result.format = float_format::fixed;
+ result.showpoint |= specs.precision != 0;
+ break;
+ case 'A':
+ result.upper = true;
+ FMT_FALLTHROUGH;
+ case 'a':
+ result.format = float_format::hex;
+ break;
+ default:
+ eh.on_error("invalid type specifier");
+ break;
+ }
+ return result;
+}
+
+template <typename Char, typename ErrorHandler = error_handler>
+FMT_CONSTEXPR auto check_cstring_type_spec(Char spec, ErrorHandler&& eh = {})
+ -> bool {
+ if (spec == 0 || spec == 's') return true;
+ if (spec != 'p') eh.on_error("invalid type specifier");
+ return false;
+}
+
+template <typename Char, typename ErrorHandler = error_handler>
+FMT_CONSTEXPR void check_string_type_spec(Char spec, ErrorHandler&& eh = {}) {
+ if (spec != 0 && spec != 's') eh.on_error("invalid type specifier");
+}
+
+template <typename Char, typename ErrorHandler>
+FMT_CONSTEXPR void check_pointer_type_spec(Char spec, ErrorHandler&& eh) {
+ if (spec != 0 && spec != 'p') eh.on_error("invalid type specifier");
+}
+
+// A parse_format_specs handler that checks if specifiers are consistent with
+// the argument type.
+template <typename Handler> class specs_checker : public Handler {
+ private:
+ detail::type arg_type_;
+
+ FMT_CONSTEXPR void require_numeric_argument() {
+ if (!is_arithmetic_type(arg_type_))
+ this->on_error("format specifier requires numeric argument");
+ }
+
+ public:
+ FMT_CONSTEXPR specs_checker(const Handler& handler, detail::type arg_type)
+ : Handler(handler), arg_type_(arg_type) {}
+
+ FMT_CONSTEXPR void on_align(align_t align) {
+ if (align == align::numeric) require_numeric_argument();
+ Handler::on_align(align);
+ }
+
+ FMT_CONSTEXPR void on_sign(sign_t s) {
+ require_numeric_argument();
+ if (is_integral_type(arg_type_) && arg_type_ != type::int_type &&
+ arg_type_ != type::long_long_type && arg_type_ != type::char_type) {
+ this->on_error("format specifier requires signed argument");
+ }
+ Handler::on_sign(s);
+ }
+
+ FMT_CONSTEXPR void on_hash() {
+ require_numeric_argument();
+ Handler::on_hash();
+ }
+
+ FMT_CONSTEXPR void on_localized() {
+ require_numeric_argument();
+ Handler::on_localized();
+ }
+
+ FMT_CONSTEXPR void on_zero() {
+ require_numeric_argument();
+ Handler::on_zero();
+ }
+
+ FMT_CONSTEXPR void end_precision() {
+ if (is_integral_type(arg_type_) || arg_type_ == type::pointer_type)
+ this->on_error("precision not allowed for this argument type");
+ }
+};
+
constexpr int invalid_arg_index = -1;
#if FMT_USE_NONTYPE_TEMPLATE_PARAMETERS
template <int N, typename T, typename... Args, typename Char>
-constexpr int get_arg_index_by_name(basic_string_view<Char> name) {
+constexpr auto get_arg_index_by_name(basic_string_view<Char> name) -> int {
if constexpr (detail::is_statically_named_arg<T>()) {
if (name == T::name) return N;
}
- if constexpr (sizeof...(Args) > 0)
+ if constexpr (sizeof...(Args) > 0) {
return get_arg_index_by_name<N + 1, Args...>(name);
- return invalid_arg_index;
+ } else {
+ (void)name; // Workaround an MSVC bug about "unused" parameter.
+ return invalid_arg_index;
+ }
}
#endif
template <typename... Args, typename Char>
-FMT_CONSTEXPR int get_arg_index_by_name(basic_string_view<Char> name) {
+FMT_CONSTEXPR auto get_arg_index_by_name(basic_string_view<Char> name) -> int {
#if FMT_USE_NONTYPE_TEMPLATE_PARAMETERS
- if constexpr (sizeof...(Args) > 0)
+ if constexpr (sizeof...(Args) > 0) {
return get_arg_index_by_name<0, Args...>(name);
-#endif
+ } else {
+ (void)name;
+ return invalid_arg_index;
+ }
+#else
(void)name;
return invalid_arg_index;
+#endif
}
template <typename Char, typename ErrorHandler, typename... Args>
class format_string_checker {
+ private:
+ using parse_context_type = compile_parse_context<Char, ErrorHandler>;
+ enum { num_args = sizeof...(Args) };
+
+ // Format specifier parsing function.
+ using parse_func = const Char* (*)(parse_context_type&);
+
+ parse_context_type context_;
+ parse_func parse_funcs_[num_args > 0 ? num_args : 1];
+
public:
explicit FMT_CONSTEXPR format_string_checker(
basic_string_view<Char> format_str, ErrorHandler eh)
@@ -2470,9 +2689,11 @@ class format_string_checker {
FMT_CONSTEXPR void on_text(const Char*, const Char*) {}
- FMT_CONSTEXPR int on_arg_id() { return context_.next_arg_id(); }
- FMT_CONSTEXPR int on_arg_id(int id) { return context_.check_arg_id(id), id; }
- FMT_CONSTEXPR int on_arg_id(basic_string_view<Char> id) {
+ FMT_CONSTEXPR auto on_arg_id() -> int { return context_.next_arg_id(); }
+ FMT_CONSTEXPR auto on_arg_id(int id) -> int {
+ return context_.check_arg_id(id), id;
+ }
+ FMT_CONSTEXPR auto on_arg_id(basic_string_view<Char> id) -> int {
#if FMT_USE_NONTYPE_TEMPLATE_PARAMETERS
auto index = get_arg_index_by_name<Args...>(id);
if (index == invalid_arg_index) on_error("named argument is not found");
@@ -2486,9 +2707,9 @@ class format_string_checker {
FMT_CONSTEXPR void on_replacement_field(int, const Char*) {}
- FMT_CONSTEXPR const Char* on_format_specs(int id, const Char* begin,
- const Char*) {
- advance_to(context_, begin);
+ FMT_CONSTEXPR auto on_format_specs(int id, const Char* begin, const Char*)
+ -> const Char* {
+ context_.advance_to(context_.begin() + (begin - &*context_.begin()));
// id >= 0 check is a workaround for gcc 10 bug (#2065).
return id >= 0 && id < num_args ? parse_funcs_[id](context_) : begin;
}
@@ -2496,127 +2717,202 @@ class format_string_checker {
FMT_CONSTEXPR void on_error(const char* message) {
context_.on_error(message);
}
-
- private:
- using parse_context_type = compile_parse_context<Char, ErrorHandler>;
- enum { num_args = sizeof...(Args) };
-
- // Format specifier parsing function.
- using parse_func = const Char* (*)(parse_context_type&);
-
- parse_context_type context_;
- parse_func parse_funcs_[num_args > 0 ? num_args : 1];
};
template <typename... Args, typename S,
enable_if_t<(is_compile_string<S>::value), int>>
void check_format_string(S format_str) {
- FMT_CONSTEXPR_DECL auto s = to_string_view(format_str);
+ FMT_CONSTEXPR auto s = to_string_view(format_str);
using checker = format_string_checker<typename S::char_type, error_handler,
remove_cvref_t<Args>...>;
- FMT_CONSTEXPR_DECL bool invalid_format =
+ FMT_CONSTEXPR bool invalid_format =
(parse_format_string<true>(s, checker(s, {})), true);
- (void)invalid_format;
-}
-
-// Converts string literals to basic_string_view.
-template <typename Char, size_t N>
-FMT_CONSTEXPR basic_string_view<Char> compile_string_to_view(
- const Char (&s)[N]) {
- // Remove trailing null character if needed. Won't be present if this is used
- // with raw character array (i.e. not defined as a string).
- return {s,
- N - ((std::char_traits<Char>::to_int_type(s[N - 1]) == 0) ? 1 : 0)};
+ ignore_unused(invalid_format);
}
-// Converts string_view to basic_string_view.
template <typename Char>
-FMT_CONSTEXPR basic_string_view<Char> compile_string_to_view(
- const std_string_view<Char>& s) {
- return {s.data(), s.size()};
-}
-
-#define FMT_STRING_IMPL(s, base) \
- [] { \
- /* Use the hidden visibility as a workaround for a GCC bug (#1973). */ \
- /* Use a macro-like name to avoid shadowing warnings. */ \
- struct FMT_GCC_VISIBILITY_HIDDEN FMT_COMPILE_STRING : base { \
- using char_type = fmt::remove_cvref_t<decltype(s[0])>; \
- FMT_MAYBE_UNUSED FMT_CONSTEXPR \
- operator fmt::basic_string_view<char_type>() const { \
- return fmt::detail::compile_string_to_view<char_type>(s); \
- } \
- }; \
- return FMT_COMPILE_STRING(); \
- }()
+void vformat_to(
+ buffer<Char>& buf, basic_string_view<Char> fmt,
+ basic_format_args<FMT_BUFFER_CONTEXT(type_identity_t<Char>)> args,
+ locale_ref loc = {});
-/**
- \rst
- Constructs a compile-time format string from a string literal *s*.
+FMT_API void vprint_mojibake(std::FILE*, string_view, format_args);
+#ifndef _WIN32
+inline void vprint_mojibake(std::FILE*, string_view, format_args) {}
+#endif
+FMT_END_DETAIL_NAMESPACE
- **Example**::
+// A formatter specialization for the core types corresponding to detail::type
+// constants.
+template <typename T, typename Char>
+struct formatter<T, Char,
+ enable_if_t<detail::type_constant<T, Char>::value !=
+ detail::type::custom_type>> {
+ private:
+ detail::dynamic_format_specs<Char> specs_;
- // A compile-time error because 'd' is an invalid specifier for strings.
- std::string s = fmt::format(FMT_STRING("{:d}"), "foo");
- \endrst
- */
-#define FMT_STRING(s) FMT_STRING_IMPL(s, fmt::compile_string)
+ public:
+ // Parses format specifiers stopping either at the end of the range or at the
+ // terminating '}'.
+ template <typename ParseContext>
+ FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
+ auto begin = ctx.begin(), end = ctx.end();
+ if (begin == end) return begin;
+ using handler_type = detail::dynamic_specs_handler<ParseContext>;
+ auto type = detail::type_constant<T, Char>::value;
+ auto checker =
+ detail::specs_checker<handler_type>(handler_type(specs_, ctx), type);
+ auto it = detail::parse_format_specs(begin, end, checker);
+ auto eh = ctx.error_handler();
+ switch (type) {
+ case detail::type::none_type:
+ FMT_ASSERT(false, "invalid argument type");
+ break;
+ case detail::type::bool_type:
+ if (!specs_.type || specs_.type == 's') break;
+ FMT_FALLTHROUGH;
+ 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::int128_type:
+ case detail::type::uint128_type:
+ detail::check_int_type_spec(specs_.type, eh);
+ break;
+ case detail::type::char_type:
+ detail::check_char_specs(specs_, eh);
+ break;
+ case detail::type::float_type:
+ if (detail::const_check(FMT_USE_FLOAT))
+ detail::parse_float_type_spec(specs_, eh);
+ else
+ FMT_ASSERT(false, "float support disabled");
+ break;
+ case detail::type::double_type:
+ if (detail::const_check(FMT_USE_DOUBLE))
+ detail::parse_float_type_spec(specs_, eh);
+ else
+ FMT_ASSERT(false, "double support disabled");
+ break;
+ case detail::type::long_double_type:
+ if (detail::const_check(FMT_USE_LONG_DOUBLE))
+ detail::parse_float_type_spec(specs_, eh);
+ else
+ FMT_ASSERT(false, "long double support disabled");
+ break;
+ case detail::type::cstring_type:
+ detail::check_cstring_type_spec(specs_.type, eh);
+ break;
+ case detail::type::string_type:
+ detail::check_string_type_spec(specs_.type, eh);
+ break;
+ case detail::type::pointer_type:
+ detail::check_pointer_type_spec(specs_.type, eh);
+ break;
+ case detail::type::custom_type:
+ // Custom format specifiers are checked in parse functions of
+ // formatter specializations.
+ break;
+ }
+ return it;
+ }
-template <typename Char, FMT_ENABLE_IF(!std::is_same<Char, char>::value)>
-std::basic_string<Char> vformat(
- basic_string_view<Char> format_str,
- basic_format_args<buffer_context<type_identity_t<Char>>> args);
+ template <typename FormatContext>
+ FMT_CONSTEXPR auto format(const T& val, FormatContext& ctx) const
+ -> decltype(ctx.out());
+};
-FMT_API std::string vformat(string_view format_str, format_args args);
+template <typename Char> struct basic_runtime { basic_string_view<Char> str; };
-template <typename Char>
-void vformat_to(
- buffer<Char>& buf, basic_string_view<Char> format_str,
- basic_format_args<FMT_BUFFER_CONTEXT(type_identity_t<Char>)> args,
- detail::locale_ref loc = {});
+template <typename Char, typename... Args> class basic_format_string {
+ private:
+ basic_string_view<Char> str_;
-template <typename Char, typename Args,
- FMT_ENABLE_IF(!std::is_same<Char, char>::value)>
-inline void vprint_mojibake(std::FILE*, basic_string_view<Char>, const Args&) {}
+ public:
+ template <typename S,
+ FMT_ENABLE_IF(
+ std::is_convertible<const S&, basic_string_view<Char>>::value)>
+ FMT_CONSTEVAL basic_format_string(const S& s) : str_(s) {
+ static_assert(
+ detail::count<
+ (std::is_base_of<detail::view, remove_reference_t<Args>>::value &&
+ std::is_reference<Args>::value)...>() == 0,
+ "passing views as lvalues is disallowed");
+#ifdef FMT_HAS_CONSTEVAL
+ if constexpr (detail::count_named_args<Args...>() == 0) {
+ using checker = detail::format_string_checker<Char, detail::error_handler,
+ remove_cvref_t<Args>...>;
+ detail::parse_format_string<true>(str_, checker(s, {}));
+ }
+#else
+ detail::check_format_string<Args...>(s);
+#endif
+ }
+ basic_format_string(basic_runtime<Char> r) : str_(r.str) {}
-FMT_API void vprint_mojibake(std::FILE*, string_view, format_args);
-#ifndef _WIN32
-inline void vprint_mojibake(std::FILE*, string_view, format_args) {}
+ FMT_INLINE operator basic_string_view<Char>() const { return str_; }
+};
+
+#if FMT_GCC_VERSION && FMT_GCC_VERSION < 409
+// Workaround broken conversion on older gcc.
+template <typename... Args> using format_string = string_view;
+template <typename S> auto runtime(const S& s) -> basic_string_view<char_t<S>> {
+ return s;
+}
+#else
+template <typename... Args>
+using format_string = basic_format_string<char, type_identity_t<Args>...>;
+// Creates a runtime format string.
+template <typename S> auto runtime(const S& s) -> basic_runtime<char_t<S>> {
+ return {{s}};
+}
#endif
-FMT_END_DETAIL_NAMESPACE
+FMT_API auto vformat(string_view fmt, format_args args) -> std::string;
+
+/**
+ \rst
+ Formats ``args`` according to specifications in ``fmt`` and returns the result
+ as a string.
+
+ **Example**::
+
+ #include <fmt/core.h>
+ std::string message = fmt::format("The answer is {}", 42);
+ \endrst
+*/
+template <typename... T>
+FMT_INLINE auto format(format_string<T...> fmt, T&&... args) -> std::string {
+ return vformat(fmt, fmt::make_format_args(args...));
+}
/** Formats a string and writes the output to ``out``. */
-// GCC 8 and earlier cannot handle std::back_insert_iterator<Container> with
-// vformat_to<ArgFormatter>(...) overload, so SFINAE on iterator type instead.
-template <typename OutputIt, typename S, typename Char = char_t<S>,
- bool enable = detail::is_output_iterator<OutputIt, Char>::value>
-auto vformat_to(OutputIt out, const S& format_str,
- basic_format_args<buffer_context<type_identity_t<Char>>> args)
- -> typename std::enable_if<enable, OutputIt>::type {
- decltype(detail::get_buffer<Char>(out)) buf(detail::get_buffer_init(out));
- detail::vformat_to(buf, to_string_view(format_str), args);
+template <typename OutputIt,
+ FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, char>::value)>
+auto vformat_to(OutputIt out, string_view fmt, format_args args) -> OutputIt {
+ using detail::get_buffer;
+ auto&& buf = get_buffer<char>(out);
+ detail::vformat_to(buf, string_view(fmt), args, {});
return detail::get_iterator(buf);
}
/**
\rst
- Formats arguments, writes the result to the output iterator ``out`` and returns
- the iterator past the end of the output range.
+ Formats ``args`` according to specifications in ``fmt``, writes the result to
+ the output iterator ``out`` and returns the iterator past the end of the output
+ range.
**Example**::
- std::vector<char> out;
+ auto out = std::vector<char>();
fmt::format_to(std::back_inserter(out), "{}", 42);
\endrst
*/
-// We cannot use FMT_ENABLE_IF because of a bug in gcc 8.3.
-template <typename OutputIt, typename S, typename... Args,
- bool enable = detail::is_output_iterator<OutputIt, char_t<S>>::value>
-inline auto format_to(OutputIt out, const S& format_str, Args&&... args) ->
- typename std::enable_if<enable, OutputIt>::type {
- const auto& vargs = fmt::make_args_checked<Args...>(format_str, args...);
- return vformat_to(out, to_string_view(format_str), vargs);
+template <typename OutputIt, typename... T,
+ FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, char>::value)>
+FMT_INLINE auto format_to(OutputIt out, format_string<T...> fmt, T&&... args)
+ -> OutputIt {
+ return vformat_to(out, fmt, fmt::make_format_args(args...));
}
template <typename OutputIt> struct format_to_n_result {
@@ -2626,112 +2922,74 @@ template <typename OutputIt> struct format_to_n_result {
size_t size;
};
-template <typename OutputIt, typename Char, typename... Args,
- FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value)>
-inline format_to_n_result<OutputIt> vformat_to_n(
- OutputIt out, size_t n, basic_string_view<Char> format_str,
- basic_format_args<buffer_context<type_identity_t<Char>>> args) {
- detail::iterator_buffer<OutputIt, Char, detail::fixed_buffer_traits> buf(out,
- n);
- detail::vformat_to(buf, format_str, args);
+template <typename OutputIt, typename... T,
+ FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, char>::value)>
+auto vformat_to_n(OutputIt out, size_t n, string_view fmt, format_args args)
+ -> format_to_n_result<OutputIt> {
+ using buffer =
+ detail::iterator_buffer<OutputIt, char, detail::fixed_buffer_traits>;
+ auto buf = buffer(out, n);
+ detail::vformat_to(buf, fmt, args, {});
return {buf.out(), buf.count()};
}
/**
- \rst
- Formats arguments, writes up to ``n`` characters of the result to the output
- iterator ``out`` and returns the total output size and the iterator past the
- end of the output range.
- \endrst
+ \rst
+ Formats ``args`` according to specifications in ``fmt``, writes up to ``n``
+ characters of the result to the output iterator ``out`` and returns the total
+ (not truncated) output size and the iterator past the end of the output range.
+ \endrst
*/
-template <typename OutputIt, typename S, typename... Args,
- bool enable = detail::is_output_iterator<OutputIt, char_t<S>>::value>
-inline auto format_to_n(OutputIt out, size_t n, const S& format_str,
- const Args&... args) ->
- typename std::enable_if<enable, format_to_n_result<OutputIt>>::type {
- const auto& vargs = fmt::make_args_checked<Args...>(format_str, args...);
- return vformat_to_n(out, n, to_string_view(format_str), vargs);
+template <typename OutputIt, typename... T,
+ FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, char>::value)>
+FMT_INLINE auto format_to_n(OutputIt out, size_t n, format_string<T...> fmt,
+ const T&... args) -> format_to_n_result<OutputIt> {
+ return vformat_to_n(out, n, fmt, fmt::make_format_args(args...));
}
-/**
- Returns the number of characters in the output of
- ``format(format_str, args...)``.
- */
-template <typename S, typename... Args, typename Char = char_t<S>>
-inline size_t formatted_size(const S& format_str, Args&&... args) {
- const auto& vargs = fmt::make_args_checked<Args...>(format_str, args...);
- detail::counting_buffer<> buf;
- detail::vformat_to(buf, to_string_view(format_str), vargs);
+/** Returns the number of chars in the output of ``format(fmt, args...)``. */
+template <typename... T>
+FMT_INLINE auto formatted_size(format_string<T...> fmt, T&&... args) -> size_t {
+ auto buf = detail::counting_buffer<>();
+ detail::vformat_to(buf, string_view(fmt), fmt::make_format_args(args...), {});
return buf.count();
}
-template <typename S, typename Char = char_t<S>>
-FMT_INLINE std::basic_string<Char> vformat(
- const S& format_str,
- basic_format_args<buffer_context<type_identity_t<Char>>> args) {
- return detail::vformat(to_string_view(format_str), args);
-}
+FMT_API void vprint(string_view fmt, format_args args);
+FMT_API void vprint(std::FILE* f, string_view fmt, format_args args);
/**
\rst
- Formats arguments and returns the result as a string.
+ Formats ``args`` according to specifications in ``fmt`` and writes the output
+ to ``stdout``.
**Example**::
- #include <fmt/core.h>
- std::string message = fmt::format("The answer is {}", 42);
- \endrst
-*/
-// Pass char_t as a default template parameter instead of using
-// std::basic_string<char_t<S>> to reduce the symbol size.
-template <typename S, typename... Args, typename Char = char_t<S>,
- FMT_ENABLE_IF(!FMT_COMPILE_TIME_CHECKS ||
- !std::is_same<Char, char>::value)>
-FMT_INLINE std::basic_string<Char> format(const S& format_str, Args&&... args) {
- const auto& vargs = fmt::make_args_checked<Args...>(format_str, args...);
- return detail::vformat(to_string_view(format_str), vargs);
-}
-
-FMT_API void vprint(string_view, format_args);
-FMT_API void vprint(std::FILE*, string_view, format_args);
-
-/**
- \rst
- Formats ``args`` according to specifications in ``format_str`` and writes the
- output to the file ``f``. Strings are assumed to be Unicode-encoded unless the
- ``FMT_UNICODE`` macro is set to 0.
-
- **Example**::
-
- fmt::print(stderr, "Don't {}!", "panic");
+ fmt::print("Elapsed time: {0:.2f} seconds", 1.23);
\endrst
*/
-template <typename S, typename... Args, typename Char = char_t<S>>
-inline void print(std::FILE* f, const S& format_str, Args&&... args) {
- const auto& vargs = fmt::make_args_checked<Args...>(format_str, args...);
- return detail::is_unicode<Char>()
- ? vprint(f, to_string_view(format_str), vargs)
- : detail::vprint_mojibake(f, to_string_view(format_str), vargs);
+template <typename... T>
+FMT_INLINE void print(format_string<T...> fmt, T&&... args) {
+ const auto& vargs = fmt::make_format_args(args...);
+ return detail::is_utf8() ? vprint(fmt, vargs)
+ : detail::vprint_mojibake(stdout, fmt, vargs);
}
/**
\rst
- Formats ``args`` according to specifications in ``format_str`` and writes
- the output to ``stdout``. Strings are assumed to be Unicode-encoded unless
- the ``FMT_UNICODE`` macro is set to 0.
+ Formats ``args`` according to specifications in ``fmt`` and writes the
+ output to the file ``f``.
**Example**::
- fmt::print("Elapsed time: {0:.2f} seconds", 1.23);
+ fmt::print(stderr, "Don't {}!", "panic");
\endrst
*/
-template <typename S, typename... Args, typename Char = char_t<S>>
-inline void print(const S& format_str, Args&&... args) {
- const auto& vargs = fmt::make_args_checked<Args...>(format_str, args...);
- return detail::is_unicode<Char>()
- ? vprint(to_string_view(format_str), vargs)
- : detail::vprint_mojibake(stdout, to_string_view(format_str),
- vargs);
+template <typename... T>
+FMT_INLINE void print(std::FILE* f, format_string<T...> fmt, T&&... args) {
+ const auto& vargs = fmt::make_format_args(args...);
+ return detail::is_utf8() ? vprint(f, fmt, vargs)
+ : detail::vprint_mojibake(f, fmt, vargs);
}
FMT_MODULE_EXPORT_END
diff --git a/deps/fmt/include/fmt/format-inl.h b/deps/fmt/include/fmt/format-inl.h
index 02a4e7c3af..94a36d1bc4 100644
--- a/deps/fmt/include/fmt/format-inl.h
+++ b/deps/fmt/include/fmt/format-inl.h
@@ -10,6 +10,7 @@
#include <algorithm>
#include <cctype>
+#include <cerrno> // errno
#include <climits>
#include <cmath>
#include <cstdarg>
@@ -102,23 +103,21 @@ template <typename Locale> Locale locale_ref::get() const {
return locale_ ? *static_cast<const std::locale*>(locale_) : std::locale();
}
-template <typename Char> FMT_FUNC std::string grouping_impl(locale_ref loc) {
- return std::use_facet<std::numpunct<Char>>(loc.get<std::locale>()).grouping();
-}
-template <typename Char> FMT_FUNC Char thousands_sep_impl(locale_ref loc) {
- return std::use_facet<std::numpunct<Char>>(loc.get<std::locale>())
- .thousands_sep();
+template <typename Char>
+FMT_FUNC auto thousands_sep_impl(locale_ref loc) -> thousands_sep_result<Char> {
+ auto& facet = std::use_facet<std::numpunct<Char>>(loc.get<std::locale>());
+ auto grouping = facet.grouping();
+ auto thousands_sep = grouping.empty() ? Char() : facet.thousands_sep();
+ return {std::move(grouping), thousands_sep};
}
template <typename Char> FMT_FUNC Char decimal_point_impl(locale_ref loc) {
return std::use_facet<std::numpunct<Char>>(loc.get<std::locale>())
.decimal_point();
}
#else
-template <typename Char> FMT_FUNC std::string grouping_impl(locale_ref) {
- return "\03";
-}
-template <typename Char> FMT_FUNC Char thousands_sep_impl(locale_ref) {
- return FMT_STATIC_THOUSANDS_SEPARATOR;
+template <typename Char>
+FMT_FUNC auto thousands_sep_impl(locale_ref) -> thousands_sep_result<Char> {
+ return {"\03", FMT_STATIC_THOUSANDS_SEPARATOR};
}
template <typename Char> FMT_FUNC Char decimal_point_impl(locale_ref) {
return '.';
@@ -147,8 +146,7 @@ template <> FMT_FUNC int count_digits<4>(detail::fallback_uintptr n) {
}
#if __cplusplus < 201703L
-template <typename T>
-constexpr const typename basic_data<T>::digit_pair basic_data<T>::digits[];
+template <typename T> constexpr const char basic_data<T>::digits[][2];
template <typename T> constexpr const char basic_data<T>::hex_digits[];
template <typename T> constexpr const char basic_data<T>::signs[];
template <typename T> constexpr const unsigned basic_data<T>::prefixes[];
@@ -565,7 +563,6 @@ class bigint {
(*this)[bigit_index] = static_cast<bigit>(sum);
sum >>= bits<bigit>::value;
}
- --num_result_bigits;
remove_leading_zeros();
exp_ *= 2;
}
@@ -640,8 +637,8 @@ inline uint64_t power_of_10_64(int exp) {
// error: the size of the region (lower, upper) outside of which numbers
// definitely do not round to value (Delta in Grisu3).
template <typename Handler>
-FMT_ALWAYS_INLINE digits::result grisu_gen_digits(fp value, uint64_t error,
- int& exp, Handler& handler) {
+FMT_INLINE digits::result grisu_gen_digits(fp value, uint64_t error, int& exp,
+ Handler& handler) {
const fp one(1ULL << -value.e, value.e);
// The integral part of scaled value (p1 in Grisu) = value / one. It cannot be
// zero because it contains a product of two 64-bit numbers with MSB set (due
@@ -1919,7 +1916,7 @@ bool is_center_integer(typename float_info<T>::carrier_uint two_f, int exponent,
}
// Remove trailing zeros from n and return the number of zeros removed (float)
-FMT_ALWAYS_INLINE int remove_trailing_zeros(uint32_t& n) FMT_NOEXCEPT {
+FMT_INLINE int remove_trailing_zeros(uint32_t& n) FMT_NOEXCEPT {
#ifdef FMT_BUILTIN_CTZ
int t = FMT_BUILTIN_CTZ(n);
#else
@@ -1947,7 +1944,7 @@ FMT_ALWAYS_INLINE int remove_trailing_zeros(uint32_t& n) FMT_NOEXCEPT {
}
// Removes trailing zeros and returns the number of zeros removed (double)
-FMT_ALWAYS_INLINE int remove_trailing_zeros(uint64_t& n) FMT_NOEXCEPT {
+FMT_INLINE int remove_trailing_zeros(uint64_t& n) FMT_NOEXCEPT {
#ifdef FMT_BUILTIN_CTZLL
int t = FMT_BUILTIN_CTZLL(n);
#else
@@ -2033,8 +2030,7 @@ FMT_ALWAYS_INLINE int remove_trailing_zeros(uint64_t& n) FMT_NOEXCEPT {
// The main algorithm for shorter interval case
template <class T>
-FMT_ALWAYS_INLINE decimal_fp<T> shorter_interval_case(int exponent)
- FMT_NOEXCEPT {
+FMT_INLINE decimal_fp<T> shorter_interval_case(int exponent) FMT_NOEXCEPT {
decimal_fp<T> ret_value;
// Compute k and beta
const int minus_k = floor_log10_pow2_minus_log10_4_over_3(exponent);
@@ -2500,19 +2496,6 @@ int snprintf_float(T value, int precision, float_specs specs,
return exp - fraction_size;
}
}
-
-struct stringifier {
- template <typename T> FMT_INLINE std::string operator()(T value) const {
- return to_string(value);
- }
- std::string operator()(basic_format_arg<format_context>::handle h) const {
- memory_buffer buf;
- format_parse_context parse_ctx({});
- format_context format_ctx(buffer_appender<char>(buf), {}, {});
- h.format(parse_ctx, format_ctx);
- return to_string(buf);
- }
-};
} // namespace detail
template <> struct formatter<detail::bigint> {
@@ -2575,14 +2558,11 @@ FMT_FUNC void report_system_error(int error_code,
report_error(format_system_error, error_code, message);
}
-FMT_FUNC std::string detail::vformat(string_view format_str, format_args args) {
- if (format_str.size() == 2 && equal2(format_str.data(), "{}")) {
- auto arg = args.get(0);
- if (!arg) error_handler().on_error("argument not found");
- return visit_format_arg(stringifier(), arg);
- }
- memory_buffer buffer;
- detail::vformat_to(buffer, format_str, args);
+FMT_FUNC std::string vformat(string_view fmt, format_args args) {
+ // Don't optimize the "{}" case to keep the binary size small and because it
+ // can be better optimized in fmt::format anyway.
+ auto buffer = memory_buffer();
+ detail::vformat_to(buffer, fmt, args);
return to_string(buffer);
}
@@ -2594,13 +2574,12 @@ extern "C" __declspec(dllimport) int __stdcall WriteConsoleW( //
} // namespace detail
#endif
-FMT_FUNC void vprint(std::FILE* f, string_view format_str, format_args args) {
- memory_buffer buffer;
- detail::vformat_to(buffer, format_str, args);
+namespace detail {
+FMT_FUNC void print(std::FILE* f, string_view text) {
#ifdef _WIN32
auto fd = _fileno(f);
if (_isatty(fd)) {
- detail::utf8_to_utf16 u16(string_view(buffer.data(), buffer.size()));
+ detail::utf8_to_utf16 u16(string_view(text.data(), text.size()));
auto written = detail::dword();
if (detail::WriteConsoleW(reinterpret_cast<void*>(_get_osfhandle(fd)),
u16.c_str(), static_cast<uint32_t>(u16.size()),
@@ -2611,7 +2590,14 @@ FMT_FUNC void vprint(std::FILE* f, string_view format_str, format_args args) {
// redirected to NUL.
}
#endif
- detail::fwrite_fully(buffer.data(), 1, buffer.size(), f);
+ detail::fwrite_fully(text.data(), 1, text.size(), f);
+}
+} // namespace detail
+
+FMT_FUNC void vprint(std::FILE* f, string_view format_str, format_args args) {
+ memory_buffer buffer;
+ detail::vformat_to(buffer, format_str, args);
+ detail::print(f, {buffer.data(), buffer.size()});
}
#ifdef _WIN32
diff --git a/deps/fmt/include/fmt/format.h b/deps/fmt/include/fmt/format.h
index a6dbd819fd..5398a23a82 100644
--- a/deps/fmt/include/fmt/format.h
+++ b/deps/fmt/include/fmt/format.h
@@ -33,10 +33,8 @@
#ifndef FMT_FORMAT_H_
#define FMT_FORMAT_H_
-#include <cerrno> // errno
-#include <cmath> // std::signbit
-#include <cstdint>
-#include <cwchar>
+#include <cmath> // std::signbit
+#include <cstdint> // uint32_t
#include <limits> // std::numeric_limits
#include <memory> // std::uninitialized_copy
#include <stdexcept> // std::runtime_error
@@ -77,24 +75,6 @@
# define FMT_MSC_DEFAULT
#endif
-#if __cplusplus == 201103L || __cplusplus == 201402L
-# if defined(__INTEL_COMPILER) || defined(__PGI)
-# define FMT_FALLTHROUGH
-# elif defined(__clang__)
-# define FMT_FALLTHROUGH [[clang::fallthrough]]
-# elif FMT_GCC_VERSION >= 700 && \
- (!defined(__EDG_VERSION__) || __EDG_VERSION__ >= 520)
-# define FMT_FALLTHROUGH [[gnu::fallthrough]]
-# else
-# define FMT_FALLTHROUGH
-# endif
-#elif FMT_HAS_CPP17_ATTRIBUTE(fallthrough) || \
- (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L)
-# define FMT_FALLTHROUGH [[fallthrough]]
-#else
-# define FMT_FALLTHROUGH
-#endif
-
#ifndef FMT_THROW
# if FMT_EXCEPTIONS
# if FMT_MSC_VER || FMT_NVCC
@@ -128,6 +108,27 @@ FMT_END_NAMESPACE
# define FMT_CATCH(x) if (false)
#endif
+#ifndef FMT_DEPRECATED
+# if FMT_HAS_CPP14_ATTRIBUTE(deprecated) || FMT_MSC_VER >= 1900
+# define FMT_DEPRECATED [[deprecated]]
+# else
+# if (defined(__GNUC__) && !defined(__LCC__)) || defined(__clang__)
+# define FMT_DEPRECATED __attribute__((deprecated))
+# elif FMT_MSC_VER
+# define FMT_DEPRECATED __declspec(deprecated)
+# else
+# define FMT_DEPRECATED /* deprecated */
+# endif
+# endif
+#endif
+
+// Workaround broken [[deprecated]] in the Intel, PGI and NVCC compilers.
+#if FMT_ICC_VERSION || defined(__PGI) || FMT_NVCC
+# define FMT_DEPRECATED_ALIAS
+#else
+# define FMT_DEPRECATED_ALIAS FMT_DEPRECATED
+#endif
+
#ifndef FMT_USE_USER_DEFINED_LITERALS
// EDG based compilers (Intel, NVIDIA, Elbrus, etc), GCC and MSVC support UDLs.
# if (FMT_HAS_FEATURE(cxx_user_literals) || FMT_GCC_VERSION >= 407 || \
@@ -139,18 +140,6 @@ FMT_END_NAMESPACE
# endif
#endif
-#ifndef FMT_USE_FLOAT
-# define FMT_USE_FLOAT 1
-#endif
-
-#ifndef FMT_USE_DOUBLE
-# define FMT_USE_DOUBLE 1
-#endif
-
-#ifndef FMT_USE_LONG_DOUBLE
-# define FMT_USE_LONG_DOUBLE 1
-#endif
-
// Defining FMT_REDUCE_INT_INSTANTIATIONS to 1, will reduce the number of
// integer formatter template instantiations to just one by only using the
// largest integer type. This results in a reduction in binary size but will
@@ -195,7 +184,7 @@ namespace detail {
# endif
# endif
-inline int clz(uint32_t x) {
+inline auto clz(uint32_t x) -> int {
unsigned long r = 0;
_BitScanReverse(&r, x);
FMT_ASSERT(x != 0, "");
@@ -207,7 +196,7 @@ inline int clz(uint32_t x) {
}
# define FMT_BUILTIN_CLZ(n) detail::clz(n)
-inline int clzll(uint64_t x) {
+inline auto clzll(uint64_t x) -> int {
unsigned long r = 0;
# ifdef _WIN64
_BitScanReverse64(&r, x);
@@ -223,7 +212,7 @@ inline int clzll(uint64_t x) {
}
# define FMT_BUILTIN_CLZLL(n) detail::clzll(n)
-inline int ctz(uint32_t x) {
+inline auto ctz(uint32_t x) -> int {
unsigned long r = 0;
_BitScanForward(&r, x);
FMT_ASSERT(x != 0, "");
@@ -232,7 +221,7 @@ inline int ctz(uint32_t x) {
}
# define FMT_BUILTIN_CTZ(n) detail::ctz(n)
-inline int ctzll(uint64_t x) {
+inline auto ctzll(uint64_t x) -> int {
unsigned long r = 0;
FMT_ASSERT(x != 0, "");
FMT_MSC_WARNING(suppress : 6102) // Suppress a bogus static analysis warning.
@@ -269,14 +258,14 @@ namespace detail {
// undefined behavior (e.g. due to type aliasing).
// Example: uint64_t d = bit_cast<uint64_t>(2.718);
template <typename Dest, typename Source>
-inline Dest bit_cast(const Source& source) {
+inline auto bit_cast(const Source& source) -> Dest {
static_assert(sizeof(Dest) == sizeof(Source), "size mismatch");
Dest dest;
std::memcpy(&dest, &source, sizeof(dest));
return dest;
}
-inline bool is_big_endian() {
+inline auto is_big_endian() -> bool {
const auto u = 1u;
struct bytes {
char data[sizeof(u)];
@@ -299,26 +288,28 @@ struct fallback_uintptr {
};
#ifdef UINTPTR_MAX
using uintptr_t = ::uintptr_t;
-inline uintptr_t to_uintptr(const void* p) { return bit_cast<uintptr_t>(p); }
+inline auto to_uintptr(const void* p) -> uintptr_t {
+ return bit_cast<uintptr_t>(p);
+}
#else
using uintptr_t = fallback_uintptr;
-inline fallback_uintptr to_uintptr(const void* p) {
+inline auto to_uintptr(const void* p) -> fallback_uintptr {
return fallback_uintptr(p);
}
#endif
// Returns the largest possible value for type T. Same as
// std::numeric_limits<T>::max() but shorter and not affected by the max macro.
-template <typename T> constexpr T max_value() {
+template <typename T> constexpr auto max_value() -> T {
return (std::numeric_limits<T>::max)();
}
-template <typename T> constexpr int num_bits() {
+template <typename T> constexpr auto num_bits() -> int {
return std::numeric_limits<T>::digits;
}
// std::numeric_limits<T>::digits may return 0 for 128-bit ints.
-template <> constexpr int num_bits<int128_t>() { return 128; }
-template <> constexpr int num_bits<uint128_t>() { return 128; }
-template <> constexpr int num_bits<fallback_uintptr>() {
+template <> constexpr auto num_bits<int128_t>() -> int { return 128; }
+template <> constexpr auto num_bits<uint128_t>() -> int { return 128; }
+template <> constexpr auto num_bits<fallback_uintptr>() -> int {
return static_cast<int>(sizeof(void*) *
std::numeric_limits<unsigned char>::digits);
}
@@ -336,31 +327,35 @@ using iterator_t = decltype(std::begin(std::declval<T&>()));
template <typename T> using sentinel_t = decltype(std::end(std::declval<T&>()));
// A workaround for std::string not having mutable data() until C++17.
-template <typename Char> inline Char* get_data(std::basic_string<Char>& s) {
+template <typename Char>
+inline auto get_data(std::basic_string<Char>& s) -> Char* {
return &s[0];
}
template <typename Container>
-inline typename Container::value_type* get_data(Container& c) {
+inline auto get_data(Container& c) -> typename Container::value_type* {
return c.data();
}
#if defined(_SECURE_SCL) && _SECURE_SCL
// Make a checked iterator to avoid MSVC warnings.
template <typename T> using checked_ptr = stdext::checked_array_iterator<T*>;
-template <typename T> checked_ptr<T> make_checked(T* p, size_t size) {
+template <typename T> auto make_checked(T* p, size_t size) -> checked_ptr<T> {
return {p, size};
}
#else
template <typename T> using checked_ptr = T*;
-template <typename T> inline T* make_checked(T* p, size_t) { return p; }
+template <typename T> inline auto make_checked(T* p, size_t) -> T* { return p; }
#endif
+// Attempts to reserve space for n extra characters in the output range.
+// Returns a pointer to the reserved range or a reference to it.
template <typename Container, FMT_ENABLE_IF(is_contiguous<Container>::value)>
#if FMT_CLANG_VERSION >= 307 && !FMT_ICC_VERSION
__attribute__((no_sanitize("undefined")))
#endif
-inline checked_ptr<typename Container::value_type>
-reserve(std::back_insert_iterator<Container> it, size_t n) {
+inline auto
+reserve(std::back_insert_iterator<Container> it, size_t n)
+ -> checked_ptr<typename Container::value_type> {
Container& c = get_container(it);
size_t size = c.size();
c.resize(size + n);
@@ -368,13 +363,14 @@ reserve(std::back_insert_iterator<Container> it, size_t n) {
}
template <typename T>
-inline buffer_appender<T> reserve(buffer_appender<T> it, size_t n) {
+inline auto reserve(buffer_appender<T> it, size_t n) -> buffer_appender<T> {
buffer<T>& buf = get_container(it);
buf.try_reserve(buf.size() + n);
return it;
}
-template <typename Iterator> constexpr Iterator& reserve(Iterator& it, size_t) {
+template <typename Iterator>
+constexpr auto reserve(Iterator& it, size_t) -> Iterator& {
return it;
}
@@ -383,10 +379,10 @@ using reserve_iterator =
remove_reference_t<decltype(reserve(std::declval<OutputIt&>(), 0))>;
template <typename T, typename OutputIt>
-constexpr T* to_pointer(OutputIt, size_t) {
+constexpr auto to_pointer(OutputIt, size_t) -> T* {
return nullptr;
}
-template <typename T> T* to_pointer(buffer_appender<T> it, size_t n) {
+template <typename T> auto to_pointer(buffer_appender<T> it, size_t n) -> T* {
buffer<T>& buf = get_container(it);
auto size = buf.size();
if (buf.capacity() < size + n) return nullptr;
@@ -395,26 +391,27 @@ template <typename T> T* to_pointer(buffer_appender<T> it, size_t n) {
}
template <typename Container, FMT_ENABLE_IF(is_contiguous<Container>::value)>
-inline std::back_insert_iterator<Container> base_iterator(
- std::back_insert_iterator<Container>& it,
- checked_ptr<typename Container::value_type>) {
+inline auto base_iterator(std::back_insert_iterator<Container>& it,
+ checked_ptr<typename Container::value_type>)
+ -> std::back_insert_iterator<Container> {
return it;
}
template <typename Iterator>
-constexpr Iterator base_iterator(Iterator, Iterator it) {
+constexpr auto base_iterator(Iterator, Iterator it) -> Iterator {
return it;
}
// <algorithm> is spectacularly slow to compile in C++20 so use a simple fill_n
// instead (#1998).
template <typename OutputIt, typename Size, typename T>
-FMT_CONSTEXPR OutputIt fill_n(OutputIt out, Size count, const T& value) {
+FMT_CONSTEXPR auto fill_n(OutputIt out, Size count, const T& value)
+ -> OutputIt {
for (Size i = 0; i < count; ++i) *out++ = value;
return out;
}
template <typename T, typename Size>
-FMT_CONSTEXPR20 T* fill_n(T* out, Size count, char value) {
+FMT_CONSTEXPR20 auto fill_n(T* out, Size count, char value) -> T* {
if (is_constant_evaluated()) {
return fill_n<T*, Size, T>(out, count, value);
}
@@ -428,43 +425,10 @@ using char8_type = char8_t;
enum char8_type : unsigned char {};
#endif
-template <typename InputIt, typename OutChar>
-using needs_conversion = bool_constant<
- std::is_same<typename std::iterator_traits<InputIt>::value_type,
- char>::value &&
- std::is_same<OutChar, char8_type>::value>;
-
-template <typename OutChar, typename InputIt, typename OutputIt,
- FMT_ENABLE_IF(!needs_conversion<InputIt, OutChar>::value)>
-FMT_CONSTEXPR OutputIt copy_str(InputIt begin, InputIt end, OutputIt it) {
- while (begin != end) *it++ = *begin++;
- return it;
-}
-
-template <typename OutChar, typename InputIt,
- FMT_ENABLE_IF(!needs_conversion<InputIt, OutChar>::value)>
-FMT_CONSTEXPR20 OutChar* copy_str(InputIt begin, InputIt end, OutChar* out) {
- if (is_constant_evaluated()) {
- return copy_str<OutChar, InputIt, OutChar*>(begin, end, out);
- }
- auto size = to_unsigned(end - begin);
- std::uninitialized_copy(begin, end, make_checked(out, size));
- return out + size;
-}
-
-template <typename OutChar, typename InputIt, typename OutputIt,
- FMT_ENABLE_IF(needs_conversion<InputIt, OutChar>::value)>
-OutputIt copy_str(InputIt begin, InputIt end, OutputIt it) {
- while (begin != end) *it++ = static_cast<char8_type>(*begin++);
- return it;
-}
-
-template <typename OutChar, typename InputIt,
- FMT_ENABLE_IF(!needs_conversion<InputIt, OutChar>::value)>
-buffer_appender<OutChar> copy_str(InputIt begin, InputIt end,
- buffer_appender<OutChar> out) {
- get_container(out).append(begin, end);
- return out;
+template <typename OutChar, typename InputIt, typename OutputIt>
+FMT_CONSTEXPR FMT_NOINLINE auto copy_str_noinline(InputIt begin, InputIt end,
+ OutputIt out) -> OutputIt {
+ return copy_str<OutChar>(begin, end, out);
}
// A public domain branchless UTF-8 decoder by Christopher Wellons:
@@ -484,8 +448,8 @@ buffer_appender<OutChar> copy_str(InputIt begin, InputIt end,
* occurs, this pointer will be a guess that depends on the particular
* error, but it will always advance at least one byte.
*/
-FMT_CONSTEXPR inline const char* utf8_decode(const char* s, uint32_t* c,
- int* e) {
+FMT_CONSTEXPR inline auto utf8_decode(const char* s, uint32_t* c, int* e)
+ -> const char* {
constexpr const int masks[] = {0x00, 0x7f, 0x1f, 0x0f, 0x07};
constexpr const uint32_t mins[] = {4194304, 0, 128, 2048, 65536};
constexpr const int shiftc[] = {0, 18, 12, 6, 0};
@@ -541,7 +505,7 @@ FMT_CONSTEXPR void for_each_codepoint(string_view s, F f) {
}
template <typename Char>
-inline size_t compute_width(basic_string_view<Char> s) {
+inline auto compute_width(basic_string_view<Char> s) -> size_t {
return s.size();
}
@@ -552,13 +516,13 @@ FMT_CONSTEXPR inline size_t compute_width(string_view s) {
struct count_code_points {
size_t* count;
FMT_CONSTEXPR void operator()(uint32_t cp, int error) const {
- *count +=
+ *count += detail::to_unsigned(
1 +
(error == 0 && cp >= 0x1100 &&
(cp <= 0x115f || // Hangul Jamo init. consonants
- cp == 0x2329 || // LEFT-POINTING ANGLE BRACKET〈
- cp == 0x232a || // RIGHT-POINTING ANGLE BRACKET 〉
- // CJK ... Yi except Unicode Character “〿”:
+ cp == 0x2329 || // LEFT-POINTING ANGLE BRACKET
+ cp == 0x232a || // RIGHT-POINTING ANGLE BRACKET
+ // CJK ... Yi except IDEOGRAPHIC HALF FILL SPACE:
(cp >= 0x2e80 && cp <= 0xa4cf && cp != 0x303f) ||
(cp >= 0xac00 && cp <= 0xd7a3) || // Hangul Syllables
(cp >= 0xf900 && cp <= 0xfaff) || // CJK Compatibility Ideographs
@@ -571,26 +535,27 @@ FMT_CONSTEXPR inline size_t compute_width(string_view s) {
// Miscellaneous Symbols and Pictographs + Emoticons:
(cp >= 0x1f300 && cp <= 0x1f64f) ||
// Supplemental Symbols and Pictographs:
- (cp >= 0x1f900 && cp <= 0x1f9ff)));
+ (cp >= 0x1f900 && cp <= 0x1f9ff))));
}
};
for_each_codepoint(s, count_code_points{&num_code_points});
return num_code_points;
}
-inline size_t compute_width(basic_string_view<char8_type> s) {
+inline auto compute_width(basic_string_view<char8_type> s) -> size_t {
return compute_width(basic_string_view<char>(
reinterpret_cast<const char*>(s.data()), s.size()));
}
template <typename Char>
-inline size_t code_point_index(basic_string_view<Char> s, size_t n) {
+inline auto code_point_index(basic_string_view<Char> s, size_t n) -> size_t {
size_t size = s.size();
return n < size ? n : size;
}
// Calculates the index of the nth code point in a UTF-8 string.
-inline size_t code_point_index(basic_string_view<char8_type> s, size_t n) {
+inline auto code_point_index(basic_string_view<char8_type> s, size_t n)
+ -> size_t {
const char8_type* data = s.data();
size_t num_code_points = 0;
for (size_t i = 0, size = s.size(); i != size; ++i) {
@@ -621,20 +586,14 @@ void buffer<T>::append(const U* begin, const U* end) {
}
}
-template <typename OutputIt, typename T, typename Traits>
-void iterator_buffer<OutputIt, T, Traits>::flush() {
- auto size = this->size();
- this->clear();
- out_ = copy_str<T>(data_, data_ + this->limit(size), out_);
-}
+template <typename T, typename Enable = void>
+struct is_locale : std::false_type {};
+template <typename T>
+struct is_locale<T, void_t<decltype(T::classic())>> : std::true_type {};
} // namespace detail
FMT_MODULE_EXPORT_BEGIN
-template <> struct is_char<detail::char8_type> : std::true_type {};
-template <> struct is_char<char16_t> : std::true_type {};
-template <> struct is_char<char32_t> : std::true_type {};
-
// The number of characters to store in the basic_memory_buffer object itself
// to avoid dynamic memory allocation.
enum { inline_buffer_size = 500 };
@@ -644,15 +603,7 @@ enum { inline_buffer_size = 500 };
A dynamically growing memory buffer for trivially copyable/constructible types
with the first ``SIZE`` elements stored in the object itself.
- You can use one of the following type aliases for common character types:
-
- +----------------+------------------------------+
- | Type | Definition |
- +================+==============================+
- | memory_buffer | basic_memory_buffer<char> |
- +----------------+------------------------------+
- | wmemory_buffer | basic_memory_buffer<wchar_t> |
- +----------------+------------------------------+
+ You can use the ``memory_buffer`` type alias for ``char`` instead.
**Example**::
@@ -729,7 +680,8 @@ class basic_memory_buffer final : public detail::buffer<T> {
Moves the content of the other ``basic_memory_buffer`` object to this one.
\endrst
*/
- basic_memory_buffer& operator=(basic_memory_buffer&& other) FMT_NOEXCEPT {
+ auto operator=(basic_memory_buffer&& other) FMT_NOEXCEPT
+ -> basic_memory_buffer& {
FMT_ASSERT(this != &other, "");
deallocate();
move(other);
@@ -737,7 +689,7 @@ class basic_memory_buffer final : public detail::buffer<T> {
}
// Returns a copy of the allocator associated with this buffer.
- Allocator get_allocator() const { return alloc_; }
+ auto get_allocator() const -> Allocator { return alloc_; }
/**
Resizes the buffer to contain *count* elements. If T is a POD type new
@@ -782,12 +734,15 @@ void basic_memory_buffer<T, SIZE, Allocator>::grow(size_t size) {
}
using memory_buffer = basic_memory_buffer<char>;
-using wmemory_buffer = basic_memory_buffer<wchar_t>;
template <typename T, size_t SIZE, typename Allocator>
struct is_contiguous<basic_memory_buffer<T, SIZE, Allocator>> : std::true_type {
};
+namespace detail {
+FMT_API void print(std::FILE*, string_view);
+}
+
/** A formatting error such as invalid format string. */
FMT_CLASS_API
class FMT_API format_error : public std::runtime_error {
@@ -802,6 +757,54 @@ class FMT_API format_error : public std::runtime_error {
~format_error() FMT_NOEXCEPT FMT_OVERRIDE FMT_MSC_DEFAULT;
};
+/**
+ \rst
+ Constructs a `~fmt::format_arg_store` object that contains references
+ to arguments and can be implicitly converted to `~fmt::format_args`.
+ If ``fmt`` is a compile-time string then `make_args_checked` checks
+ its validity at compile time.
+ \endrst
+ */
+template <typename... Args, typename S, typename Char = char_t<S>>
+FMT_INLINE auto make_args_checked(const S& fmt,
+ const remove_reference_t<Args>&... args)
+ -> format_arg_store<buffer_context<Char>, remove_reference_t<Args>...> {
+ static_assert(
+ detail::count<(
+ std::is_base_of<detail::view, remove_reference_t<Args>>::value &&
+ std::is_reference<Args>::value)...>() == 0,
+ "passing views as lvalues is disallowed");
+ detail::check_format_string<Args...>(fmt);
+ return {args...};
+}
+
+// compile-time support
+namespace detail_exported {
+#if FMT_USE_NONTYPE_TEMPLATE_PARAMETERS
+template <typename Char, size_t N> struct fixed_string {
+ constexpr fixed_string(const Char (&str)[N]) {
+ detail::copy_str<Char, const Char*, Char*>(static_cast<const Char*>(str),
+ str + N, data);
+ }
+ Char data[N]{};
+};
+#endif
+
+// Converts a compile-time string to basic_string_view.
+template <typename Char, size_t N>
+constexpr auto compile_string_to_view(const Char (&s)[N])
+ -> basic_string_view<Char> {
+ // Remove trailing NUL character if needed. Won't be present if this is used
+ // with a raw character array (i.e. not defined as a string).
+ return {s, N - (std::char_traits<Char>::to_int_type(s[N - 1]) == 0 ? 1 : 0)};
+}
+template <typename Char>
+constexpr auto compile_string_to_view(detail::std_string_view<Char> s)
+ -> basic_string_view<Char> {
+ return {s.data(), s.size()};
+}
+} // namespace detail_exported
+
FMT_BEGIN_DETAIL_NAMESPACE
inline void throw_format_error(const char* message) {
@@ -820,16 +823,16 @@ using is_signed =
// Returns true if value is negative, false otherwise.
// Same as `value < 0` but doesn't produce warnings if T is an unsigned type.
template <typename T, FMT_ENABLE_IF(is_signed<T>::value)>
-FMT_CONSTEXPR bool is_negative(T value) {
+FMT_CONSTEXPR auto is_negative(T value) -> bool {
return value < 0;
}
template <typename T, FMT_ENABLE_IF(!is_signed<T>::value)>
-FMT_CONSTEXPR bool is_negative(T) {
+FMT_CONSTEXPR auto is_negative(T) -> bool {
return false;
}
template <typename T, FMT_ENABLE_IF(std::is_floating_point<T>::value)>
-FMT_CONSTEXPR bool is_supported_floating_point(T) {
+FMT_CONSTEXPR auto is_supported_floating_point(T) -> uint16_t {
return (std::is_same<T, float>::value && FMT_USE_FLOAT) ||
(std::is_same<T, double>::value && FMT_USE_DOUBLE) ||
(std::is_same<T, long double>::value && FMT_USE_LONG_DOUBLE);
@@ -856,8 +859,7 @@ template <typename T = void> struct basic_data {
static const uint64_t log10_2_significand = 0x4d104d427de7fbcc;
// GCC generates slightly better code for pairs than chars.
- using digit_pair = char[2];
- static constexpr const digit_pair digits[] = {
+ FMT_API static constexpr const char digits[100][2] = {
{'0', '0'}, {'0', '1'}, {'0', '2'}, {'0', '3'}, {'0', '4'}, {'0', '5'},
{'0', '6'}, {'0', '7'}, {'0', '8'}, {'0', '9'}, {'1', '0'}, {'1', '1'},
{'1', '2'}, {'1', '3'}, {'1', '4'}, {'1', '5'}, {'1', '6'}, {'1', '7'},
@@ -876,29 +878,25 @@ template <typename T = void> struct basic_data {
{'9', '0'}, {'9', '1'}, {'9', '2'}, {'9', '3'}, {'9', '4'}, {'9', '5'},
{'9', '6'}, {'9', '7'}, {'9', '8'}, {'9', '9'}};
- static constexpr const char hex_digits[] = "0123456789abcdef";
- static constexpr const char signs[] = {0, '-', '+', ' '};
- static constexpr const unsigned prefixes[4] = {0, 0, 0x1000000u | '+',
- 0x1000000u | ' '};
- static constexpr const char left_padding_shifts[] = {31, 31, 0, 1, 0};
- static constexpr const char right_padding_shifts[] = {0, 31, 0, 1, 0};
+ FMT_API static constexpr const char hex_digits[] = "0123456789abcdef";
+ FMT_API static constexpr const char signs[4] = {0, '-', '+', ' '};
+ FMT_API static constexpr const unsigned prefixes[4] = {0, 0, 0x1000000u | '+',
+ 0x1000000u | ' '};
+ FMT_API static constexpr const char left_padding_shifts[5] = {31, 31, 0, 1,
+ 0};
+ FMT_API static constexpr const char right_padding_shifts[5] = {0, 31, 0, 1,
+ 0};
};
+#ifdef FMT_SHARED
+// Required for -flto, -fivisibility=hidden and -shared to work
+extern template struct basic_data<void>;
+#endif
+
// This is a struct rather than an alias to avoid shadowing warnings in gcc.
struct data : basic_data<> {};
-// Maps bsr(n) to ceil(log10(pow(2, bsr(n) + 1) - 1)).
-// This is a function instead of an array to workaround a bug in GCC10 (#1810).
-FMT_INLINE uint16_t bsr2log10(int bsr) {
- static constexpr uint16_t data[] = {
- 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5,
- 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10,
- 10, 11, 11, 11, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 15, 15,
- 15, 16, 16, 16, 16, 17, 17, 17, 18, 18, 18, 19, 19, 19, 19, 20};
- return data[bsr];
-}
-
-template <typename T> FMT_CONSTEXPR int count_digits_fallback(T n) {
+template <typename T> FMT_CONSTEXPR auto count_digits_fallback(T n) -> int {
int count = 1;
for (;;) {
// Integer division is slow so do it for a group of four digits instead
@@ -913,31 +911,36 @@ template <typename T> FMT_CONSTEXPR int count_digits_fallback(T n) {
}
}
#if FMT_USE_INT128
-FMT_CONSTEXPR inline int count_digits(uint128_t n) {
+FMT_CONSTEXPR inline auto count_digits(uint128_t n) -> int {
return count_digits_fallback(n);
}
#endif
// Returns the number of decimal digits in n. Leading zeros are not counted
// except for n == 0 in which case count_digits returns 1.
-FMT_CONSTEXPR20 inline int count_digits(uint64_t n) {
- if (is_constant_evaluated()) {
- return count_digits_fallback(n);
- }
+FMT_CONSTEXPR20 inline auto count_digits(uint64_t n) -> int {
#ifdef FMT_BUILTIN_CLZLL
- // https://github.com/fmtlib/format-benchmark/blob/master/digits10
- auto t = bsr2log10(FMT_BUILTIN_CLZLL(n | 1) ^ 63);
- constexpr const uint64_t zero_or_powers_of_10[] = {
- 0, 0, FMT_POWERS_OF_10(1U), FMT_POWERS_OF_10(1000000000ULL),
- 10000000000000000000ULL};
- return t - (n < zero_or_powers_of_10[t]);
-#else
- return count_digits_fallback(n);
+ if (!is_constant_evaluated()) {
+ // https://github.com/fmtlib/format-benchmark/blob/master/digits10
+ // Maps bsr(n) to ceil(log10(pow(2, bsr(n) + 1) - 1)).
+ constexpr uint16_t bsr2log10[] = {
+ 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5,
+ 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10,
+ 10, 11, 11, 11, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 15, 15,
+ 15, 16, 16, 16, 16, 17, 17, 17, 18, 18, 18, 19, 19, 19, 19, 20};
+ auto t = bsr2log10[FMT_BUILTIN_CLZLL(n | 1) ^ 63];
+ constexpr const uint64_t zero_or_powers_of_10[] = {
+ 0, 0, FMT_POWERS_OF_10(1U), FMT_POWERS_OF_10(1000000000ULL),
+ 10000000000000000000ULL};
+ return t - (n < zero_or_powers_of_10[t]);
+ }
#endif
+ return count_digits_fallback(n);
}
// Counts the number of digits in n. BITS = log2(radix).
-template <int BITS, typename UInt> FMT_CONSTEXPR int count_digits(UInt n) {
+template <int BITS, typename UInt>
+FMT_CONSTEXPR auto count_digits(UInt n) -> int {
#ifdef FMT_BUILTIN_CLZ
if (num_bits<UInt>() == 32)
return (FMT_BUILTIN_CLZ(static_cast<uint32_t>(n) | 1) ^ 31) / BITS + 1;
@@ -949,65 +952,82 @@ template <int BITS, typename UInt> FMT_CONSTEXPR int count_digits(UInt n) {
return num_digits;
}
-template <> int count_digits<4>(detail::fallback_uintptr n);
-
-#if FMT_GCC_VERSION || FMT_CLANG_VERSION
-# define FMT_ALWAYS_INLINE inline __attribute__((always_inline))
-#elif FMT_MSC_VER
-# define FMT_ALWAYS_INLINE __forceinline
-#else
-# define FMT_ALWAYS_INLINE inline
-#endif
+template <> auto count_digits<4>(detail::fallback_uintptr n) -> int;
+
+// It is a separate function rather than a part of count_digits to workaround
+// the lack of static constexpr in constexpr functions.
+FMT_INLINE uint64_t count_digits_inc(int n) {
+ // An optimization by Kendall Willets from https://bit.ly/3uOIQrB.
+ // This increments the upper 32 bits (log10(T) - 1) when >= T is added.
+#define FMT_INC(T) (((sizeof(#T) - 1ull) << 32) - T)
+ static constexpr uint64_t table[] = {
+ FMT_INC(0), FMT_INC(0), FMT_INC(0), // 8
+ FMT_INC(10), FMT_INC(10), FMT_INC(10), // 64
+ FMT_INC(100), FMT_INC(100), FMT_INC(100), // 512
+ FMT_INC(1000), FMT_INC(1000), FMT_INC(1000), // 4096
+ FMT_INC(10000), FMT_INC(10000), FMT_INC(10000), // 32k
+ FMT_INC(100000), FMT_INC(100000), FMT_INC(100000), // 256k
+ FMT_INC(1000000), FMT_INC(1000000), FMT_INC(1000000), // 2048k
+ FMT_INC(10000000), FMT_INC(10000000), FMT_INC(10000000), // 16M
+ FMT_INC(100000000), FMT_INC(100000000), FMT_INC(100000000), // 128M
+ FMT_INC(1000000000), FMT_INC(1000000000), FMT_INC(1000000000), // 1024M
+ FMT_INC(1000000000), FMT_INC(1000000000) // 4B
+ };
+ return table[n];
+}
-#ifdef FMT_BUILTIN_CLZ
// Optional version of count_digits for better performance on 32-bit platforms.
-FMT_CONSTEXPR20 inline int count_digits(uint32_t n) {
- if (is_constant_evaluated()) {
- return count_digits_fallback(n);
+FMT_CONSTEXPR20 inline auto count_digits(uint32_t n) -> int {
+#ifdef FMT_BUILTIN_CLZ
+ if (!is_constant_evaluated()) {
+ auto inc = count_digits_inc(FMT_BUILTIN_CLZ(n | 1) ^ 31);
+ return static_cast<int>((n + inc) >> 32);
}
- auto t = bsr2log10(FMT_BUILTIN_CLZ(n | 1) ^ 31);
- constexpr const uint32_t zero_or_powers_of_10[] = {0, 0,
- FMT_POWERS_OF_10(1U)};
- return t - (n < zero_or_powers_of_10[t]);
-}
#endif
+ return count_digits_fallback(n);
+}
-template <typename Int> constexpr int digits10() FMT_NOEXCEPT {
+template <typename Int> constexpr auto digits10() FMT_NOEXCEPT -> int {
return std::numeric_limits<Int>::digits10;
}
-template <> constexpr int digits10<int128_t>() FMT_NOEXCEPT { return 38; }
-template <> constexpr int digits10<uint128_t>() FMT_NOEXCEPT { return 38; }
-
-// DEPRECATED! grouping will be merged into thousands_sep.
-template <typename Char> FMT_API std::string grouping_impl(locale_ref loc);
-template <typename Char> inline std::string grouping(locale_ref loc) {
- return grouping_impl<char>(loc);
+template <> constexpr auto digits10<int128_t>() FMT_NOEXCEPT -> int {
+ return 38;
}
-template <> inline std::string grouping<wchar_t>(locale_ref loc) {
- return grouping_impl<wchar_t>(loc);
+template <> constexpr auto digits10<uint128_t>() FMT_NOEXCEPT -> int {
+ return 38;
}
-template <typename Char> FMT_API Char thousands_sep_impl(locale_ref loc);
-template <typename Char> inline Char thousands_sep(locale_ref loc) {
- return Char(thousands_sep_impl<char>(loc));
+template <typename Char> struct thousands_sep_result {
+ std::string grouping;
+ Char thousands_sep;
+};
+
+template <typename Char>
+FMT_API auto thousands_sep_impl(locale_ref loc) -> thousands_sep_result<Char>;
+template <typename Char>
+inline auto thousands_sep(locale_ref loc) -> thousands_sep_result<Char> {
+ auto result = thousands_sep_impl<char>(loc);
+ return {result.grouping, Char(result.thousands_sep)};
}
-template <> inline wchar_t thousands_sep(locale_ref loc) {
+template <>
+inline auto thousands_sep(locale_ref loc) -> thousands_sep_result<wchar_t> {
return thousands_sep_impl<wchar_t>(loc);
}
-template <typename Char> FMT_API Char decimal_point_impl(locale_ref loc);
-template <typename Char> inline Char decimal_point(locale_ref loc) {
+template <typename Char>
+FMT_API auto decimal_point_impl(locale_ref loc) -> Char;
+template <typename Char> inline auto decimal_point(locale_ref loc) -> Char {
return Char(decimal_point_impl<char>(loc));
}
-template <> inline wchar_t decimal_point(locale_ref loc) {
+template <> inline auto decimal_point(locale_ref loc) -> wchar_t {
return decimal_point_impl<wchar_t>(loc);
}
// Compares two characters for equality.
-template <typename Char> bool equal2(const Char* lhs, const char* rhs) {
- return lhs[0] == rhs[0] && lhs[1] == rhs[1];
+template <typename Char> auto equal2(const Char* lhs, const char* rhs) -> bool {
+ return lhs[0] == Char(rhs[0]) && lhs[1] == Char(rhs[1]);
}
-inline bool equal2(const char* lhs, const char* rhs) {
+inline auto equal2(const char* lhs, const char* rhs) -> bool {
return memcmp(lhs, rhs, 2) == 0;
}
@@ -1027,9 +1047,8 @@ template <typename Iterator> struct format_decimal_result {
// buffer of specified size. The caller must ensure that the buffer is large
// enough.
template <typename Char, typename UInt>
-FMT_CONSTEXPR20 format_decimal_result<Char*> format_decimal(Char* out,
- UInt value,
- int size) {
+FMT_CONSTEXPR20 auto format_decimal(Char* out, UInt value, int size)
+ -> format_decimal_result<Char*> {
FMT_ASSERT(size >= count_digits(value), "invalid digit count");
out += size;
Char* end = out;
@@ -1060,17 +1079,17 @@ FMT_CONSTEXPR20 format_decimal_result<Char*> format_decimal(Char* out,
template <typename Char, typename UInt, typename Iterator,
FMT_ENABLE_IF(!std::is_pointer<remove_cvref_t<Iterator>>::value)>
-inline format_decimal_result<Iterator> format_decimal(Iterator out, UInt value,
- int size) {
+inline auto format_decimal(Iterator out, UInt value, int size)
+ -> format_decimal_result<Iterator> {
// Buffer is large enough to hold all digits (digits10 + 1).
Char buffer[digits10<UInt>() + 1];
auto end = format_decimal(buffer, value, size).end;
- return {out, detail::copy_str<Char>(buffer, end, out)};
+ return {out, detail::copy_str_noinline<Char>(buffer, end, out)};
}
template <unsigned BASE_BITS, typename Char, typename UInt>
-FMT_CONSTEXPR Char* format_uint(Char* buffer, UInt value, int num_digits,
- bool upper = false) {
+FMT_CONSTEXPR auto format_uint(Char* buffer, UInt value, int num_digits,
+ bool upper = false) -> Char* {
buffer += num_digits;
Char* end = buffer;
do {
@@ -1083,8 +1102,8 @@ FMT_CONSTEXPR Char* format_uint(Char* buffer, UInt value, int num_digits,
}
template <unsigned BASE_BITS, typename Char>
-Char* format_uint(Char* buffer, detail::fallback_uintptr n, int num_digits,
- bool = false) {
+auto format_uint(Char* buffer, detail::fallback_uintptr n, int num_digits,
+ bool = false) -> Char* {
auto char_digits = std::numeric_limits<unsigned char>::digits / 4;
int start = (num_digits + char_digits - 1) / char_digits - 1;
if (int start_digits = num_digits % char_digits) {
@@ -1105,7 +1124,8 @@ Char* format_uint(Char* buffer, detail::fallback_uintptr n, int num_digits,
}
template <unsigned BASE_BITS, typename Char, typename It, typename UInt>
-inline It format_uint(It out, UInt value, int num_digits, bool upper = false) {
+inline auto format_uint(It out, UInt value, int num_digits, bool upper = false)
+ -> It {
if (auto ptr = to_pointer<Char>(out, to_unsigned(num_digits))) {
format_uint<BASE_BITS>(ptr, value, num_digits, upper);
return out;
@@ -1113,24 +1133,22 @@ inline It format_uint(It out, UInt value, int num_digits, bool upper = false) {
// Buffer should be large enough to hold all digits (digits / BASE_BITS + 1).
char buffer[num_bits<UInt>() / BASE_BITS + 1];
format_uint<BASE_BITS>(buffer, value, num_digits, upper);
- return detail::copy_str<Char>(buffer, buffer + num_digits, out);
+ return detail::copy_str_noinline<Char>(buffer, buffer + num_digits, out);
}
// A converter from UTF-8 to UTF-16.
class utf8_to_utf16 {
private:
- wmemory_buffer buffer_;
+ basic_memory_buffer<wchar_t> buffer_;
public:
FMT_API explicit utf8_to_utf16(string_view s);
- operator wstring_view() const { return {&buffer_[0], size()}; }
- size_t size() const { return buffer_.size() - 1; }
- const wchar_t* c_str() const { return &buffer_[0]; }
- std::wstring str() const { return {&buffer_[0], size()}; }
+ operator basic_string_view<wchar_t>() const { return {&buffer_[0], size()}; }
+ auto size() const -> size_t { return buffer_.size() - 1; }
+ auto c_str() const -> const wchar_t* { return &buffer_[0]; }
+ auto str() const -> std::wstring { return {&buffer_[0], size()}; }
};
-template <typename T = void> struct null {};
-
namespace dragonbox {
// Type-specific information that Dragonbox uses.
@@ -1194,37 +1212,21 @@ template <typename T> struct decimal_fp {
int exponent;
};
-template <typename T> FMT_API decimal_fp<T> to_decimal(T x) FMT_NOEXCEPT;
+template <typename T>
+FMT_API auto to_decimal(T x) FMT_NOEXCEPT -> decimal_fp<T>;
} // namespace dragonbox
template <typename T>
-constexpr typename dragonbox::float_info<T>::carrier_uint exponent_mask() {
+constexpr auto exponent_mask() ->
+ typename dragonbox::float_info<T>::carrier_uint {
using uint = typename dragonbox::float_info<T>::carrier_uint;
return ((uint(1) << dragonbox::float_info<T>::exponent_bits) - 1)
<< dragonbox::float_info<T>::significand_bits;
}
-// A floating-point presentation format.
-enum class float_format : unsigned char {
- general, // General: exponent notation or fixed point based on magnitude.
- exp, // Exponent notation with the default precision of 6, e.g. 1.2e-3.
- fixed, // Fixed point with the default precision of 6, e.g. 0.0012.
- hex
-};
-
-struct float_specs {
- int precision;
- float_format format : 8;
- sign_t sign : 8;
- bool upper : 1;
- bool locale : 1;
- bool binary32 : 1;
- bool use_grisu : 1;
- bool showpoint : 1;
-};
-
// Writes the exponent exp in the form "[+-]d{2,3}" to buffer.
-template <typename Char, typename It> It write_exponent(int exp, It it) {
+template <typename Char, typename It>
+auto write_exponent(int exp, It it) -> It {
FMT_ASSERT(-10000 < exp && exp < 10000, "exponent out of range");
if (exp < 0) {
*it++ = static_cast<Char>('-');
@@ -1245,132 +1247,22 @@ template <typename Char, typename It> It write_exponent(int exp, It it) {
}
template <typename T>
-int format_float(T value, int precision, float_specs specs, buffer<char>& buf);
+auto format_float(T value, int precision, float_specs specs, buffer<char>& buf)
+ -> int;
// Formats a floating-point number with snprintf.
template <typename T>
-int snprintf_float(T value, int precision, float_specs specs,
- buffer<char>& buf);
-
-template <typename T> T promote_float(T value) { return value; }
-inline double promote_float(float value) { return static_cast<double>(value); }
-
-template <typename ErrorHandler = error_handler, typename Char>
-FMT_CONSTEXPR float_specs parse_float_type_spec(
- const basic_format_specs<Char>& specs, ErrorHandler&& eh = {}) {
- auto result = float_specs();
- result.showpoint = specs.alt;
- result.locale = specs.localized;
- switch (specs.type) {
- case 0:
- result.format = float_format::general;
- break;
- case 'G':
- result.upper = true;
- FMT_FALLTHROUGH;
- case 'g':
- result.format = float_format::general;
- break;
- case 'E':
- result.upper = true;
- FMT_FALLTHROUGH;
- case 'e':
- result.format = float_format::exp;
- result.showpoint |= specs.precision != 0;
- break;
- case 'F':
- result.upper = true;
- FMT_FALLTHROUGH;
- case 'f':
- result.format = float_format::fixed;
- result.showpoint |= specs.precision != 0;
- break;
- case 'A':
- result.upper = true;
- FMT_FALLTHROUGH;
- case 'a':
- result.format = float_format::hex;
- break;
- default:
- eh.on_error("invalid type specifier");
- break;
- }
- return result;
-}
-
-template <typename ErrorHandler>
-FMT_CONSTEXPR void check_int_type_spec(char spec, ErrorHandler&& eh) {
- switch (spec) {
- case 0:
- case 'd':
- case 'x':
- case 'X':
- case 'b':
- case 'B':
- case 'o':
- case 'c':
- break;
- default:
- eh.on_error("invalid type specifier");
- break;
- }
-}
-
-template <typename Char, typename Handler>
-FMT_CONSTEXPR void handle_char_specs(const basic_format_specs<Char>& specs,
- Handler&& handler) {
- if (specs.type && specs.type != 'c') return handler.on_int();
- if (specs.align == align::numeric || specs.sign != sign::none || specs.alt)
- handler.on_error("invalid format specifier for char");
- handler.on_char();
-}
-
-template <typename Char, typename Handler>
-FMT_CONSTEXPR void handle_cstring_type_spec(Char spec, Handler&& handler) {
- if (spec == 0 || spec == 's')
- handler.on_string();
- else if (spec == 'p')
- handler.on_pointer();
- else
- handler.on_error("invalid type specifier");
-}
-
-template <typename Char, typename ErrorHandler>
-FMT_CONSTEXPR void check_string_type_spec(Char spec, ErrorHandler&& eh) {
- if (spec != 0 && spec != 's') eh.on_error("invalid type specifier");
-}
+auto snprintf_float(T value, int precision, float_specs specs,
+ buffer<char>& buf) -> int;
-template <typename Char, typename ErrorHandler>
-FMT_CONSTEXPR void check_pointer_type_spec(Char spec, ErrorHandler&& eh) {
- if (spec != 0 && spec != 'p') eh.on_error("invalid type specifier");
+template <typename T> auto promote_float(T value) -> T { return value; }
+inline auto promote_float(float value) -> double {
+ return static_cast<double>(value);
}
-template <typename ErrorHandler>
-class char_specs_checker : public ErrorHandler {
- private:
- char type_;
-
- public:
- FMT_CONSTEXPR char_specs_checker(char type, ErrorHandler eh)
- : ErrorHandler(eh), type_(type) {}
-
- FMT_CONSTEXPR void on_int() { check_int_type_spec(type_, *this); }
- FMT_CONSTEXPR void on_char() {}
-};
-
-template <typename ErrorHandler>
-class cstring_type_checker : public ErrorHandler {
- public:
- FMT_CONSTEXPR explicit cstring_type_checker(ErrorHandler eh)
- : ErrorHandler(eh) {}
-
- FMT_CONSTEXPR void on_string() {}
- FMT_CONSTEXPR void on_pointer() {}
-};
-
template <typename OutputIt, typename Char>
-FMT_NOINLINE FMT_CONSTEXPR OutputIt fill(OutputIt it, size_t n,
- const fill_t<Char>& fill) {
+FMT_NOINLINE FMT_CONSTEXPR auto fill(OutputIt it, size_t n,
+ const fill_t<Char>& fill) -> OutputIt {
auto fill_size = fill.size();
if (fill_size == 1) return detail::fill_n(it, n, fill[0]);
auto data = fill.data();
@@ -1384,9 +1276,9 @@ FMT_NOINLINE FMT_CONSTEXPR OutputIt fill(OutputIt it, size_t n,
// width: output display width in (terminal) column positions.
template <align::type align = align::left, typename OutputIt, typename Char,
typename F>
-FMT_CONSTEXPR OutputIt write_padded(OutputIt out,
- const basic_format_specs<Char>& specs,
- size_t size, size_t width, F&& f) {
+FMT_CONSTEXPR auto write_padded(OutputIt out,
+ const basic_format_specs<Char>& specs,
+ size_t size, size_t width, F&& f) -> OutputIt {
static_assert(align == align::left || align == align::right, "");
unsigned spec_width = to_unsigned(specs.width);
size_t padding = spec_width > width ? spec_width - width : 0;
@@ -1403,35 +1295,50 @@ FMT_CONSTEXPR OutputIt write_padded(OutputIt out,
template <align::type align = align::left, typename OutputIt, typename Char,
typename F>
-constexpr OutputIt write_padded(OutputIt out,
- const basic_format_specs<Char>& specs,
- size_t size, F&& f) {
+constexpr auto write_padded(OutputIt out, const basic_format_specs<Char>& specs,
+ size_t size, F&& f) -> OutputIt {
return write_padded<align>(out, specs, size, size, f);
}
-template <typename Char, typename OutputIt>
-OutputIt write_bytes(OutputIt out, string_view bytes,
- const basic_format_specs<Char>& specs) {
- return write_padded(out, specs, bytes.size(),
- [bytes](reserve_iterator<OutputIt> it) {
- const char* data = bytes.data();
- return copy_str<Char>(data, data + bytes.size(), it);
- });
+template <align::type align = align::left, typename Char, typename OutputIt>
+FMT_CONSTEXPR auto write_bytes(OutputIt out, string_view bytes,
+ const basic_format_specs<Char>& specs)
+ -> OutputIt {
+ return write_padded<align>(
+ out, specs, bytes.size(), [bytes](reserve_iterator<OutputIt> it) {
+ const char* data = bytes.data();
+ return copy_str<Char>(data, data + bytes.size(), it);
+ });
+}
+
+template <typename Char, typename OutputIt, typename UIntPtr>
+auto write_ptr(OutputIt out, UIntPtr value,
+ const basic_format_specs<Char>* specs) -> OutputIt {
+ int num_digits = count_digits<4>(value);
+ auto size = to_unsigned(num_digits) + size_t(2);
+ auto write = [=](reserve_iterator<OutputIt> it) {
+ *it++ = static_cast<Char>('0');
+ *it++ = static_cast<Char>('x');
+ return format_uint<4, Char>(it, value, num_digits);
+ };
+ return specs ? write_padded<align::right>(out, *specs, size, write)
+ : base_iterator(out, write(reserve(out, size)));
}
template <typename Char, typename OutputIt>
-FMT_CONSTEXPR OutputIt write_char(OutputIt out, Char value,
- const basic_format_specs<Char>& specs) {
+FMT_CONSTEXPR auto write_char(OutputIt out, Char value,
+ const basic_format_specs<Char>& specs)
+ -> OutputIt {
return write_padded(out, specs, 1, [=](reserve_iterator<OutputIt> it) {
*it++ = value;
return it;
});
}
template <typename Char, typename OutputIt>
-FMT_CONSTEXPR OutputIt write(OutputIt out, Char value,
- const basic_format_specs<Char>& specs,
- locale_ref loc = {}) {
- return !specs.type || specs.type == 'c'
+FMT_CONSTEXPR auto write(OutputIt out, Char value,
+ const basic_format_specs<Char>& specs,
+ locale_ref loc = {}) -> OutputIt {
+ return check_char_specs(specs)
? write_char(out, value, specs)
: write(out, static_cast<int>(value), specs, loc);
}
@@ -1463,9 +1370,10 @@ template <typename Char> struct write_int_data {
// where <digits> are written by write_digits(it).
// prefix contains chars in three lower bytes and the size in the fourth byte.
template <typename OutputIt, typename Char, typename W>
-FMT_CONSTEXPR FMT_INLINE OutputIt
-write_int(OutputIt out, int num_digits, unsigned prefix,
- const basic_format_specs<Char>& specs, W write_digits) {
+FMT_CONSTEXPR FMT_INLINE auto write_int(OutputIt out, int num_digits,
+ unsigned prefix,
+ const basic_format_specs<Char>& specs,
+ W write_digits) -> OutputIt {
// Slightly faster check for specs.width == 0 && specs.precision == -1.
if ((specs.width | (specs.precision + 1)) == 0) {
auto it = reserve(out, to_unsigned(num_digits) + (prefix >> 24));
@@ -1486,17 +1394,16 @@ write_int(OutputIt out, int num_digits, unsigned prefix,
}
template <typename OutputIt, typename UInt, typename Char>
-bool write_int_localized(OutputIt& out, UInt value, unsigned prefix,
- const basic_format_specs<Char>& specs,
- locale_ref loc) {
+auto write_int_localized(OutputIt& out, UInt value, unsigned prefix,
+ const basic_format_specs<Char>& specs, locale_ref loc)
+ -> bool {
static_assert(std::is_same<uint64_or_128_t<UInt>, UInt>::value, "");
const auto sep_size = 1;
- std::string groups = grouping<Char>(loc);
- if (groups.empty()) return false;
- auto sep = thousands_sep<Char>(loc);
- if (!sep) return false;
+ auto ts = thousands_sep<Char>(loc);
+ if (!ts.thousands_sep) return false;
int num_digits = count_digits(value);
int size = num_digits, n = num_digits;
+ const std::string& groups = ts.grouping;
std::string::const_iterator group = groups.cbegin();
while (group != groups.cend() && n > *group && *group > 0 &&
*group != max_value<char>()) {
@@ -1511,7 +1418,7 @@ bool write_int_localized(OutputIt& out, UInt value, unsigned prefix,
if (prefix != 0) ++size;
const auto usize = to_unsigned(size);
buffer.resize(usize);
- basic_string_view<Char> s(&sep, sep_size);
+ basic_string_view<Char> s(&ts.thousands_sep, sep_size);
// Index of a decimal digit with the least significant digit having index 0.
int digit_index = 0;
group = groups.cbegin();
@@ -1544,19 +1451,32 @@ FMT_CONSTEXPR inline void prefix_append(unsigned& prefix, unsigned value) {
prefix += (1u + (value > 0xff ? 1 : 0)) << 24;
}
-template <typename Char, typename OutputIt, typename T,
- FMT_ENABLE_IF(is_integral<T>::value && !std::is_same<T, bool>::value)>
-FMT_CONSTEXPR FMT_INLINE OutputIt
-write_int(OutputIt out, T value, const basic_format_specs<Char>& specs,
- locale_ref loc) {
+template <typename UInt> struct write_int_arg {
+ UInt abs_value;
+ unsigned prefix;
+};
+
+template <typename T>
+FMT_CONSTEXPR auto make_write_int_arg(T value, sign_t sign)
+ -> write_int_arg<uint32_or_64_or_128_t<T>> {
auto prefix = 0u;
auto abs_value = static_cast<uint32_or_64_or_128_t<T>>(value);
if (is_negative(value)) {
prefix = 0x01000000 | '-';
abs_value = 0 - abs_value;
} else {
- prefix = data::prefixes[specs.sign];
+ prefix = data::prefixes[sign];
}
+ return {abs_value, prefix};
+}
+
+template <typename Char, typename OutputIt, typename T>
+FMT_CONSTEXPR FMT_INLINE auto write_int(OutputIt out, write_int_arg<T> arg,
+ const basic_format_specs<Char>& specs,
+ locale_ref loc) -> OutputIt {
+ static_assert(std::is_same<T, uint32_or_64_or_128_t<T>>::value, "");
+ auto abs_value = arg.abs_value;
+ auto prefix = arg.prefix;
auto utype = static_cast<unsigned>(specs.type);
switch (specs.type) {
case 0:
@@ -1614,54 +1534,65 @@ template <typename Char, typename OutputIt, typename T,
FMT_ENABLE_IF(is_integral<T>::value &&
!std::is_same<T, bool>::value &&
std::is_same<OutputIt, buffer_appender<Char>>::value)>
-FMT_CONSTEXPR OutputIt write(OutputIt out, T value,
- const basic_format_specs<Char>& specs,
- locale_ref loc) {
- return write_int(out, value, specs, loc);
+FMT_CONSTEXPR auto write(OutputIt out, T value,
+ const basic_format_specs<Char>& specs, locale_ref loc)
+ -> OutputIt {
+ return write_int(out, make_write_int_arg(value, specs.sign), specs, loc);
}
// An inlined version of write used in format string compilation.
template <typename Char, typename OutputIt, typename T,
FMT_ENABLE_IF(is_integral<T>::value &&
!std::is_same<T, bool>::value &&
!std::is_same<OutputIt, buffer_appender<Char>>::value)>
-FMT_CONSTEXPR FMT_INLINE OutputIt write(OutputIt out, T value,
- const basic_format_specs<Char>& specs,
- locale_ref loc) {
- return write_int(out, value, specs, loc);
+FMT_CONSTEXPR FMT_INLINE auto write(OutputIt out, T value,
+ const basic_format_specs<Char>& specs,
+ locale_ref loc) -> OutputIt {
+ return write_int(out, make_write_int_arg(value, specs.sign), specs, loc);
}
-template <typename OutputIt, typename StrChar, typename Char>
-FMT_CONSTEXPR OutputIt write(OutputIt out, basic_string_view<StrChar> s,
- const basic_format_specs<Char>& specs) {
+template <typename Char, typename OutputIt>
+FMT_CONSTEXPR auto write(OutputIt out, basic_string_view<Char> s,
+ const basic_format_specs<Char>& specs) -> OutputIt {
auto data = s.data();
auto size = s.size();
if (specs.precision >= 0 && to_unsigned(specs.precision) < size)
size = code_point_index(s, to_unsigned(specs.precision));
- auto width = specs.width != 0
- ? compute_width(basic_string_view<StrChar>(data, size))
- : 0;
+ auto width =
+ specs.width != 0 ? compute_width(basic_string_view<Char>(data, size)) : 0;
return write_padded(out, specs, size, width,
[=](reserve_iterator<OutputIt> it) {
return copy_str<Char>(data, data + size, it);
});
}
template <typename Char, typename OutputIt>
-FMT_CONSTEXPR OutputIt write(OutputIt out,
- basic_string_view<type_identity_t<Char>> s,
- const basic_format_specs<Char>& specs,
- locale_ref) {
- return write(out, s, specs); // Adapt write to formatter::format.
+FMT_CONSTEXPR auto write(OutputIt out,
+ basic_string_view<type_identity_t<Char>> s,
+ const basic_format_specs<Char>& specs, locale_ref)
+ -> OutputIt {
+ check_string_type_spec(specs.type);
+ return write(out, s, specs);
+}
+template <typename Char, typename OutputIt>
+FMT_CONSTEXPR auto write(OutputIt out, const Char* s,
+ const basic_format_specs<Char>& specs, locale_ref)
+ -> OutputIt {
+ return check_cstring_type_spec(specs.type)
+ ? write(out, basic_string_view<Char>(s), specs, {})
+ : write_ptr<Char>(out, to_uintptr(s), &specs);
}
template <typename Char, typename OutputIt>
-OutputIt write_nonfinite(OutputIt out, bool isinf,
- const basic_format_specs<Char>& specs,
- const float_specs& fspecs) {
+auto write_nonfinite(OutputIt out, bool isinf, basic_format_specs<Char> specs,
+ const float_specs& fspecs) -> OutputIt {
auto str =
isinf ? (fspecs.upper ? "INF" : "inf") : (fspecs.upper ? "NAN" : "nan");
constexpr size_t str_size = 3;
auto sign = fspecs.sign;
auto size = str_size + (sign ? 1 : 0);
+ // Replace '0'-padding with space for non-finite values.
+ const bool is_zero_fill =
+ specs.fill.size() == 1 && *specs.fill.data() == static_cast<Char>('0');
+ if (is_zero_fill) specs.fill[0] = static_cast<Char>(' ');
return write_padded(out, specs, size, [=](reserve_iterator<OutputIt> it) {
if (sign) *it++ = static_cast<Char>(data::signs[sign]);
return copy_str<Char>(str, str + str_size, it);
@@ -1675,30 +1606,29 @@ struct big_decimal_fp {
int exponent;
};
-inline int get_significand_size(const big_decimal_fp& fp) {
+inline auto get_significand_size(const big_decimal_fp& fp) -> int {
return fp.significand_size;
}
template <typename T>
-inline int get_significand_size(const dragonbox::decimal_fp<T>& fp) {
+inline auto get_significand_size(const dragonbox::decimal_fp<T>& fp) -> int {
return count_digits(fp.significand);
}
template <typename Char, typename OutputIt>
-inline OutputIt write_significand(OutputIt out, const char* significand,
- int& significand_size) {
+inline auto write_significand(OutputIt out, const char* significand,
+ int& significand_size) -> OutputIt {
return copy_str<Char>(significand, significand + significand_size, out);
}
template <typename Char, typename OutputIt, typename UInt>
-inline OutputIt write_significand(OutputIt out, UInt significand,
- int significand_size) {
+inline auto write_significand(OutputIt out, UInt significand,
+ int significand_size) -> OutputIt {
return format_decimal<Char>(out, significand, significand_size).end;
}
template <typename Char, typename UInt,
FMT_ENABLE_IF(std::is_integral<UInt>::value)>
-inline Char* write_significand(Char* out, UInt significand,
- int significand_size, int integral_size,
- Char decimal_point) {
+inline auto write_significand(Char* out, UInt significand, int significand_size,
+ int integral_size, Char decimal_point) -> Char* {
if (!decimal_point)
return format_decimal(out, significand, significand_size).end;
auto end = format_decimal(out + 1, significand, significand_size).end;
@@ -1714,31 +1644,32 @@ inline Char* write_significand(Char* out, UInt significand,
template <typename OutputIt, typename UInt, typename Char,
FMT_ENABLE_IF(!std::is_pointer<remove_cvref_t<OutputIt>>::value)>
-inline OutputIt write_significand(OutputIt out, UInt significand,
- int significand_size, int integral_size,
- Char decimal_point) {
+inline auto write_significand(OutputIt out, UInt significand,
+ int significand_size, int integral_size,
+ Char decimal_point) -> OutputIt {
// Buffer is large enough to hold digits (digits10 + 1) and a decimal point.
Char buffer[digits10<UInt>() + 2];
auto end = write_significand(buffer, significand, significand_size,
integral_size, decimal_point);
- return detail::copy_str<Char>(buffer, end, out);
+ return detail::copy_str_noinline<Char>(buffer, end, out);
}
template <typename OutputIt, typename Char>
-inline OutputIt write_significand(OutputIt out, const char* significand,
- int significand_size, int integral_size,
- Char decimal_point) {
- out = detail::copy_str<Char>(significand, significand + integral_size, out);
+inline auto write_significand(OutputIt out, const char* significand,
+ int significand_size, int integral_size,
+ Char decimal_point) -> OutputIt {
+ out = detail::copy_str_noinline<Char>(significand,
+ significand + integral_size, out);
if (!decimal_point) return out;
*out++ = decimal_point;
- return detail::copy_str<Char>(significand + integral_size,
- significand + significand_size, out);
+ return detail::copy_str_noinline<Char>(significand + integral_size,
+ significand + significand_size, out);
}
template <typename OutputIt, typename DecimalFP, typename Char>
-OutputIt write_float(OutputIt out, const DecimalFP& fp,
- const basic_format_specs<Char>& specs, float_specs fspecs,
- Char decimal_point) {
+auto write_float(OutputIt out, const DecimalFP& fp,
+ const basic_format_specs<Char>& specs, float_specs fspecs,
+ Char decimal_point) -> OutputIt {
auto significand = fp.significand;
int significand_size = get_significand_size(fp);
static const Char zero = static_cast<Char>('0');
@@ -1836,8 +1767,8 @@ OutputIt write_float(OutputIt out, const DecimalFP& fp,
template <typename Char, typename OutputIt, typename T,
FMT_ENABLE_IF(std::is_floating_point<T>::value)>
-OutputIt write(OutputIt out, T value, basic_format_specs<Char> specs,
- locale_ref loc = {}) {
+auto write(OutputIt out, T value, basic_format_specs<Char> specs,
+ locale_ref loc = {}) -> OutputIt {
if (const_check(!is_supported_floating_point(value))) return out;
float_specs fspecs = parse_float_type_spec(specs);
fspecs.sign = specs.sign;
@@ -1863,7 +1794,8 @@ OutputIt write(OutputIt out, T value, basic_format_specs<Char> specs,
if (fspecs.format == float_format::hex) {
if (fspecs.sign) buffer.push_back(data::signs[fspecs.sign]);
snprintf_float(promote_float(value), specs.precision, fspecs, buffer);
- return write_bytes(out, {buffer.data(), buffer.size()}, specs);
+ return write_bytes<align::right>(out, {buffer.data(), buffer.size()},
+ specs);
}
int precision = specs.precision >= 0 || !specs.type ? specs.precision : 6;
if (fspecs.format == float_format::exp) {
@@ -1884,7 +1816,7 @@ OutputIt write(OutputIt out, T value, basic_format_specs<Char> specs,
template <typename Char, typename OutputIt, typename T,
FMT_ENABLE_IF(is_fast_float<T>::value)>
-OutputIt write(OutputIt out, T value) {
+auto write(OutputIt out, T value) -> OutputIt {
if (const_check(!is_supported_floating_point(value))) return out;
using floaty = conditional_t<std::is_same<T, long double>::value, double, T>;
@@ -1910,48 +1842,28 @@ OutputIt write(OutputIt out, T value) {
template <typename Char, typename OutputIt, typename T,
FMT_ENABLE_IF(std::is_floating_point<T>::value &&
!is_fast_float<T>::value)>
-inline OutputIt write(OutputIt out, T value) {
+inline auto write(OutputIt out, T value) -> OutputIt {
return write(out, value, basic_format_specs<Char>());
}
-template <typename Char, typename OutputIt, typename UIntPtr>
-OutputIt write_ptr(OutputIt out, UIntPtr value,
- const basic_format_specs<Char>* specs) {
- int num_digits = count_digits<4>(value);
- auto size = to_unsigned(num_digits) + size_t(2);
- auto write = [=](reserve_iterator<OutputIt> it) {
- *it++ = static_cast<Char>('0');
- *it++ = static_cast<Char>('x');
- return format_uint<4, Char>(it, value, num_digits);
- };
- return specs ? write_padded<align::right>(out, *specs, size, write)
- : base_iterator(out, write(reserve(out, size)));
-}
-
template <typename Char, typename OutputIt>
-OutputIt write(OutputIt out, monostate) {
+auto write(OutputIt out, monostate, basic_format_specs<Char> = {},
+ locale_ref = {}) -> OutputIt {
FMT_ASSERT(false, "");
return out;
}
-template <typename Char, typename OutputIt,
- FMT_ENABLE_IF(!std::is_same<Char, char>::value)>
-OutputIt write(OutputIt out, string_view value) {
- auto it = reserve(out, value.size());
- it = copy_str<Char>(value.begin(), value.end(), it);
- return base_iterator(out, it);
-}
-
template <typename Char, typename OutputIt>
-FMT_CONSTEXPR OutputIt write(OutputIt out, basic_string_view<Char> value) {
+FMT_CONSTEXPR auto write(OutputIt out, basic_string_view<Char> value)
+ -> OutputIt {
auto it = reserve(out, value.size());
- it = copy_str<Char>(value.begin(), value.end(), it);
+ it = copy_str_noinline<Char>(value.begin(), value.end(), it);
return base_iterator(out, it);
}
template <typename Char, typename OutputIt, typename T,
FMT_ENABLE_IF(is_string<T>::value)>
-constexpr OutputIt write(OutputIt out, const T& value) {
+constexpr auto write(OutputIt out, const T& value) -> OutputIt {
return write<Char>(out, to_string_view(value));
}
@@ -1959,7 +1871,7 @@ template <typename Char, typename OutputIt, typename T,
FMT_ENABLE_IF(is_integral<T>::value &&
!std::is_same<T, bool>::value &&
!std::is_same<T, Char>::value)>
-FMT_CONSTEXPR OutputIt write(OutputIt out, T value) {
+FMT_CONSTEXPR auto write(OutputIt out, T value) -> OutputIt {
auto abs_value = static_cast<uint32_or_64_or_128_t<T>>(value);
bool negative = is_negative(value);
// Don't do -abs_value since it trips unsigned-integer-overflow sanitizer.
@@ -1985,30 +1897,31 @@ template <
mapped_type_constant<T, basic_format_context<OutputIt, Char>>::value !=
type::custom_type,
FMT_ENABLE_IF(check)>
-FMT_CONSTEXPR OutputIt write(OutputIt out, T value) {
+FMT_CONSTEXPR auto write(OutputIt out, T value) -> OutputIt {
return write<Char>(
out, static_cast<typename std::underlying_type<T>::type>(value));
}
template <typename Char, typename OutputIt, typename T,
FMT_ENABLE_IF(std::is_same<T, bool>::value)>
-FMT_CONSTEXPR OutputIt write(OutputIt out, T value,
- const basic_format_specs<Char>& specs = {},
- locale_ref = {}) {
+FMT_CONSTEXPR auto write(OutputIt out, T value,
+ const basic_format_specs<Char>& specs = {},
+ locale_ref = {}) -> OutputIt {
return specs.type && specs.type != 's'
? write(out, value ? 1 : 0, specs, {})
- : write(out, string_view(value ? "true" : "false"), specs);
+ : write_bytes(out, value ? "true" : "false", specs);
}
template <typename Char, typename OutputIt>
-FMT_CONSTEXPR OutputIt write(OutputIt out, Char value) {
+FMT_CONSTEXPR auto write(OutputIt out, Char value) -> OutputIt {
auto it = reserve(out, 1);
*it++ = value;
return base_iterator(out, it);
}
template <typename Char, typename OutputIt>
-FMT_CONSTEXPR_CHAR_TRAITS OutputIt write(OutputIt out, const Char* value) {
+FMT_CONSTEXPR_CHAR_TRAITS auto write(OutputIt out, const Char* value)
+ -> OutputIt {
if (!value) {
FMT_THROW(format_error("string pointer is null"));
} else {
@@ -2020,16 +1933,19 @@ FMT_CONSTEXPR_CHAR_TRAITS OutputIt write(OutputIt out, const Char* value) {
template <typename Char, typename OutputIt, typename T,
FMT_ENABLE_IF(std::is_same<T, void>::value)>
-OutputIt write(OutputIt out, const T* value,
- const basic_format_specs<Char>& specs = {}, locale_ref = {}) {
+auto write(OutputIt out, const T* value,
+ const basic_format_specs<Char>& specs = {}, locale_ref = {})
+ -> OutputIt {
+ check_pointer_type_spec(specs.type, error_handler());
return write_ptr<Char>(out, to_uintptr(value), &specs);
}
template <typename Char, typename OutputIt, typename T>
-auto write(OutputIt out, const T& value) -> typename std::enable_if<
- mapped_type_constant<T, basic_format_context<OutputIt, Char>>::value ==
- type::custom_type,
- OutputIt>::type {
+FMT_CONSTEXPR auto write(OutputIt out, const T& value) ->
+ typename std::enable_if<
+ mapped_type_constant<T, basic_format_context<OutputIt, Char>>::value ==
+ type::custom_type,
+ OutputIt>::type {
using context_type = basic_format_context<OutputIt, Char>;
using formatter_type =
conditional_t<has_formatter<T, context_type>::value,
@@ -2041,231 +1957,52 @@ auto write(OutputIt out, const T& value) -> typename std::enable_if<
// An argument visitor that formats the argument and writes it via the output
// iterator. It's a class and not a generic lambda for compatibility with C++11.
-template <typename OutputIt, typename Char> struct default_arg_formatter {
- using context = basic_format_context<OutputIt, Char>;
+template <typename Char> struct default_arg_formatter {
+ using iterator = buffer_appender<Char>;
+ using context = buffer_context<Char>;
- OutputIt out;
+ iterator out;
basic_format_args<context> args;
locale_ref loc;
- template <typename T> OutputIt operator()(T value) {
+ template <typename T> auto operator()(T value) -> iterator {
return write<Char>(out, value);
}
-
- OutputIt operator()(typename basic_format_arg<context>::handle handle) {
+ auto operator()(typename basic_format_arg<context>::handle h) -> iterator {
basic_format_parse_context<Char> parse_ctx({});
- basic_format_context<OutputIt, Char> format_ctx(out, args, loc);
- handle.format(parse_ctx, format_ctx);
+ context format_ctx(out, args, loc);
+ h.format(parse_ctx, format_ctx);
return format_ctx.out();
}
};
-template <typename OutputIt, typename Char,
- typename ErrorHandler = error_handler>
-class arg_formatter_base {
- public:
- using iterator = OutputIt;
- using char_type = Char;
- using format_specs = basic_format_specs<Char>;
-
- private:
- iterator out_;
- const format_specs& specs_;
- locale_ref locale_;
-
- // Attempts to reserve space for n extra characters in the output range.
- // Returns a pointer to the reserved range or a reference to out_.
- auto reserve(size_t n) -> decltype(detail::reserve(out_, n)) {
- return detail::reserve(out_, n);
- }
-
- void write(char value) {
- auto&& it = reserve(1);
- *it++ = value;
- }
-
- template <typename Ch, FMT_ENABLE_IF(std::is_same<Ch, Char>::value)>
- void write(Ch value) {
- out_ = detail::write<Char>(out_, value);
- }
-
- void write(string_view value) {
- auto&& it = reserve(value.size());
- it = copy_str<Char>(value.begin(), value.end(), it);
- }
- void write(wstring_view value) {
- static_assert(std::is_same<Char, wchar_t>::value, "");
- auto&& it = reserve(value.size());
- it = copy_str<Char>(value.begin(), value.end(), it);
- }
-
- template <typename Ch>
- void write(const Ch* s, size_t size, const format_specs& specs) {
- auto width =
- specs.width != 0 ? compute_width(basic_string_view<Ch>(s, size)) : 0;
- out_ = write_padded(out_, specs, size, width,
- [=](reserve_iterator<OutputIt> it) {
- return copy_str<Char>(s, s + size, it);
- });
- }
-
- template <typename Ch>
- FMT_CONSTEXPR void write(basic_string_view<Ch> s,
- const format_specs& specs = {}) {
- out_ = detail::write(out_, s, specs);
- }
-
- void write_pointer(const void* p) {
- out_ = write_ptr<char_type>(out_, to_uintptr(p), &specs_);
- }
-
- struct char_spec_handler : ErrorHandler {
- arg_formatter_base& formatter;
- Char value;
-
- constexpr char_spec_handler(arg_formatter_base& f, Char val)
- : formatter(f), value(val) {}
-
- FMT_CONSTEXPR void on_int() {
- // char is only formatted as int if there are specs.
- formatter.out_ = detail::write(formatter.out_, static_cast<int>(value),
- formatter.specs_, formatter.locale_);
- }
- FMT_CONSTEXPR void on_char() {
- formatter.out_ =
- detail::write<Char>(formatter.out_, value, formatter.specs_);
- }
- };
-
- struct cstring_spec_handler : error_handler {
- arg_formatter_base& formatter;
- const Char* value;
-
- cstring_spec_handler(arg_formatter_base& f, const Char* val)
- : formatter(f), value(val) {}
-
- void on_string() { formatter.write(value); }
- void on_pointer() { formatter.write_pointer(value); }
- };
-
- protected:
- iterator out() { return out_; }
- const format_specs& specs() { return specs_; }
-
- FMT_CONSTEXPR void write(bool value) {
- write(string_view(value ? "true" : "false"), specs_);
- }
-
- void write(const Char* value) {
- if (value)
- write(basic_string_view<char_type>(value), specs_);
- else
- FMT_THROW(format_error("string pointer is null"));
- }
-
- public:
- constexpr arg_formatter_base(OutputIt out, const format_specs& s,
- locale_ref loc)
- : out_(out), specs_(s), locale_(loc) {}
-
- iterator operator()(monostate) {
- FMT_ASSERT(false, "invalid argument type");
- return out_;
- }
-
- template <typename T, FMT_ENABLE_IF(is_integral<T>::value)>
- FMT_CONSTEXPR FMT_INLINE iterator operator()(T value) {
- return out_ = detail::write(out_, value, specs_, locale_);
- }
-
- FMT_CONSTEXPR iterator operator()(Char value) {
- handle_char_specs(specs_,
- char_spec_handler(*this, static_cast<Char>(value)));
- return out_;
- }
-
- FMT_CONSTEXPR iterator operator()(bool value) {
- if (specs_.type && specs_.type != 's') return (*this)(value ? 1 : 0);
- write(value != 0);
- return out_;
- }
-
- template <typename T, FMT_ENABLE_IF(std::is_floating_point<T>::value)>
- iterator operator()(T value) {
- if (const_check(is_supported_floating_point(value)))
- out_ = detail::write(out_, value, specs_, locale_);
- else
- FMT_ASSERT(false, "unsupported float argument type");
- return out_;
- }
-
- iterator operator()(const Char* value) {
- handle_cstring_type_spec(specs_.type, cstring_spec_handler(*this, value));
- return out_;
- }
+template <typename Char> struct arg_formatter {
+ using iterator = buffer_appender<Char>;
+ using context = buffer_context<Char>;
- FMT_CONSTEXPR iterator operator()(basic_string_view<Char> value) {
- check_string_type_spec(specs_.type, error_handler());
- write(value, specs_);
- return out_;
- }
+ iterator out;
+ const basic_format_specs<Char>& specs;
+ locale_ref locale;
- iterator operator()(const void* value) {
- check_pointer_type_spec(specs_.type, error_handler());
- write_pointer(value);
- return out_;
+ template <typename T>
+ FMT_CONSTEXPR FMT_INLINE auto operator()(T value) -> iterator {
+ return detail::write(out, value, specs, locale);
}
-};
-
-/** The default argument formatter. */
-template <typename OutputIt, typename Char>
-class arg_formatter : public arg_formatter_base<OutputIt, Char> {
- private:
- using char_type = Char;
- using base = arg_formatter_base<OutputIt, Char>;
- using context_type = basic_format_context<OutputIt, Char>;
-
- context_type& ctx_;
-
- public:
- using iterator = typename base::iterator;
- using format_specs = typename base::format_specs;
-
- /**
- \rst
- Constructs an argument formatter object.
- *ctx* is a reference to the formatting context,
- *specs* contains format specifier information for standard argument types.
- \endrst
- */
- constexpr explicit arg_formatter(context_type& ctx, const format_specs& specs)
- : base(ctx.out(), specs, ctx.locale()), ctx_(ctx) {}
-
- using base::operator();
-
- iterator operator()(typename basic_format_arg<context_type>::handle) {
- // User-defined types are handled separately because they require access to
- // the parse context.
- return ctx_.out();
+ auto operator()(typename basic_format_arg<context>::handle) -> iterator {
+ // User-defined types are handled separately because they require access
+ // to the parse context.
+ return out;
}
};
-template <typename Context> class custom_formatter {
- private:
- using char_type = typename Context::char_type;
-
- basic_format_parse_context<char_type>& parse_ctx_;
- Context& ctx_;
-
- public:
- explicit custom_formatter(basic_format_parse_context<char_type>& parse_ctx,
- Context& ctx)
- : parse_ctx_(parse_ctx), ctx_(ctx) {}
+template <typename Char> struct custom_formatter {
+ basic_format_parse_context<Char>& parse_ctx;
+ buffer_context<Char>& ctx;
- void operator()(typename basic_format_arg<Context>::handle h) const {
- h.format(parse_ctx_, ctx_);
+ void operator()(
+ typename basic_format_arg<buffer_context<Char>>::handle h) const {
+ h.format(parse_ctx, ctx);
}
-
template <typename T> void operator()(T) const {}
};
@@ -2280,13 +2017,13 @@ template <typename ErrorHandler> class width_checker {
explicit FMT_CONSTEXPR width_checker(ErrorHandler& eh) : handler_(eh) {}
template <typename T, FMT_ENABLE_IF(is_integer<T>::value)>
- FMT_CONSTEXPR unsigned long long operator()(T value) {
+ FMT_CONSTEXPR auto operator()(T value) -> unsigned long long {
if (is_negative(value)) handler_.on_error("negative width");
return static_cast<unsigned long long>(value);
}
template <typename T, FMT_ENABLE_IF(!is_integer<T>::value)>
- FMT_CONSTEXPR unsigned long long operator()(T) {
+ FMT_CONSTEXPR auto operator()(T) -> unsigned long long {
handler_.on_error("width is not integer");
return 0;
}
@@ -2300,13 +2037,13 @@ template <typename ErrorHandler> class precision_checker {
explicit FMT_CONSTEXPR precision_checker(ErrorHandler& eh) : handler_(eh) {}
template <typename T, FMT_ENABLE_IF(is_integer<T>::value)>
- FMT_CONSTEXPR unsigned long long operator()(T value) {
+ FMT_CONSTEXPR auto operator()(T value) -> unsigned long long {
if (is_negative(value)) handler_.on_error("negative precision");
return static_cast<unsigned long long>(value);
}
template <typename T, FMT_ENABLE_IF(!is_integer<T>::value)>
- FMT_CONSTEXPR unsigned long long operator()(T) {
+ FMT_CONSTEXPR auto operator()(T) -> unsigned long long {
handler_.on_error("precision is not integer");
return 0;
}
@@ -2315,197 +2052,62 @@ template <typename ErrorHandler> class precision_checker {
ErrorHandler& handler_;
};
-template <typename ErrorHandler> class numeric_specs_checker {
- public:
- FMT_CONSTEXPR numeric_specs_checker(ErrorHandler& eh, detail::type arg_type)
- : error_handler_(eh), arg_type_(arg_type) {}
-
- FMT_CONSTEXPR void require_numeric_argument() {
- if (!is_arithmetic_type(arg_type_))
- error_handler_.on_error("format specifier requires numeric argument");
- }
-
- FMT_CONSTEXPR void check_sign() {
- require_numeric_argument();
- if (is_integral_type(arg_type_) && arg_type_ != type::int_type &&
- arg_type_ != type::long_long_type && arg_type_ != type::char_type) {
- error_handler_.on_error("format specifier requires signed argument");
- }
- }
-
- FMT_CONSTEXPR void check_precision() {
- if (is_integral_type(arg_type_) || arg_type_ == type::pointer_type)
- error_handler_.on_error("precision not allowed for this argument type");
- }
-
- private:
- ErrorHandler& error_handler_;
- detail::type arg_type_;
-};
-
-// A format specifier handler that checks if specifiers are consistent with the
-// argument type.
-template <typename Handler> class specs_checker : public Handler {
- private:
- numeric_specs_checker<Handler> checker_;
-
- // Suppress an MSVC warning about using this in initializer list.
- FMT_CONSTEXPR Handler& error_handler() { return *this; }
-
- public:
- FMT_CONSTEXPR specs_checker(const Handler& handler, detail::type arg_type)
- : Handler(handler), checker_(error_handler(), arg_type) {}
-
- FMT_CONSTEXPR specs_checker(const specs_checker& other)
- : Handler(other), checker_(error_handler(), other.arg_type_) {}
-
- FMT_CONSTEXPR void on_align(align_t align) {
- if (align == align::numeric) checker_.require_numeric_argument();
- Handler::on_align(align);
- }
-
- FMT_CONSTEXPR void on_plus() {
- checker_.check_sign();
- Handler::on_plus();
- }
-
- FMT_CONSTEXPR void on_minus() {
- checker_.check_sign();
- Handler::on_minus();
- }
-
- FMT_CONSTEXPR void on_space() {
- checker_.check_sign();
- Handler::on_space();
- }
-
- FMT_CONSTEXPR void on_hash() {
- checker_.require_numeric_argument();
- Handler::on_hash();
- }
-
- FMT_CONSTEXPR void on_localized() {
- checker_.require_numeric_argument();
- Handler::on_localized();
- }
-
- FMT_CONSTEXPR void on_zero() {
- checker_.require_numeric_argument();
- Handler::on_zero();
- }
-
- FMT_CONSTEXPR void end_precision() { checker_.check_precision(); }
-};
-
template <template <typename> class Handler, typename FormatArg,
typename ErrorHandler>
-FMT_CONSTEXPR int get_dynamic_spec(FormatArg arg, ErrorHandler eh) {
+FMT_CONSTEXPR auto get_dynamic_spec(FormatArg arg, ErrorHandler eh) -> int {
unsigned long long value = visit_format_arg(Handler<ErrorHandler>(eh), arg);
if (value > to_unsigned(max_value<int>())) eh.on_error("number is too big");
return static_cast<int>(value);
}
template <typename Context, typename ID>
-FMT_CONSTEXPR typename Context::format_arg get_arg(Context& ctx, ID id) {
+FMT_CONSTEXPR auto get_arg(Context& ctx, ID id) ->
+ typename Context::format_arg {
auto arg = ctx.arg(id);
if (!arg) ctx.on_error("argument not found");
return arg;
}
// The standard format specifier handler with checking.
-template <typename ParseContext, typename Context>
-class specs_handler : public specs_setter<typename Context::char_type> {
- public:
- using char_type = typename Context::char_type;
-
- FMT_CONSTEXPR specs_handler(basic_format_specs<char_type>& specs,
- ParseContext& parse_ctx, Context& ctx)
- : specs_setter<char_type>(specs),
- parse_context_(parse_ctx),
- context_(ctx) {}
-
- template <typename Id> FMT_CONSTEXPR void on_dynamic_width(Id arg_id) {
- this->specs_.width = get_dynamic_spec<width_checker>(
- get_arg(arg_id), context_.error_handler());
- }
-
- template <typename Id> FMT_CONSTEXPR void on_dynamic_precision(Id arg_id) {
- this->specs_.precision = get_dynamic_spec<precision_checker>(
- get_arg(arg_id), context_.error_handler());
- }
-
- void on_error(const char* message) { context_.on_error(message); }
-
+template <typename Char> class specs_handler : public specs_setter<Char> {
private:
+ basic_format_parse_context<Char>& parse_context_;
+ buffer_context<Char>& context_;
+
// This is only needed for compatibility with gcc 4.4.
- using format_arg = typename Context::format_arg;
+ using format_arg = basic_format_arg<buffer_context<Char>>;
- FMT_CONSTEXPR format_arg get_arg(auto_id) {
+ FMT_CONSTEXPR auto get_arg(auto_id) -> format_arg {
return detail::get_arg(context_, parse_context_.next_arg_id());
}
- FMT_CONSTEXPR format_arg get_arg(int arg_id) {
+ FMT_CONSTEXPR auto get_arg(int arg_id) -> format_arg {
parse_context_.check_arg_id(arg_id);
return detail::get_arg(context_, arg_id);
}
- FMT_CONSTEXPR format_arg get_arg(basic_string_view<char_type> arg_id) {
+ FMT_CONSTEXPR auto get_arg(basic_string_view<Char> arg_id) -> format_arg {
parse_context_.check_arg_id(arg_id);
return detail::get_arg(context_, arg_id);
}
- ParseContext& parse_context_;
- Context& context_;
-};
-
-template <typename OutputIt, typename Char, typename Context>
-struct format_handler : detail::error_handler {
- basic_format_parse_context<Char> parse_context;
- Context context;
-
- format_handler(OutputIt out, basic_string_view<Char> str,
- basic_format_args<Context> format_args, detail::locale_ref loc)
- : parse_context(str), context(out, format_args, loc) {}
-
- void on_text(const Char* begin, const Char* end) {
- auto text = basic_string_view<Char>(begin, to_unsigned(end - begin));
- context.advance_to(write<Char>(context.out(), text));
- }
+ public:
+ FMT_CONSTEXPR specs_handler(basic_format_specs<Char>& specs,
+ basic_format_parse_context<Char>& parse_ctx,
+ buffer_context<Char>& ctx)
+ : specs_setter<Char>(specs), parse_context_(parse_ctx), context_(ctx) {}
- int on_arg_id() { return parse_context.next_arg_id(); }
- int on_arg_id(int id) { return parse_context.check_arg_id(id), id; }
- int on_arg_id(basic_string_view<Char> id) {
- int arg_id = context.arg_id(id);
- if (arg_id < 0) on_error("argument not found");
- return arg_id;
+ template <typename Id> FMT_CONSTEXPR void on_dynamic_width(Id arg_id) {
+ this->specs_.width = get_dynamic_spec<width_checker>(
+ get_arg(arg_id), context_.error_handler());
}
- FMT_INLINE void on_replacement_field(int id, const Char*) {
- auto arg = get_arg(context, id);
- context.advance_to(visit_format_arg(
- default_arg_formatter<OutputIt, Char>{context.out(), context.args(),
- context.locale()},
- arg));
+ template <typename Id> FMT_CONSTEXPR void on_dynamic_precision(Id arg_id) {
+ this->specs_.precision = get_dynamic_spec<precision_checker>(
+ get_arg(arg_id), context_.error_handler());
}
- const Char* on_format_specs(int id, const Char* begin, const Char* end) {
- auto arg = get_arg(context, id);
- if (arg.type() == type::custom_type) {
- advance_to(parse_context, begin);
- visit_format_arg(custom_formatter<Context>(parse_context, context), arg);
- return parse_context.begin();
- }
- auto specs = basic_format_specs<Char>();
- using parse_context_t = basic_format_parse_context<Char>;
- specs_checker<specs_handler<parse_context_t, Context>> handler(
- specs_handler<parse_context_t, Context>(specs, parse_context, context),
- arg.type());
- begin = parse_format_specs(begin, end, handler);
- if (begin == end || *begin != '}') on_error("missing '}' in format string");
- context.advance_to(
- visit_format_arg(arg_formatter<OutputIt, Char>(context, specs), arg));
- return begin;
- }
+ void on_error(const char* message) { context_.on_error(message); }
};
template <template <typename> class Handler, typename Context>
@@ -2526,6 +2128,88 @@ FMT_CONSTEXPR void handle_dynamic_spec(int& value,
}
}
+#define FMT_STRING_IMPL(s, base, explicit) \
+ [] { \
+ /* Use the hidden visibility as a workaround for a GCC bug (#1973). */ \
+ /* Use a macro-like name to avoid shadowing warnings. */ \
+ struct FMT_GCC_VISIBILITY_HIDDEN FMT_COMPILE_STRING : base { \
+ using char_type = fmt::remove_cvref_t<decltype(s[0])>; \
+ FMT_MAYBE_UNUSED FMT_CONSTEXPR explicit \
+ operator fmt::basic_string_view<char_type>() const { \
+ return fmt::detail_exported::compile_string_to_view<char_type>(s); \
+ } \
+ }; \
+ return FMT_COMPILE_STRING(); \
+ }()
+
+/**
+ \rst
+ Constructs a compile-time format string from a string literal *s*.
+
+ **Example**::
+
+ // A compile-time error because 'd' is an invalid specifier for strings.
+ std::string s = fmt::format(FMT_STRING("{:d}"), "foo");
+ \endrst
+ */
+#define FMT_STRING(s) FMT_STRING_IMPL(s, fmt::compile_string, )
+
+#if FMT_USE_USER_DEFINED_LITERALS
+template <typename Char> struct udl_formatter {
+ basic_string_view<Char> str;
+
+ template <typename... T>
+ auto operator()(T&&... args) const -> std::basic_string<Char> {
+ return vformat(str, fmt::make_args_checked<T...>(str, args...));
+ }
+};
+
+# if FMT_USE_NONTYPE_TEMPLATE_PARAMETERS
+template <typename T, typename Char, size_t N,
+ fmt::detail_exported::fixed_string<Char, N> Str>
+struct statically_named_arg : view {
+ static constexpr auto name = Str.data;
+
+ const T& value;
+ statically_named_arg(const T& v) : value(v) {}
+};
+
+template <typename T, typename Char, size_t N,
+ fmt::detail_exported::fixed_string<Char, N> Str>
+struct is_named_arg<statically_named_arg<T, Char, N, Str>> : std::true_type {};
+
+template <typename T, typename Char, size_t N,
+ fmt::detail_exported::fixed_string<Char, N> Str>
+struct is_statically_named_arg<statically_named_arg<T, Char, N, Str>>
+ : std::true_type {};
+
+template <typename Char, size_t N,
+ fmt::detail_exported::fixed_string<Char, N> Str>
+struct udl_arg {
+ template <typename T> auto operator=(T&& value) const {
+ return statically_named_arg<T, Char, N, Str>(std::forward<T>(value));
+ }
+};
+# else
+template <typename Char> struct udl_arg {
+ const Char* str;
+
+ template <typename T> auto operator=(T&& value) const -> named_arg<Char, T> {
+ return {str, std::forward<T>(value)};
+ }
+};
+# endif
+#endif // FMT_USE_USER_DEFINED_LITERALS
+
+template <typename Locale, typename Char>
+auto vformat(const Locale& loc, basic_string_view<Char> format_str,
+ basic_format_args<buffer_context<type_identity_t<Char>>> args)
+ -> std::basic_string<Char> {
+ basic_memory_buffer<Char> buffer;
+ detail::vformat_to(buffer, format_str, args, detail::locale_ref(loc));
+ return {buffer.data(), buffer.size()};
+}
+
using format_func = void (*)(detail::buffer<char>&, int, const char*);
FMT_API void format_error_code(buffer<char>& out, int error_code,
@@ -2533,20 +2217,15 @@ FMT_API void format_error_code(buffer<char>& out, int error_code,
FMT_API void report_error(format_func func, int error_code,
const char* message) FMT_NOEXCEPT;
-
FMT_END_DETAIL_NAMESPACE
-template <typename OutputIt, typename Char>
-using arg_formatter FMT_DEPRECATED_ALIAS =
- detail::arg_formatter<OutputIt, Char>;
-
-FMT_API std::system_error vsystem_error(int error_code, string_view format_str,
- format_args args);
+FMT_API auto vsystem_error(int error_code, string_view format_str,
+ format_args args) -> std::system_error;
/**
\rst
Constructs :class:`std::system_error` with a message formatted with
- ``fmt::format(message, args...)``.
+ ``fmt::format(fmt, args...)``.
*error_code* is a system error code as given by ``errno``.
**Example**::
@@ -2560,10 +2239,10 @@ FMT_API std::system_error vsystem_error(int error_code, string_view format_str,
throw fmt::system_error(errno, "cannot open file '{}'", filename);
\endrst
*/
-template <typename... Args>
-std::system_error system_error(int error_code, string_view message,
- const Args&... args) {
- return vsystem_error(error_code, message, make_format_args(args...));
+template <typename... T>
+auto system_error(int error_code, format_string<T...> fmt, T&&... args)
+ -> std::system_error {
+ return vsystem_error(error_code, fmt, fmt::make_format_args(args...));
}
/**
@@ -2599,12 +2278,12 @@ class format_int {
mutable char buffer_[buffer_size];
char* str_;
- template <typename UInt> char* format_unsigned(UInt value) {
+ template <typename UInt> auto format_unsigned(UInt value) -> char* {
auto n = static_cast<detail::uint32_or_64_or_128_t<UInt>>(value);
return detail::format_decimal(buffer_, n, buffer_size - 1).begin;
}
- template <typename Int> char* format_signed(Int value) {
+ template <typename Int> auto format_signed(Int value) -> char* {
auto abs_value = static_cast<detail::uint32_or_64_or_128_t<Int>>(value);
bool negative = value < 0;
if (negative) abs_value = 0 - abs_value;
@@ -2623,7 +2302,7 @@ class format_int {
: str_(format_unsigned(value)) {}
/** Returns the number of characters written to the output buffer. */
- size_t size() const {
+ auto size() const -> size_t {
return detail::to_unsigned(buffer_ - str_ + buffer_size - 1);
}
@@ -2631,13 +2310,13 @@ class format_int {
Returns a pointer to the output buffer content. No terminating null
character is appended.
*/
- const char* data() const { return str_; }
+ auto data() const -> const char* { return str_; }
/**
Returns a pointer to the output buffer content with terminating null
character appended.
*/
- const char* c_str() const {
+ auto c_str() const -> const char* {
buffer_[buffer_size - 1] = '\0';
return str_;
}
@@ -2647,102 +2326,28 @@ class format_int {
Returns the content of the output buffer as an ``std::string``.
\endrst
*/
- std::string str() const { return std::string(str_, size()); }
+ auto str() const -> std::string { return std::string(str_, size()); }
};
-// A formatter specialization for the core types corresponding to detail::type
-// constants.
template <typename T, typename Char>
-struct formatter<T, Char,
- enable_if_t<detail::type_constant<T, Char>::value !=
- detail::type::custom_type>> {
- FMT_CONSTEXPR formatter() = default;
-
- // Parses format specifiers stopping either at the end of the range or at the
- // terminating '}'.
- template <typename ParseContext>
- FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
- auto begin = ctx.begin(), end = ctx.end();
- if (begin == end) return begin;
- using handler_type = detail::dynamic_specs_handler<ParseContext>;
- auto type = detail::type_constant<T, Char>::value;
- detail::specs_checker<handler_type> handler(handler_type(specs_, ctx),
- type);
- auto it = detail::parse_format_specs(begin, end, handler);
- auto eh = ctx.error_handler();
- switch (type) {
- case detail::type::none_type:
- FMT_ASSERT(false, "invalid argument type");
- break;
- case detail::type::bool_type:
- if (!specs_.type || specs_.type == 's') break;
- FMT_FALLTHROUGH;
- 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::int128_type:
- case detail::type::uint128_type:
- detail::check_int_type_spec(specs_.type, eh);
- break;
- case detail::type::char_type:
- detail::handle_char_specs(
- specs_, detail::char_specs_checker<decltype(eh)>(specs_.type, eh));
- break;
- case detail::type::float_type:
- if (detail::const_check(FMT_USE_FLOAT))
- detail::parse_float_type_spec(specs_, eh);
- else
- FMT_ASSERT(false, "float support disabled");
- break;
- case detail::type::double_type:
- if (detail::const_check(FMT_USE_DOUBLE))
- detail::parse_float_type_spec(specs_, eh);
- else
- FMT_ASSERT(false, "double support disabled");
- break;
- case detail::type::long_double_type:
- if (detail::const_check(FMT_USE_LONG_DOUBLE))
- detail::parse_float_type_spec(specs_, eh);
- else
- FMT_ASSERT(false, "long double support disabled");
- break;
- case detail::type::cstring_type:
- detail::handle_cstring_type_spec(
- specs_.type, detail::cstring_type_checker<decltype(eh)>(eh));
- break;
- case detail::type::string_type:
- detail::check_string_type_spec(specs_.type, eh);
- break;
- case detail::type::pointer_type:
- detail::check_pointer_type_spec(specs_.type, eh);
- break;
- case detail::type::custom_type:
- // Custom format specifiers should be checked in parse functions of
- // formatter specializations.
- break;
- }
- return it;
- }
-
- template <typename FormatContext>
- FMT_CONSTEXPR FMT_INLINE auto format(const T& val, FormatContext& ctx) const
- -> decltype(ctx.out()) {
- if (specs_.width_ref.kind != detail::arg_id_kind::none ||
- specs_.precision_ref.kind != detail::arg_id_kind::none) {
- auto specs = specs_;
- detail::handle_dynamic_spec<detail::width_checker>(specs.width,
- specs.width_ref, ctx);
- detail::handle_dynamic_spec<detail::precision_checker>(
- specs.precision, specs.precision_ref, ctx);
- return detail::write<Char>(ctx.out(), val, specs, ctx.locale());
- }
- return detail::write<Char>(ctx.out(), val, specs_, ctx.locale());
+template <typename FormatContext>
+FMT_CONSTEXPR FMT_INLINE auto
+formatter<T, Char,
+ enable_if_t<detail::type_constant<T, Char>::value !=
+ detail::type::custom_type>>::format(const T& val,
+ FormatContext& ctx)
+ const -> decltype(ctx.out()) {
+ if (specs_.width_ref.kind != detail::arg_id_kind::none ||
+ specs_.precision_ref.kind != detail::arg_id_kind::none) {
+ auto specs = specs_;
+ detail::handle_dynamic_spec<detail::width_checker>(specs.width,
+ specs.width_ref, ctx);
+ detail::handle_dynamic_spec<detail::precision_checker>(
+ specs.precision, specs.precision_ref, ctx);
+ return detail::write<Char>(ctx.out(), val, specs, ctx.locale());
}
-
- private:
- detail::dynamic_format_specs<Char> specs_;
-};
+ return detail::write<Char>(ctx.out(), val, specs_, ctx.locale());
+}
#define FMT_FORMAT_AS(Type, Base) \
template <typename Char> \
@@ -2796,14 +2401,22 @@ struct formatter<Char[N], Char> : formatter<basic_string_view<Char>, Char> {
// };
template <typename Char = char> class dynamic_formatter {
private:
+ detail::dynamic_format_specs<Char> specs_;
+ const Char* format_str_;
+
struct null_handler : detail::error_handler {
void on_align(align_t) {}
- void on_plus() {}
- void on_minus() {}
- void on_space() {}
+ void on_sign(sign_t) {}
void on_hash() {}
};
+ template <typename Context> void handle_specs(Context& ctx) {
+ detail::handle_dynamic_spec<detail::width_checker>(specs_.width,
+ specs_.width_ref, ctx);
+ detail::handle_dynamic_spec<detail::precision_checker>(
+ specs_.precision, specs_.precision_ref, ctx);
+ }
+
public:
template <typename ParseContext>
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
@@ -2819,45 +2432,13 @@ template <typename Char = char> class dynamic_formatter {
detail::specs_checker<null_handler> checker(
null_handler(), detail::mapped_type_constant<T, FormatContext>::value);
checker.on_align(specs_.align);
- switch (specs_.sign) {
- case sign::none:
- break;
- case sign::plus:
- checker.on_plus();
- break;
- case sign::minus:
- checker.on_minus();
- break;
- case sign::space:
- checker.on_space();
- break;
- }
+ if (specs_.sign != sign::none) checker.on_sign(specs_.sign);
if (specs_.alt) checker.on_hash();
if (specs_.precision >= 0) checker.end_precision();
- using af = detail::arg_formatter<typename FormatContext::iterator,
- typename FormatContext::char_type>;
- visit_format_arg(af(ctx, specs_), detail::make_arg<FormatContext>(val));
- return ctx.out();
- }
-
- private:
- template <typename Context> void handle_specs(Context& ctx) {
- detail::handle_dynamic_spec<detail::width_checker>(specs_.width,
- specs_.width_ref, ctx);
- detail::handle_dynamic_spec<detail::precision_checker>(
- specs_.precision, specs_.precision_ref, ctx);
+ return detail::write<Char>(ctx.out(), val, specs_, ctx.locale());
}
-
- detail::dynamic_format_specs<Char> specs_;
- const Char* format_str_;
};
-template <typename Char, typename ErrorHandler>
-FMT_CONSTEXPR void advance_to(
- basic_format_parse_context<Char, ErrorHandler>& ctx, const Char* p) {
- ctx.advance_to(ctx.begin() + (p - &*ctx.begin()));
-}
-
/**
\rst
Converts ``p`` to ``const void*`` for pointer formatting.
@@ -2867,14 +2448,14 @@ FMT_CONSTEXPR void advance_to(
auto s = fmt::format("{}", fmt::ptr(p));
\endrst
*/
-template <typename T> const void* ptr(T p) {
+template <typename T> auto ptr(T p) -> const void* {
static_assert(std::is_pointer<T>::value, "");
return detail::bit_cast<const void*>(p);
}
-template <typename T> const void* ptr(const std::unique_ptr<T>& p) {
+template <typename T> auto ptr(const std::unique_ptr<T>& p) -> const void* {
return p.get();
}
-template <typename T> const void* ptr(const std::shared_ptr<T>& p) {
+template <typename T> auto ptr(const std::shared_ptr<T>& p) -> const void* {
return p.get();
}
@@ -2912,18 +2493,21 @@ template <> struct formatter<bytes> {
}
};
-template <typename It, typename Sentinel, typename Char>
-struct arg_join : detail::view {
+template <typename It, typename Sentinel, typename Char = char>
+struct join_view : detail::view {
It begin;
Sentinel end;
basic_string_view<Char> sep;
- arg_join(It b, Sentinel e, basic_string_view<Char> s)
+ join_view(It b, Sentinel e, basic_string_view<Char> s)
: begin(b), end(e), sep(s) {}
};
template <typename It, typename Sentinel, typename Char>
-struct formatter<arg_join<It, Sentinel, Char>, Char> {
+using arg_join FMT_DEPRECATED_ALIAS = join_view<It, Sentinel, Char>;
+
+template <typename It, typename Sentinel, typename Char>
+struct formatter<join_view<It, Sentinel, Char>, Char> {
private:
using value_type = typename std::iterator_traits<It>::value_type;
using context = buffer_context<Char>;
@@ -2939,9 +2523,9 @@ struct formatter<arg_join<It, Sentinel, Char>, Char> {
}
using formatter_type =
- conditional_t<is_formattable<value_type>::value,
- formatter<remove_cvref_t<decltype(
- map(std::declval<const value_type&>()))>,
+ conditional_t<is_formattable<value_type, Char>::value,
+ formatter<remove_cvref_t<decltype(map(
+ std::declval<const value_type&>()))>,
Char>,
detail::fallback_formatter<value_type, Char>>;
@@ -2954,7 +2538,7 @@ struct formatter<arg_join<It, Sentinel, Char>, Char> {
}
template <typename FormatContext>
- auto format(const arg_join<It, Sentinel, Char>& value, FormatContext& ctx)
+ auto format(const join_view<It, Sentinel, Char>& value, FormatContext& ctx)
-> decltype(ctx.out()) {
auto it = value.begin;
auto out = ctx.out();
@@ -2971,16 +2555,11 @@ struct formatter<arg_join<It, Sentinel, Char>, Char> {
};
/**
- Returns an object that formats the iterator range `[begin, end)` with elements
- separated by `sep`.
+ Returns an object that formats the iterator range `[begin, end)` with
+ elements separated by `sep`.
*/
template <typename It, typename Sentinel>
-arg_join<It, Sentinel, char> join(It begin, Sentinel end, string_view sep) {
- return {begin, end, sep};
-}
-
-template <typename It, typename Sentinel>
-arg_join<It, Sentinel, wchar_t> join(It begin, Sentinel end, wstring_view sep) {
+auto join(It begin, Sentinel end, string_view sep) -> join_view<It, Sentinel> {
return {begin, end, sep};
}
@@ -3001,14 +2580,8 @@ arg_join<It, Sentinel, wchar_t> join(It begin, Sentinel end, wstring_view sep) {
\endrst
*/
template <typename Range>
-arg_join<detail::iterator_t<Range>, detail::sentinel_t<Range>, char> join(
- Range&& range, string_view sep) {
- return join(std::begin(range), std::end(range), sep);
-}
-
-template <typename Range>
-arg_join<detail::iterator_t<Range>, detail::sentinel_t<Range>, wchar_t> join(
- Range&& range, wstring_view sep) {
+auto join(Range&& range, string_view sep)
+ -> join_view<detail::iterator_t<Range>, detail::sentinel_t<Range>> {
return join(std::begin(range), std::end(range), sep);
}
@@ -3024,231 +2597,165 @@ arg_join<detail::iterator_t<Range>, detail::sentinel_t<Range>, wchar_t> join(
\endrst
*/
template <typename T, FMT_ENABLE_IF(!std::is_integral<T>::value)>
-inline std::string to_string(const T& value) {
- std::string result;
+inline auto to_string(const T& value) -> std::string {
+ auto result = std::string();
detail::write<char>(std::back_inserter(result), value);
return result;
}
template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
-inline std::string to_string(T value) {
- // The buffer should be large enough to store the number including the sign or
- // "false" for bool.
+inline auto to_string(T value) -> std::string {
+ // The buffer should be large enough to store the number including the sign
+ // or "false" for bool.
constexpr int max_size = detail::digits10<T>() + 2;
char buffer[max_size > 5 ? static_cast<unsigned>(max_size) : 5];
char* begin = buffer;
return std::string(begin, detail::write<char>(begin, value));
}
-/**
- Converts *value* to ``std::wstring`` using the default format for type *T*.
- */
-template <typename T> inline std::wstring to_wstring(const T& value) {
- return format(FMT_STRING(L"{}"), value);
-}
-
template <typename Char, size_t SIZE>
-std::basic_string<Char> to_string(const basic_memory_buffer<Char, SIZE>& buf) {
+auto to_string(const basic_memory_buffer<Char, SIZE>& buf)
+ -> std::basic_string<Char> {
auto size = buf.size();
detail::assume(size < std::basic_string<Char>().max_size());
return std::basic_string<Char>(buf.data(), size);
}
-FMT_MODULE_EXPORT_END
+FMT_BEGIN_DETAIL_NAMESPACE
template <typename Char>
-void detail::vformat_to(
- detail::buffer<Char>& buf, basic_string_view<Char> format_str,
- basic_format_args<buffer_context<type_identity_t<Char>>> args,
- detail::locale_ref loc) {
- using iterator = typename buffer_context<Char>::iterator;
+void vformat_to(
+ buffer<Char>& buf, basic_string_view<Char> fmt,
+ basic_format_args<FMT_BUFFER_CONTEXT(type_identity_t<Char>)> args,
+ locale_ref loc) {
+ // workaround for msvc bug regarding name-lookup in module
+ // link names into function scope
+ using detail::arg_formatter;
+ using detail::buffer_appender;
+ using detail::custom_formatter;
+ using detail::default_arg_formatter;
+ using detail::get_arg;
+ using detail::locale_ref;
+ using detail::parse_format_specs;
+ using detail::specs_checker;
+ using detail::specs_handler;
+ using detail::to_unsigned;
+ using detail::type;
+ using detail::write;
auto out = buffer_appender<Char>(buf);
- if (format_str.size() == 2 && equal2(format_str.data(), "{}")) {
+ if (fmt.size() == 2 && equal2(fmt.data(), "{}")) {
auto arg = args.get(0);
if (!arg) error_handler().on_error("argument not found");
- visit_format_arg(default_arg_formatter<iterator, Char>{out, args, loc},
- arg);
+ visit_format_arg(default_arg_formatter<Char>{out, args, loc}, arg);
return;
}
- format_handler<iterator, Char, buffer_context<Char>> h(out, format_str, args,
- loc);
- parse_format_string<false>(format_str, h);
-}
-
-#ifndef FMT_HEADER_ONLY
-extern template void detail::vformat_to(detail::buffer<char>&, string_view,
- basic_format_args<format_context>,
- detail::locale_ref);
-namespace detail {
-
-extern template FMT_API std::string grouping_impl<char>(locale_ref loc);
-extern template FMT_API std::string grouping_impl<wchar_t>(locale_ref loc);
-extern template FMT_API char thousands_sep_impl<char>(locale_ref loc);
-extern template FMT_API wchar_t thousands_sep_impl<wchar_t>(locale_ref loc);
-extern template FMT_API char decimal_point_impl(locale_ref loc);
-extern template FMT_API wchar_t decimal_point_impl(locale_ref loc);
-extern template int format_float<double>(double value, int precision,
- float_specs specs, buffer<char>& buf);
-extern template int format_float<long double>(long double value, int precision,
- float_specs specs,
- buffer<char>& buf);
-int snprintf_float(float value, int precision, float_specs specs,
- buffer<char>& buf) = delete;
-extern template int snprintf_float<double>(double value, int precision,
- float_specs specs,
- buffer<char>& buf);
-extern template int snprintf_float<long double>(long double value,
- int precision,
- float_specs specs,
- buffer<char>& buf);
-} // namespace detail
-#endif
-
-FMT_MODULE_EXPORT_BEGIN
-
-template <typename S, typename Char = char_t<S>,
- FMT_ENABLE_IF(detail::is_string<S>::value)>
-inline void vformat_to(
- detail::buffer<Char>& buf, const S& format_str,
- basic_format_args<FMT_BUFFER_CONTEXT(type_identity_t<Char>)> args) {
- return detail::vformat_to(buf, to_string_view(format_str), args);
-}
-
-template <typename S, typename... Args, size_t SIZE = inline_buffer_size,
- typename Char = enable_if_t<detail::is_string<S>::value, char_t<S>>>
-inline typename buffer_context<Char>::iterator format_to(
- basic_memory_buffer<Char, SIZE>& buf, const S& format_str, Args&&... args) {
- const auto& vargs = fmt::make_args_checked<Args...>(format_str, args...);
- detail::vformat_to(buf, to_string_view(format_str), vargs);
- return detail::buffer_appender<Char>(buf);
-}
-template <typename OutputIt, typename Char = char>
-using format_context_t = basic_format_context<OutputIt, Char>;
+ struct format_handler : error_handler {
+ basic_format_parse_context<Char> parse_context;
+ buffer_context<Char> context;
-template <typename OutputIt, typename Char = char>
-using format_args_t = basic_format_args<format_context_t<OutputIt, Char>>;
+ format_handler(buffer_appender<Char> out, basic_string_view<Char> str,
+ basic_format_args<buffer_context<Char>> args, locale_ref loc)
+ : parse_context(str), context(out, args, loc) {}
-template <typename OutputIt, typename Char = typename OutputIt::value_type>
-using format_to_n_context FMT_DEPRECATED_ALIAS = buffer_context<Char>;
-
-template <typename OutputIt, typename Char = typename OutputIt::value_type>
-using format_to_n_args FMT_DEPRECATED_ALIAS =
- basic_format_args<buffer_context<Char>>;
-
-template <typename OutputIt, typename Char, typename... Args>
-FMT_DEPRECATED format_arg_store<buffer_context<Char>, Args...>
-make_format_to_n_args(const Args&... args) {
- return format_arg_store<buffer_context<Char>, Args...>(args...);
-}
-
-#if FMT_COMPILE_TIME_CHECKS
-template <typename... Args> struct format_string {
- string_view str;
-
- template <size_t N> consteval format_string(const char (&s)[N]) : str(s) {
- if constexpr (detail::count_named_args<Args...>() == 0) {
- using checker = detail::format_string_checker<char, detail::error_handler,
- remove_cvref_t<Args>...>;
- detail::parse_format_string<true>(string_view(s, N), checker(s, {}));
+ void on_text(const Char* begin, const Char* end) {
+ auto text = basic_string_view<Char>(begin, to_unsigned(end - begin));
+ context.advance_to(write<Char>(context.out(), text));
}
- }
-
- template <typename T,
- FMT_ENABLE_IF(std::is_constructible_v<string_view, const T&>)>
- format_string(const T& s) : str(s) {}
-};
-template <typename... Args>
-FMT_INLINE std::string format(
- format_string<std::type_identity_t<Args>...> format_str, Args&&... args) {
- return detail::vformat(format_str.str, make_format_args(args...));
-}
-#endif
-
-template <typename Char, enable_if_t<(!std::is_same<Char, char>::value), int>>
-std::basic_string<Char> detail::vformat(
- basic_string_view<Char> format_str,
- basic_format_args<buffer_context<type_identity_t<Char>>> args) {
- basic_memory_buffer<Char> buffer;
- detail::vformat_to(buffer, format_str, args);
- return to_string(buffer);
-}
+ FMT_CONSTEXPR auto on_arg_id() -> int {
+ return parse_context.next_arg_id();
+ }
+ FMT_CONSTEXPR auto on_arg_id(int id) -> int {
+ return parse_context.check_arg_id(id), id;
+ }
+ FMT_CONSTEXPR auto on_arg_id(basic_string_view<Char> id) -> int {
+ int arg_id = context.arg_id(id);
+ if (arg_id < 0) on_error("argument not found");
+ return arg_id;
+ }
-template <typename Char, FMT_ENABLE_IF(std::is_same<Char, wchar_t>::value)>
-void vprint(std::FILE* f, basic_string_view<Char> format_str,
- wformat_args args) {
- wmemory_buffer buffer;
- detail::vformat_to(buffer, format_str, args);
- buffer.push_back(L'\0');
- if (std::fputws(buffer.data(), f) == -1)
- FMT_THROW(system_error(errno, "cannot write to file"));
-}
+ FMT_INLINE void on_replacement_field(int id, const Char*) {
+ auto arg = get_arg(context, id);
+ context.advance_to(visit_format_arg(
+ default_arg_formatter<Char>{context.out(), context.args(),
+ context.locale()},
+ arg));
+ }
-template <typename Char, FMT_ENABLE_IF(std::is_same<Char, wchar_t>::value)>
-void vprint(basic_string_view<Char> format_str, wformat_args args) {
- vprint(stdout, format_str, args);
+ auto on_format_specs(int id, const Char* begin, const Char* end)
+ -> const Char* {
+ auto arg = get_arg(context, id);
+ if (arg.type() == type::custom_type) {
+ parse_context.advance_to(parse_context.begin() +
+ (begin - &*parse_context.begin()));
+ visit_format_arg(custom_formatter<Char>{parse_context, context}, arg);
+ return parse_context.begin();
+ }
+ auto specs = basic_format_specs<Char>();
+ specs_checker<specs_handler<Char>> handler(
+ specs_handler<Char>(specs, parse_context, context), arg.type());
+ begin = parse_format_specs(begin, end, handler);
+ if (begin == end || *begin != '}')
+ on_error("missing '}' in format string");
+ auto f = arg_formatter<Char>{context.out(), specs, context.locale()};
+ context.advance_to(visit_format_arg(f, arg));
+ return begin;
+ }
+ };
+ detail::parse_format_string<false>(fmt, format_handler(out, fmt, args, loc));
}
-FMT_MODULE_EXPORT_END
+#ifndef FMT_HEADER_ONLY
+extern template FMT_API auto thousands_sep_impl<char>(locale_ref)
+ -> thousands_sep_result<char>;
+extern template FMT_API auto thousands_sep_impl<wchar_t>(locale_ref)
+ -> thousands_sep_result<wchar_t>;
+extern template FMT_API auto decimal_point_impl(locale_ref) -> char;
+extern template FMT_API auto decimal_point_impl(locale_ref) -> wchar_t;
+extern template auto format_float<double>(double value, int precision,
+ float_specs specs, buffer<char>& buf)
+ -> int;
+extern template auto format_float<long double>(long double value, int precision,
+ float_specs specs,
+ buffer<char>& buf) -> int;
+void snprintf_float(float, int, float_specs, buffer<char>&) = delete;
+extern template auto snprintf_float<double>(double value, int precision,
+ float_specs specs,
+ buffer<char>& buf) -> int;
+extern template auto snprintf_float<long double>(long double value,
+ int precision,
+ float_specs specs,
+ buffer<char>& buf) -> int;
+#endif // FMT_HEADER_ONLY
-#if FMT_USE_NONTYPE_TEMPLATE_PARAMETERS
-namespace detail {
-template <typename Char, size_t N> struct fixed_string {
- constexpr fixed_string(const Char (&str)[N]) {
- copy_str<Char, const Char*, Char*>(static_cast<const Char*>(str), str + N,
- data);
- }
- Char data[N]{};
-};
-} // namespace detail
-#endif
+FMT_END_DETAIL_NAMESPACE
#if FMT_USE_USER_DEFINED_LITERALS
-namespace detail {
-template <typename Char> struct udl_formatter {
- basic_string_view<Char> str;
+inline namespace literals {
+/**
+ \rst
+ User-defined literal equivalent of :func:`fmt::arg`.
- template <typename... Args>
- std::basic_string<Char> operator()(Args&&... args) const {
- return format(str, std::forward<Args>(args)...);
- }
-};
+ **Example**::
+ using namespace fmt::literals;
+ fmt::print("Elapsed time: {s:.2f} seconds", "s"_a=1.23);
+ \endrst
+ */
# if FMT_USE_NONTYPE_TEMPLATE_PARAMETERS
-template <typename T, typename Char, size_t N, fixed_string<Char, N> Str>
-struct statically_named_arg : view {
- static constexpr auto name = Str.data;
-
- const T& value;
- statically_named_arg(const T& v) : value(v) {}
-};
-
-template <typename T, typename Char, size_t N, fixed_string<Char, N> Str>
-struct is_named_arg<statically_named_arg<T, Char, N, Str>> : std::true_type {};
-
-template <typename T, typename Char, size_t N, fixed_string<Char, N> Str>
-struct is_statically_named_arg<statically_named_arg<T, Char, N, Str>>
- : std::true_type {};
-
-template <typename Char, size_t N, fixed_string<Char, N> Str> struct udl_arg {
- template <typename T> auto operator=(T&& value) const {
- return statically_named_arg<T, Char, N, Str>(std::forward<T>(value));
- }
-};
+template <detail_exported::fixed_string Str>
+constexpr auto operator""_a()
+ -> detail::udl_arg<remove_cvref_t<decltype(Str.data[0])>,
+ sizeof(Str.data) / sizeof(decltype(Str.data[0])), Str> {
+ return {};
+}
# else
-template <typename Char> struct udl_arg {
- const Char* str;
-
- template <typename T> named_arg<Char, T> operator=(T&& value) const {
- return {str, std::forward<T>(value)};
- }
-};
+constexpr auto operator"" _a(const char* s, size_t) -> detail::udl_arg<char> {
+ return {s};
+}
# endif
-} // namespace detail
-FMT_MODULE_EXPORT_BEGIN
-inline namespace literals {
/**
\rst
User-defined literal equivalent of :func:`fmt::format`.
@@ -3259,46 +2766,60 @@ inline namespace literals {
std::string message = "The answer is {}"_format(42);
\endrst
*/
-constexpr detail::udl_formatter<char> operator"" _format(const char* s,
- size_t n) {
- return {{s, n}};
-}
-constexpr detail::udl_formatter<wchar_t> operator"" _format(const wchar_t* s,
- size_t n) {
+constexpr auto operator"" _format(const char* s, size_t n)
+ -> detail::udl_formatter<char> {
return {{s, n}};
}
+} // namespace literals
+#endif // FMT_USE_USER_DEFINED_LITERALS
-/**
- \rst
- User-defined literal equivalent of :func:`fmt::arg`.
+template <typename Locale, FMT_ENABLE_IF(detail::is_locale<Locale>::value)>
+inline auto vformat(const Locale& loc, string_view fmt, format_args args)
+ -> std::string {
+ return detail::vformat(loc, fmt, args);
+}
- **Example**::
+template <typename Locale, typename... T,
+ FMT_ENABLE_IF(detail::is_locale<Locale>::value)>
+inline auto format(const Locale& loc, format_string<T...> fmt, T&&... args)
+ -> std::string {
+ return vformat(loc, string_view(fmt), fmt::make_format_args(args...));
+}
- using namespace fmt::literals;
- fmt::print("Elapsed time: {s:.2f} seconds", "s"_a=1.23);
- \endrst
- */
-# if FMT_USE_NONTYPE_TEMPLATE_PARAMETERS
-template <detail::fixed_string Str>
-constexpr detail::udl_arg<remove_cvref_t<decltype(Str.data[0])>,
- sizeof(Str.data) / sizeof(decltype(Str.data[0])), Str>
-operator""_a() {
- return {};
+template <typename... T, size_t SIZE, typename Allocator>
+FMT_DEPRECATED auto format_to(basic_memory_buffer<char, SIZE, Allocator>& buf,
+ format_string<T...> fmt, T&&... args)
+ -> appender {
+ detail::vformat_to(buf, string_view(fmt), fmt::make_format_args(args...));
+ return appender(buf);
}
-# else
-constexpr detail::udl_arg<char> operator"" _a(const char* s, size_t) {
- return {s};
+
+template <typename OutputIt, typename Locale,
+ FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, char>::value&&
+ detail::is_locale<Locale>::value)>
+auto vformat_to(OutputIt out, const Locale& loc, string_view fmt,
+ format_args args) -> OutputIt {
+ using detail::get_buffer;
+ auto&& buf = get_buffer<char>(out);
+ detail::vformat_to(buf, fmt, args, detail::locale_ref(loc));
+ return detail::get_iterator(buf);
}
-constexpr detail::udl_arg<wchar_t> operator"" _a(const wchar_t* s, size_t) {
- return {s};
+
+template <typename OutputIt, typename Locale, typename... T,
+ FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, char>::value&&
+ detail::is_locale<Locale>::value)>
+FMT_INLINE auto format_to(OutputIt out, const Locale& loc,
+ format_string<T...> fmt, T&&... args) -> OutputIt {
+ return vformat_to(out, loc, fmt, fmt::make_format_args(args...));
}
-# endif
-} // namespace literals
FMT_MODULE_EXPORT_END
-#endif // FMT_USE_USER_DEFINED_LITERALS
FMT_END_NAMESPACE
+#ifdef FMT_DEPRECATED_INCLUDE_XCHAR
+# include "xchar.h"
+#endif
+
#ifdef FMT_HEADER_ONLY
# define FMT_FUNC inline
# include "format-inl.h"
diff --git a/deps/fmt/include/fmt/locale.h b/deps/fmt/include/fmt/locale.h
index e79140a1a1..7571b5261b 100644
--- a/deps/fmt/include/fmt/locale.h
+++ b/deps/fmt/include/fmt/locale.h
@@ -1,67 +1,2 @@
-// Formatting library for C++ - std::locale support
-//
-// Copyright (c) 2012 - present, Victor Zverovich
-// All rights reserved.
-//
-// For the license information refer to format.h.
-
-#ifndef FMT_LOCALE_H_
-#define FMT_LOCALE_H_
-
-#include <locale>
-
-#include "format.h"
-
-FMT_BEGIN_NAMESPACE
-
-namespace detail {
-template <typename Char>
-std::basic_string<Char> vformat(
- const std::locale& loc, basic_string_view<Char> format_str,
- basic_format_args<buffer_context<type_identity_t<Char>>> args) {
- basic_memory_buffer<Char> buffer;
- detail::vformat_to(buffer, format_str, args, detail::locale_ref(loc));
- return fmt::to_string(buffer);
-}
-} // namespace detail
-
-FMT_MODULE_EXPORT_BEGIN
-
-template <typename S, typename Char = char_t<S>>
-inline std::basic_string<Char> vformat(
- const std::locale& loc, const S& format_str,
- basic_format_args<buffer_context<type_identity_t<Char>>> args) {
- return detail::vformat(loc, to_string_view(format_str), args);
-}
-
-template <typename S, typename... Args, typename Char = char_t<S>>
-inline std::basic_string<Char> format(const std::locale& loc,
- const S& format_str, Args&&... args) {
- return detail::vformat(loc, to_string_view(format_str),
- fmt::make_args_checked<Args...>(format_str, args...));
-}
-
-template <typename S, typename OutputIt, typename... Args,
- typename Char = char_t<S>,
- FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value)>
-inline OutputIt vformat_to(
- OutputIt out, const std::locale& loc, const S& format_str,
- basic_format_args<buffer_context<type_identity_t<Char>>> args) {
- decltype(detail::get_buffer<Char>(out)) buf(detail::get_buffer_init(out));
- vformat_to(buf, to_string_view(format_str), args, detail::locale_ref(loc));
- return detail::get_iterator(buf);
-}
-
-template <typename OutputIt, typename S, typename... Args,
- bool enable = detail::is_output_iterator<OutputIt, char_t<S>>::value>
-inline auto format_to(OutputIt out, const std::locale& loc, const S& format_str,
- Args&&... args) ->
- typename std::enable_if<enable, OutputIt>::type {
- const auto& vargs = fmt::make_args_checked<Args...>(format_str, args...);
- return vformat_to(out, loc, to_string_view(format_str), vargs);
-}
-
-FMT_MODULE_EXPORT_END
-FMT_END_NAMESPACE
-
-#endif // FMT_LOCALE_H_
+#include "xchar.h"
+#warning fmt/locale.h is deprecated, include fmt/format.h or fmt/xchar.h instead
diff --git a/deps/fmt/include/fmt/os.h b/deps/fmt/include/fmt/os.h
index 1a8833def4..f6c0f32985 100644
--- a/deps/fmt/include/fmt/os.h
+++ b/deps/fmt/include/fmt/os.h
@@ -70,6 +70,7 @@
#define FMT_RETRY(result, expression) FMT_RETRY_VAL(result, expression, -1)
FMT_BEGIN_NAMESPACE
+FMT_MODULE_EXPORT_BEGIN
/**
\rst
@@ -128,7 +129,8 @@ template <typename Char> struct formatter<std::error_code, Char> {
FMT_CONSTEXPR auto format(const std::error_code& ec, FormatContext& ctx) const
-> decltype(ctx.out()) {
auto out = ctx.out();
- out = detail::write<Char>(out, to_string_view(ec.category().name()));
+ out = detail::write_bytes(out, ec.category().name(),
+ basic_format_specs<Char>());
out = detail::write<Char>(out, Char(':'));
out = detail::write<Char>(out, ec.value());
return out;
@@ -138,7 +140,7 @@ template <typename Char> struct formatter<std::error_code, Char> {
#ifdef _WIN32
FMT_API const std::error_category& system_category() FMT_NOEXCEPT;
-namespace detail {
+FMT_BEGIN_DETAIL_NAMESPACE
// A converter from UTF-16 to UTF-8.
// It is only provided for Windows since other systems support UTF-8 natively.
class utf16_to_utf8 {
@@ -147,7 +149,7 @@ class utf16_to_utf8 {
public:
utf16_to_utf8() {}
- FMT_API explicit utf16_to_utf8(wstring_view s);
+ FMT_API explicit utf16_to_utf8(basic_string_view<wchar_t> s);
operator string_view() const { return string_view(&buffer_[0], size()); }
size_t size() const { return buffer_.size() - 1; }
const char* c_str() const { return &buffer_[0]; }
@@ -156,12 +158,12 @@ class utf16_to_utf8 {
// Performs conversion returning a system error code instead of
// throwing exception on conversion error. This method may still throw
// in case of memory allocation error.
- FMT_API int convert(wstring_view s);
+ FMT_API int convert(basic_string_view<wchar_t> s);
};
FMT_API void format_windows_error(buffer<char>& out, int error_code,
const char* message) FMT_NOEXCEPT;
-} // namespace detail
+FMT_END_DETAIL_NAMESPACE
FMT_API std::system_error vwindows_error(int error_code, string_view format_str,
format_args args);
@@ -197,7 +199,7 @@ FMT_API std::system_error vwindows_error(int error_code, string_view format_str,
template <typename... Args>
std::system_error windows_error(int error_code, string_view message,
const Args&... args) {
- return vwindows_error(error_code, message, make_format_args(args...));
+ return vwindows_error(error_code, message, fmt::make_format_args(args...));
}
// Reports a Windows error without throwing an exception.
@@ -268,7 +270,7 @@ class buffered_file {
template <typename... Args>
inline void print(string_view format_str, const Args&... args) {
- vprint(format_str, make_format_args(args...));
+ vprint(format_str, fmt::make_format_args(args...));
}
};
@@ -360,7 +362,7 @@ class file {
// Returns the memory page size.
long getpagesize();
-namespace detail {
+FMT_BEGIN_DETAIL_NAMESPACE
struct buffer_size {
buffer_size() = default;
@@ -389,12 +391,13 @@ struct ostream_params {
this->buffer_size = bs.value;
}
};
-} // namespace detail
-static constexpr detail::buffer_size buffer_size;
+FMT_END_DETAIL_NAMESPACE
+
+constexpr detail::buffer_size buffer_size;
/** A fast output stream which is not thread-safe. */
-class ostream final : private detail::buffer<char> {
+class FMT_API ostream final : private detail::buffer<char> {
private:
file file_;
@@ -404,7 +407,7 @@ class ostream final : private detail::buffer<char> {
clear();
}
- FMT_API void grow(size_t) override final;
+ void grow(size_t) override;
ostream(cstring_view path, const detail::ostream_params& params)
: file_(path, params.oflag) {
@@ -432,13 +435,12 @@ class ostream final : private detail::buffer<char> {
}
/**
- Formats ``args`` according to specifications in ``format_str`` and writes
- the output to the file.
+ Formats ``args`` according to specifications in ``fmt`` and writes the
+ output to the file.
*/
- template <typename S, typename... Args>
- void print(const S& format_str, Args&&... args) {
- format_to(detail::buffer_appender<char>(*this), format_str,
- std::forward<Args>(args)...);
+ template <typename... T> void print(format_string<T...> fmt, T&&... args) {
+ vformat_to(detail::buffer_appender<char>(*this), fmt,
+ fmt::make_format_args(args...));
}
};
@@ -507,6 +509,7 @@ class locale {
};
using Locale FMT_DEPRECATED_ALIAS = locale;
#endif // FMT_LOCALE
+FMT_MODULE_EXPORT_END
FMT_END_NAMESPACE
#endif // FMT_OS_H_
diff --git a/deps/fmt/include/fmt/printf.h b/deps/fmt/include/fmt/printf.h
index c65fe4049f..3a3cd15283 100644
--- a/deps/fmt/include/fmt/printf.h
+++ b/deps/fmt/include/fmt/printf.h
@@ -15,7 +15,49 @@
#include "format.h"
FMT_BEGIN_NAMESPACE
-namespace detail {
+FMT_MODULE_EXPORT_BEGIN
+
+template <typename T> struct printf_formatter { printf_formatter() = delete; };
+
+template <typename Char>
+class basic_printf_parse_context : public basic_format_parse_context<Char> {
+ using basic_format_parse_context<Char>::basic_format_parse_context;
+};
+
+template <typename OutputIt, typename Char> class basic_printf_context {
+ private:
+ OutputIt out_;
+ basic_format_args<basic_printf_context> args_;
+
+ public:
+ using char_type = Char;
+ using format_arg = basic_format_arg<basic_printf_context>;
+ using parse_context_type = basic_printf_parse_context<Char>;
+ template <typename T> using formatter_type = printf_formatter<T>;
+
+ /**
+ \rst
+ Constructs a ``printf_context`` object. References to the arguments are
+ stored in the context object so make sure they have appropriate lifetimes.
+ \endrst
+ */
+ basic_printf_context(OutputIt out,
+ basic_format_args<basic_printf_context> args)
+ : out_(out), args_(args) {}
+
+ OutputIt out() { return out_; }
+ void advance_to(OutputIt it) { out_ = it; }
+
+ detail::locale_ref locale() { return {}; }
+
+ format_arg arg(int id) const { return args_.get(id); }
+
+ FMT_CONSTEXPR void on_error(const char* message) {
+ detail::error_handler().on_error(message);
+ }
+};
+
+FMT_BEGIN_DETAIL_NAMESPACE
// Checks if a value fits in int - used to avoid warnings about comparing
// signed and unsigned integers.
@@ -179,65 +221,34 @@ template <typename Char> class printf_width_handler {
}
};
-template <typename Char, typename Context>
-void vprintf(buffer<Char>& buf, basic_string_view<Char> format,
- basic_format_args<Context> args) {
- Context(buffer_appender<Char>(buf), format, args).format();
-}
-} // namespace detail
-
-// For printing into memory_buffer.
-template <typename Char, typename Context>
-FMT_DEPRECATED void printf(detail::buffer<Char>& buf,
- basic_string_view<Char> format,
- basic_format_args<Context> args) {
- return detail::vprintf(buf, format, args);
-}
-using detail::vprintf;
-
-FMT_MODULE_EXPORT_BEGIN
-
-template <typename Char>
-class basic_printf_parse_context : public basic_format_parse_context<Char> {
- using basic_format_parse_context<Char>::basic_format_parse_context;
-};
-template <typename OutputIt, typename Char> class basic_printf_context;
-
-FMT_MODULE_EXPORT_END
-
-/**
- \rst
- The ``printf`` argument formatter.
- \endrst
- */
+// The ``printf`` argument formatter.
template <typename OutputIt, typename Char>
-class printf_arg_formatter : public detail::arg_formatter_base<OutputIt, Char> {
+class printf_arg_formatter : public arg_formatter<Char> {
private:
- using base = detail::arg_formatter_base<OutputIt, Char>;
+ using base = arg_formatter<Char>;
using context_type = basic_printf_context<OutputIt, Char>;
- using format_specs = typename base::format_specs;
+ using format_specs = basic_format_specs<Char>;
context_type& context_;
OutputIt write_null_pointer(bool is_string = false) {
- auto s = this->specs();
+ auto s = this->specs;
s.type = 0;
- return detail::write(this->out(),
- string_view(is_string ? "(null)" : "(nil)"), s);
+ return write_bytes(this->out, is_string ? "(null)" : "(nil)", s);
}
public:
- printf_arg_formatter(OutputIt iter, format_specs& specs, context_type& ctx)
- : base(iter, specs, detail::locale_ref()), context_(ctx) {}
+ printf_arg_formatter(OutputIt iter, format_specs& s, context_type& ctx)
+ : base{iter, s, locale_ref()}, context_(ctx) {}
OutputIt operator()(monostate value) { return base::operator()(value); }
- template <typename T, FMT_ENABLE_IF(fmt::detail::is_integral<T>::value)>
+ template <typename T, FMT_ENABLE_IF(detail::is_integral<T>::value)>
OutputIt operator()(T value) {
// MSVC2013 fails to compile separate overloads for bool and Char so use
// std::is_same instead.
if (std::is_same<T, Char>::value) {
- format_specs fmt_specs = this->specs();
+ format_specs fmt_specs = this->specs;
if (fmt_specs.type && fmt_specs.type != 'c')
return (*this)(static_cast<int>(value));
fmt_specs.sign = sign::none;
@@ -247,8 +258,7 @@ class printf_arg_formatter : public detail::arg_formatter_base<OutputIt, Char> {
// ignored for non-numeric types
if (fmt_specs.align == align::none || fmt_specs.align == align::numeric)
fmt_specs.align = align::right;
- return detail::write<Char>(this->out(), static_cast<Char>(value),
- fmt_specs);
+ return write<Char>(this->out, static_cast<Char>(value), fmt_specs);
}
return base::operator()(value);
}
@@ -261,13 +271,13 @@ class printf_arg_formatter : public detail::arg_formatter_base<OutputIt, Char> {
/** Formats a null-terminated C string. */
OutputIt operator()(const char* value) {
if (value) return base::operator()(value);
- return write_null_pointer(this->specs().type != 'p');
+ return write_null_pointer(this->specs.type != 'p');
}
/** Formats a null-terminated wide C string. */
OutputIt operator()(const wchar_t* value) {
if (value) return base::operator()(value);
- return write_null_pointer(this->specs().type != 'p');
+ return write_null_pointer(this->specs.type != 'p');
}
OutputIt operator()(basic_string_view<Char> value) {
@@ -281,87 +291,16 @@ class printf_arg_formatter : public detail::arg_formatter_base<OutputIt, Char> {
/** Formats an argument of a custom (user-defined) type. */
OutputIt operator()(typename basic_format_arg<context_type>::handle handle) {
- handle.format(context_.parse_context(), context_);
- return this->out();
- }
-};
-
-template <typename T> struct printf_formatter {
- printf_formatter() = delete;
-
- template <typename ParseContext>
- auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
- return ctx.begin();
- }
-
- template <typename FormatContext>
- auto format(const T&, FormatContext& ctx) -> decltype(ctx.out()) {
- return ctx.out();
- }
-};
-
-/**
- This template formats data and writes the output through an output iterator.
- */
-template <typename OutputIt, typename Char> class basic_printf_context {
- public:
- /** The character type for the output. */
- using char_type = Char;
- using iterator = OutputIt;
- using format_arg = basic_format_arg<basic_printf_context>;
- using parse_context_type = basic_printf_parse_context<Char>;
- template <typename T> using formatter_type = printf_formatter<T>;
-
- private:
- using format_specs = basic_format_specs<char_type>;
-
- OutputIt out_;
- basic_format_args<basic_printf_context> args_;
- parse_context_type parse_ctx_;
-
- static void parse_flags(format_specs& specs, const Char*& it,
- const Char* end);
-
- // Returns the argument with specified index or, if arg_index is -1, the next
- // argument.
- format_arg get_arg(int arg_index = -1);
-
- // Parses argument index, flags and width and returns the argument index.
- int parse_header(const Char*& it, const Char* end, format_specs& specs);
-
- public:
- /**
- \rst
- Constructs a ``printf_context`` object. References to the arguments are
- stored in the context object so make sure they have appropriate lifetimes.
- \endrst
- */
- basic_printf_context(OutputIt out, basic_string_view<char_type> format_str,
- basic_format_args<basic_printf_context> args)
- : out_(out), args_(args), parse_ctx_(format_str) {}
-
- OutputIt out() { return out_; }
- void advance_to(OutputIt it) { out_ = it; }
-
- detail::locale_ref locale() { return {}; }
-
- format_arg arg(int id) const { return args_.get(id); }
-
- parse_context_type& parse_context() { return parse_ctx_; }
-
- FMT_CONSTEXPR void on_error(const char* message) {
- parse_ctx_.on_error(message);
+ auto parse_ctx =
+ basic_printf_parse_context<Char>(basic_string_view<Char>());
+ handle.format(parse_ctx, context_);
+ return this->out;
}
-
- /** Formats stored arguments and writes the output to the range. */
- template <typename ArgFormatter = printf_arg_formatter<OutputIt, Char>>
- OutputIt format();
};
-template <typename OutputIt, typename Char>
-void basic_printf_context<OutputIt, Char>::parse_flags(format_specs& specs,
- const Char*& it,
- const Char* end) {
+template <typename Char>
+void parse_flags(basic_format_specs<Char>& specs, const Char*& it,
+ const Char* end) {
for (; it != end; ++it) {
switch (*it) {
case '-':
@@ -387,35 +326,24 @@ void basic_printf_context<OutputIt, Char>::parse_flags(format_specs& specs,
}
}
-template <typename OutputIt, typename Char>
-typename basic_printf_context<OutputIt, Char>::format_arg
-basic_printf_context<OutputIt, Char>::get_arg(int arg_index) {
- if (arg_index < 0)
- arg_index = parse_ctx_.next_arg_id();
- else
- parse_ctx_.check_arg_id(--arg_index);
- return detail::get_arg(*this, arg_index);
-}
-
-template <typename OutputIt, typename Char>
-int basic_printf_context<OutputIt, Char>::parse_header(const Char*& it,
- const Char* end,
- format_specs& specs) {
+template <typename Char, typename GetArg>
+int parse_header(const Char*& it, const Char* end,
+ basic_format_specs<Char>& specs, GetArg get_arg) {
int arg_index = -1;
- char_type c = *it;
+ Char c = *it;
if (c >= '0' && c <= '9') {
// Parse an argument index (if followed by '$') or a width possibly
// preceded with '0' flag(s).
- detail::error_handler eh;
- int value = parse_nonnegative_int(it, end, eh);
+ int value = parse_nonnegative_int(it, end, -1);
if (it != end && *it == '$') { // value is an argument index
++it;
- arg_index = value;
+ arg_index = value != -1 ? value : max_value<int>();
} else {
if (c == '0') specs.fill[0] = '0';
if (value != 0) {
// Nonzero value means that we parsed width and don't need to
// parse it or flags again, so return now.
+ if (value == -1) FMT_THROW(format_error("number is too big"));
specs.width = value;
return arg_index;
}
@@ -425,30 +353,44 @@ int basic_printf_context<OutputIt, Char>::parse_header(const Char*& it,
// Parse width.
if (it != end) {
if (*it >= '0' && *it <= '9') {
- detail::error_handler eh;
- specs.width = parse_nonnegative_int(it, end, eh);
+ specs.width = parse_nonnegative_int(it, end, -1);
+ if (specs.width == -1) FMT_THROW(format_error("number is too big"));
} else if (*it == '*') {
++it;
specs.width = static_cast<int>(visit_format_arg(
- detail::printf_width_handler<char_type>(specs), get_arg()));
+ detail::printf_width_handler<Char>(specs), get_arg(-1)));
}
}
return arg_index;
}
-template <typename OutputIt, typename Char>
-template <typename ArgFormatter>
-OutputIt basic_printf_context<OutputIt, Char>::format() {
- auto out = this->out();
- const Char* start = parse_ctx_.begin();
- const Char* end = parse_ctx_.end();
+template <typename Char, typename Context>
+void vprintf(buffer<Char>& buf, basic_string_view<Char> format,
+ basic_format_args<Context> args) {
+ using OutputIt = buffer_appender<Char>;
+ auto out = OutputIt(buf);
+ auto context = basic_printf_context<OutputIt, Char>(out, args);
+ auto parse_ctx = basic_printf_parse_context<Char>(format);
+
+ // Returns the argument with specified index or, if arg_index is -1, the next
+ // argument.
+ auto get_arg = [&](int arg_index) {
+ if (arg_index < 0)
+ arg_index = parse_ctx.next_arg_id();
+ else
+ parse_ctx.check_arg_id(--arg_index);
+ return detail::get_arg(context, arg_index);
+ };
+
+ const Char* start = parse_ctx.begin();
+ const Char* end = parse_ctx.end();
auto it = start;
while (it != end) {
if (!detail::find<false, Char>(it, end, '%', it)) {
it = end; // detail::find leaves it == nullptr if it doesn't find '%'
break;
}
- char_type c = *it++;
+ Char c = *it++;
if (it != end && *it == c) {
out = detail::write(
out, basic_string_view<Char>(start, detail::to_unsigned(it - start)));
@@ -458,30 +400,29 @@ OutputIt basic_printf_context<OutputIt, Char>::format() {
out = detail::write(out, basic_string_view<Char>(
start, detail::to_unsigned(it - 1 - start)));
- format_specs specs;
+ basic_format_specs<Char> specs;
specs.align = align::right;
// Parse argument index, flags and width.
- int arg_index = parse_header(it, end, specs);
- if (arg_index == 0) on_error("argument not found");
+ int arg_index = parse_header(it, end, specs, get_arg);
+ if (arg_index == 0) parse_ctx.on_error("argument not found");
// Parse precision.
if (it != end && *it == '.') {
++it;
c = it != end ? *it : 0;
if ('0' <= c && c <= '9') {
- detail::error_handler eh;
- specs.precision = parse_nonnegative_int(it, end, eh);
+ specs.precision = parse_nonnegative_int(it, end, 0);
} else if (c == '*') {
++it;
specs.precision = static_cast<int>(
- visit_format_arg(detail::printf_precision_handler(), get_arg()));
+ visit_format_arg(detail::printf_precision_handler(), get_arg(-1)));
} else {
specs.precision = 0;
}
}
- format_arg arg = get_arg(arg_index);
+ auto arg = get_arg(arg_index);
// For d, i, o, u, x, and X conversion specifiers, if a precision is
// specified, the '0' flag is ignored
if (specs.precision >= 0 && arg.is_integral())
@@ -491,9 +432,10 @@ OutputIt basic_printf_context<OutputIt, Char>::format() {
auto str = visit_format_arg(detail::get_cstring<Char>(), arg);
auto str_end = str + specs.precision;
auto nul = std::find(str, str_end, Char());
- arg = detail::make_arg<basic_printf_context>(basic_string_view<Char>(
- str,
- detail::to_unsigned(nul != str_end ? nul - str : specs.precision)));
+ arg = detail::make_arg<basic_printf_context<OutputIt, Char>>(
+ basic_string_view<Char>(
+ str, detail::to_unsigned(nul != str_end ? nul - str
+ : specs.precision)));
}
if (specs.alt && visit_format_arg(detail::is_zero_int(), arg))
specs.alt = false;
@@ -507,7 +449,7 @@ OutputIt basic_printf_context<OutputIt, Char>::format() {
// Parse length and convert the argument to the required type.
c = it != end ? *it++ : 0;
- char_type t = it != end ? *it : 0;
+ Char t = it != end ? *it : 0;
using detail::convert_arg;
switch (c) {
case 'h':
@@ -557,8 +499,9 @@ OutputIt basic_printf_context<OutputIt, Char>::format() {
specs.type = 'd';
break;
case 'c':
- visit_format_arg(detail::char_converter<basic_printf_context>(arg),
- arg);
+ visit_format_arg(
+ detail::char_converter<basic_printf_context<OutputIt, Char>>(arg),
+ arg);
break;
}
}
@@ -566,13 +509,12 @@ OutputIt basic_printf_context<OutputIt, Char>::format() {
start = it;
// Format argument.
- out = visit_format_arg(ArgFormatter(out, specs, *this), arg);
+ out = visit_format_arg(
+ detail::printf_arg_formatter<OutputIt, Char>(out, specs, context), arg);
}
- return detail::write(
- out, basic_string_view<Char>(start, detail::to_unsigned(it - start)));
+ detail::write(out, basic_string_view<Char>(start, to_unsigned(it - start)));
}
-
-FMT_MODULE_EXPORT_BEGIN
+FMT_END_DETAIL_NAMESPACE
template <typename Char>
using basic_printf_context_t =
@@ -590,9 +532,9 @@ using wprintf_args = basic_format_args<wprintf_context>;
arguments and can be implicitly converted to `~fmt::printf_args`.
\endrst
*/
-template <typename... Args>
-inline format_arg_store<printf_context, Args...> make_printf_args(
- const Args&... args) {
+template <typename... T>
+inline auto make_printf_args(const T&... args)
+ -> format_arg_store<printf_context, T...> {
return {args...};
}
@@ -602,18 +544,19 @@ inline format_arg_store<printf_context, Args...> make_printf_args(
arguments and can be implicitly converted to `~fmt::wprintf_args`.
\endrst
*/
-template <typename... Args>
-inline format_arg_store<wprintf_context, Args...> make_wprintf_args(
- const Args&... args) {
+template <typename... T>
+inline auto make_wprintf_args(const T&... args)
+ -> format_arg_store<wprintf_context, T...> {
return {args...};
}
template <typename S, typename Char = char_t<S>>
-inline std::basic_string<Char> vsprintf(
- const S& format,
- basic_format_args<basic_printf_context_t<type_identity_t<Char>>> args) {
+inline auto vsprintf(
+ const S& fmt,
+ basic_format_args<basic_printf_context_t<type_identity_t<Char>>> args)
+ -> std::basic_string<Char> {
basic_memory_buffer<Char> buffer;
- vprintf(buffer, to_string_view(format), args);
+ vprintf(buffer, to_string_view(fmt), args);
return to_string(buffer);
}
@@ -626,19 +569,20 @@ inline std::basic_string<Char> vsprintf(
std::string message = fmt::sprintf("The answer is %d", 42);
\endrst
*/
-template <typename S, typename... Args,
+template <typename S, typename... T,
typename Char = enable_if_t<detail::is_string<S>::value, char_t<S>>>
-inline std::basic_string<Char> sprintf(const S& format, const Args&... args) {
+inline auto sprintf(const S& fmt, const T&... args) -> std::basic_string<Char> {
using context = basic_printf_context_t<Char>;
- return vsprintf(to_string_view(format), make_format_args<context>(args...));
+ return vsprintf(to_string_view(fmt), fmt::make_format_args<context>(args...));
}
template <typename S, typename Char = char_t<S>>
-inline int vfprintf(
- std::FILE* f, const S& format,
- basic_format_args<basic_printf_context_t<type_identity_t<Char>>> args) {
+inline auto vfprintf(
+ std::FILE* f, const S& fmt,
+ basic_format_args<basic_printf_context_t<type_identity_t<Char>>> args)
+ -> int {
basic_memory_buffer<Char> buffer;
- vprintf(buffer, to_string_view(format), args);
+ vprintf(buffer, to_string_view(fmt), args);
size_t size = buffer.size();
return std::fwrite(buffer.data(), sizeof(Char), size, f) < size
? -1
@@ -654,19 +598,19 @@ inline int vfprintf(
fmt::fprintf(stderr, "Don't %s!", "panic");
\endrst
*/
-template <typename S, typename... Args,
- typename Char = enable_if_t<detail::is_string<S>::value, char_t<S>>>
-inline int fprintf(std::FILE* f, const S& format, const Args&... args) {
+template <typename S, typename... T, typename Char = char_t<S>>
+inline auto fprintf(std::FILE* f, const S& fmt, const T&... args) -> int {
using context = basic_printf_context_t<Char>;
- return vfprintf(f, to_string_view(format),
- make_format_args<context>(args...));
+ return vfprintf(f, to_string_view(fmt),
+ fmt::make_format_args<context>(args...));
}
template <typename S, typename Char = char_t<S>>
-inline int vprintf(
- const S& format,
- basic_format_args<basic_printf_context_t<type_identity_t<Char>>> args) {
- return vfprintf(stdout, to_string_view(format), args);
+inline auto vprintf(
+ const S& fmt,
+ basic_format_args<basic_printf_context_t<type_identity_t<Char>>> args)
+ -> int {
+ return vfprintf(stdout, to_string_view(fmt), args);
}
/**
@@ -678,51 +622,28 @@ inline int vprintf(
fmt::printf("Elapsed time: %.2f seconds", 1.23);
\endrst
*/
-template <typename S, typename... Args,
- FMT_ENABLE_IF(detail::is_string<S>::value)>
-inline int printf(const S& format_str, const Args&... args) {
- using context = basic_printf_context_t<char_t<S>>;
- return vprintf(to_string_view(format_str),
- make_format_args<context>(args...));
+template <typename S, typename... T, FMT_ENABLE_IF(detail::is_string<S>::value)>
+inline auto printf(const S& fmt, const T&... args) -> int {
+ return vprintf(
+ to_string_view(fmt),
+ fmt::make_format_args<basic_printf_context_t<char_t<S>>>(args...));
}
template <typename S, typename Char = char_t<S>>
-inline int vfprintf(
- std::basic_ostream<Char>& os, const S& format,
- basic_format_args<basic_printf_context_t<type_identity_t<Char>>> args) {
+FMT_DEPRECATED auto vfprintf(
+ std::basic_ostream<Char>& os, const S& fmt,
+ basic_format_args<basic_printf_context_t<type_identity_t<Char>>> args)
+ -> int {
basic_memory_buffer<Char> buffer;
- vprintf(buffer, to_string_view(format), args);
+ vprintf(buffer, to_string_view(fmt), args);
os.write(buffer.data(), static_cast<std::streamsize>(buffer.size()));
return static_cast<int>(buffer.size());
}
-
-/** Formats arguments and writes the output to the range. */
-template <typename ArgFormatter, typename Char,
- typename Context =
- basic_printf_context<typename ArgFormatter::iterator, Char>>
-typename ArgFormatter::iterator vprintf(
- detail::buffer<Char>& out, basic_string_view<Char> format_str,
- basic_format_args<type_identity_t<Context>> args) {
- typename ArgFormatter::iterator iter(out);
- Context(iter, format_str, args).template format<ArgFormatter>();
- return iter;
-}
-
-/**
- \rst
- Prints formatted data to the stream *os*.
-
- **Example**::
-
- fmt::fprintf(cerr, "Don't %s!", "panic");
- \endrst
- */
-template <typename S, typename... Args, typename Char = char_t<S>>
-inline int fprintf(std::basic_ostream<Char>& os, const S& format_str,
- const Args&... args) {
- using context = basic_printf_context_t<Char>;
- return vfprintf(os, to_string_view(format_str),
- make_format_args<context>(args...));
+template <typename S, typename... T, typename Char = char_t<S>>
+FMT_DEPRECATED auto fprintf(std::basic_ostream<Char>& os, const S& fmt,
+ const T&... args) -> int {
+ return vfprintf(os, to_string_view(fmt),
+ fmt::make_format_args<basic_printf_context_t<Char>>(args...));
}
FMT_MODULE_EXPORT_END
diff --git a/deps/fmt/include/fmt/ranges.h b/deps/fmt/include/fmt/ranges.h
index 367d7a6ba3..f0390df211 100644
--- a/deps/fmt/include/fmt/ranges.h
+++ b/deps/fmt/include/fmt/ranges.h
@@ -19,15 +19,7 @@
FMT_BEGIN_NAMESPACE
-template <typename Char> struct formatting_base {
- template <typename ParseContext>
- FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
- return ctx.begin();
- }
-};
-
-template <typename Char, typename Enable = void>
-struct formatting_range : formatting_base<Char> {
+template <typename Char, typename Enable = void> struct formatting_range {
#ifdef FMT_DEPRECATED_BRACED_RANGES
Char prefix = '{';
Char postfix = '}';
@@ -35,12 +27,21 @@ struct formatting_range : formatting_base<Char> {
Char prefix = '[';
Char postfix = ']';
#endif
+
+ template <typename ParseContext>
+ FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
+ return ctx.begin();
+ }
};
-template <typename Char, typename Enable = void>
-struct formatting_tuple : formatting_base<Char> {
+template <typename Char, typename Enable = void> struct formatting_tuple {
Char prefix = '(';
Char postfix = ')';
+
+ template <typename ParseContext>
+ FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
+ return ctx.begin();
+ }
};
namespace detail {
@@ -296,8 +297,8 @@ struct formatter<TupleT, Char, enable_if_t<fmt::is_tuple_like<TupleT>::value>> {
}
formatting_tuple<Char>& formatting;
size_t& i;
- typename std::add_lvalue_reference<decltype(
- std::declval<FormatContext>().out())>::type out;
+ typename std::add_lvalue_reference<
+ decltype(std::declval<FormatContext>().out())>::type out;
};
public:
@@ -362,50 +363,53 @@ struct formatter<
}
};
-template <typename Char, typename... T> struct tuple_arg_join : detail::view {
+template <typename Char, typename... T> struct tuple_join_view : detail::view {
const std::tuple<T...>& tuple;
basic_string_view<Char> sep;
- tuple_arg_join(const std::tuple<T...>& t, basic_string_view<Char> s)
+ tuple_join_view(const std::tuple<T...>& t, basic_string_view<Char> s)
: tuple(t), sep{s} {}
};
template <typename Char, typename... T>
-struct formatter<tuple_arg_join<Char, T...>, Char> {
+using tuple_arg_join = tuple_join_view<Char, T...>;
+
+template <typename Char, typename... T>
+struct formatter<tuple_join_view<Char, T...>, Char> {
template <typename ParseContext>
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
return ctx.begin();
}
template <typename FormatContext>
- typename FormatContext::iterator format(
- const tuple_arg_join<Char, T...>& value, FormatContext& ctx) {
+ auto format(const tuple_join_view<Char, T...>& value, FormatContext& ctx) ->
+ typename FormatContext::iterator {
return format(value, ctx, detail::make_index_sequence<sizeof...(T)>{});
}
private:
template <typename FormatContext, size_t... N>
- typename FormatContext::iterator format(
- const tuple_arg_join<Char, T...>& value, FormatContext& ctx,
- detail::index_sequence<N...>) {
- return format_args(value, ctx, std::get<N>(value.tuple)...);
+ auto format(const tuple_join_view<Char, T...>& value, FormatContext& ctx,
+ detail::index_sequence<N...>) ->
+ typename FormatContext::iterator {
+ using std::get;
+ return format_args(value, ctx, get<N>(value.tuple)...);
}
template <typename FormatContext>
- typename FormatContext::iterator format_args(
- const tuple_arg_join<Char, T...>&, FormatContext& ctx) {
+ auto format_args(const tuple_join_view<Char, T...>&, FormatContext& ctx) ->
+ typename FormatContext::iterator {
// NOTE: for compilers that support C++17, this empty function instantiation
// can be replaced with a constexpr branch in the variadic overload.
return ctx.out();
}
template <typename FormatContext, typename Arg, typename... Args>
- typename FormatContext::iterator format_args(
- const tuple_arg_join<Char, T...>& value, FormatContext& ctx,
- const Arg& arg, const Args&... args) {
+ auto format_args(const tuple_join_view<Char, T...>& value, FormatContext& ctx,
+ const Arg& arg, const Args&... args) ->
+ typename FormatContext::iterator {
using base = formatter<typename std::decay<Arg>::type, Char>;
- auto out = ctx.out();
- out = base{}.format(arg, ctx);
+ auto out = base().format(arg, ctx);
if (sizeof...(Args) > 0) {
out = std::copy(value.sep.begin(), value.sep.end(), out);
ctx.advance_to(out);
@@ -429,14 +433,15 @@ FMT_MODULE_EXPORT_BEGIN
\endrst
*/
template <typename... T>
-FMT_CONSTEXPR tuple_arg_join<char, T...> join(const std::tuple<T...>& tuple,
- string_view sep) {
+FMT_CONSTEXPR auto join(const std::tuple<T...>& tuple, string_view sep)
+ -> tuple_join_view<char, T...> {
return {tuple, sep};
}
template <typename... T>
-FMT_CONSTEXPR tuple_arg_join<wchar_t, T...> join(const std::tuple<T...>& tuple,
- wstring_view sep) {
+FMT_CONSTEXPR auto join(const std::tuple<T...>& tuple,
+ basic_string_view<wchar_t> sep)
+ -> tuple_join_view<wchar_t, T...> {
return {tuple, sep};
}
@@ -452,14 +457,8 @@ FMT_CONSTEXPR tuple_arg_join<wchar_t, T...> join(const std::tuple<T...>& tuple,
\endrst
*/
template <typename T>
-arg_join<const T*, const T*, char> join(std::initializer_list<T> list,
- string_view sep) {
- return join(std::begin(list), std::end(list), sep);
-}
-
-template <typename T>
-arg_join<const T*, const T*, wchar_t> join(std::initializer_list<T> list,
- wstring_view sep) {
+auto join(std::initializer_list<T> list, string_view sep)
+ -> join_view<const T*, const T*> {
return join(std::begin(list), std::end(list), sep);
}
diff --git a/deps/fmt/include/fmt/xchar.h b/deps/fmt/include/fmt/xchar.h
new file mode 100644
index 0000000000..a0dd032f16
--- /dev/null
+++ b/deps/fmt/include/fmt/xchar.h
@@ -0,0 +1,236 @@
+// Formatting library for C++ - optional wchar_t and exotic character support
+//
+// Copyright (c) 2012 - present, Victor Zverovich
+// All rights reserved.
+//
+// For the license information refer to format.h.
+
+#ifndef FMT_WCHAR_H_
+#define FMT_WCHAR_H_
+
+#include <cwchar>
+#include <tuple>
+
+#include "format.h"
+
+FMT_BEGIN_NAMESPACE
+namespace detail {
+template <typename T>
+using is_exotic_char = bool_constant<!std::is_same<T, char>::value>;
+}
+
+FMT_MODULE_EXPORT_BEGIN
+
+using wstring_view = basic_string_view<wchar_t>;
+using wformat_parse_context = basic_format_parse_context<wchar_t>;
+using wformat_context = buffer_context<wchar_t>;
+using wformat_args = basic_format_args<wformat_context>;
+using wmemory_buffer = basic_memory_buffer<wchar_t>;
+
+#if FMT_GCC_VERSION && FMT_GCC_VERSION < 409
+// Workaround broken conversion on older gcc.
+template <typename... Args> using wformat_string = wstring_view;
+#else
+template <typename... Args>
+using wformat_string = basic_format_string<wchar_t, type_identity_t<Args>...>;
+#endif
+
+template <> struct is_char<wchar_t> : std::true_type {};
+template <> struct is_char<detail::char8_type> : std::true_type {};
+template <> struct is_char<char16_t> : std::true_type {};
+template <> struct is_char<char32_t> : std::true_type {};
+
+template <typename... Args>
+constexpr format_arg_store<wformat_context, Args...> make_wformat_args(
+ const Args&... args) {
+ return {args...};
+}
+
+inline namespace literals {
+constexpr auto operator"" _format(const wchar_t* s, size_t n)
+ -> detail::udl_formatter<wchar_t> {
+ return {{s, n}};
+}
+
+#if FMT_USE_USER_DEFINED_LITERALS && !FMT_USE_NONTYPE_TEMPLATE_PARAMETERS
+constexpr detail::udl_arg<wchar_t> operator"" _a(const wchar_t* s, size_t) {
+ return {s};
+}
+#endif
+} // namespace literals
+
+template <typename It, typename Sentinel>
+auto join(It begin, Sentinel end, wstring_view sep)
+ -> join_view<It, Sentinel, wchar_t> {
+ return {begin, end, sep};
+}
+
+template <typename Range>
+auto join(Range&& range, wstring_view sep)
+ -> join_view<detail::iterator_t<Range>, detail::sentinel_t<Range>,
+ wchar_t> {
+ return join(std::begin(range), std::end(range), sep);
+}
+
+template <typename T>
+auto join(std::initializer_list<T> list, wstring_view sep)
+ -> join_view<const T*, const T*, wchar_t> {
+ return join(std::begin(list), std::end(list), sep);
+}
+
+template <typename Char, FMT_ENABLE_IF(!std::is_same<Char, char>::value)>
+auto vformat(basic_string_view<Char> format_str,
+ basic_format_args<buffer_context<type_identity_t<Char>>> args)
+ -> std::basic_string<Char> {
+ basic_memory_buffer<Char> buffer;
+ detail::vformat_to(buffer, format_str, args);
+ return to_string(buffer);
+}
+
+// Pass char_t as a default template parameter instead of using
+// std::basic_string<char_t<S>> to reduce the symbol size.
+template <typename S, typename... Args, typename Char = char_t<S>,
+ FMT_ENABLE_IF(!std::is_same<Char, char>::value)>
+auto format(const S& format_str, Args&&... args) -> std::basic_string<Char> {
+ const auto& vargs = fmt::make_args_checked<Args...>(format_str, args...);
+ return vformat(to_string_view(format_str), vargs);
+}
+
+template <typename Locale, typename S, typename Char = char_t<S>,
+ FMT_ENABLE_IF(detail::is_locale<Locale>::value&&
+ detail::is_exotic_char<Char>::value)>
+inline auto vformat(
+ const Locale& loc, const S& format_str,
+ basic_format_args<buffer_context<type_identity_t<Char>>> args)
+ -> std::basic_string<Char> {
+ return detail::vformat(loc, to_string_view(format_str), args);
+}
+
+template <typename Locale, typename S, typename... Args,
+ typename Char = char_t<S>,
+ FMT_ENABLE_IF(detail::is_locale<Locale>::value&&
+ detail::is_exotic_char<Char>::value)>
+inline auto format(const Locale& loc, const S& format_str, Args&&... args)
+ -> std::basic_string<Char> {
+ return detail::vformat(loc, to_string_view(format_str),
+ fmt::make_args_checked<Args...>(format_str, args...));
+}
+
+template <typename OutputIt, typename S, typename Char = char_t<S>,
+ FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value&&
+ detail::is_exotic_char<Char>::value)>
+auto vformat_to(OutputIt out, const S& format_str,
+ basic_format_args<buffer_context<type_identity_t<Char>>> args)
+ -> OutputIt {
+ auto&& buf = detail::get_buffer<Char>(out);
+ detail::vformat_to(buf, to_string_view(format_str), args);
+ return detail::get_iterator(buf);
+}
+
+template <typename OutputIt, typename S, typename... Args,
+ typename Char = char_t<S>,
+ FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value&&
+ detail::is_exotic_char<Char>::value)>
+inline auto format_to(OutputIt out, const S& fmt, Args&&... args) -> OutputIt {
+ const auto& vargs = fmt::make_args_checked<Args...>(fmt, args...);
+ return vformat_to(out, to_string_view(fmt), vargs);
+}
+
+template <typename S, typename... Args, typename Char, size_t SIZE,
+ typename Allocator, FMT_ENABLE_IF(detail::is_string<S>::value)>
+FMT_DEPRECATED auto format_to(basic_memory_buffer<Char, SIZE, Allocator>& buf,
+ const S& format_str, Args&&... args) ->
+ typename buffer_context<Char>::iterator {
+ const auto& vargs = fmt::make_args_checked<Args...>(format_str, args...);
+ detail::vformat_to(buf, to_string_view(format_str), vargs, {});
+ return detail::buffer_appender<Char>(buf);
+}
+
+template <typename Locale, typename S, typename OutputIt, typename... Args,
+ typename Char = char_t<S>,
+ FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value&&
+ detail::is_locale<Locale>::value&&
+ detail::is_exotic_char<Char>::value)>
+inline auto vformat_to(
+ OutputIt out, const Locale& loc, const S& format_str,
+ basic_format_args<buffer_context<type_identity_t<Char>>> args) -> OutputIt {
+ auto&& buf = detail::get_buffer<Char>(out);
+ vformat_to(buf, to_string_view(format_str), args, detail::locale_ref(loc));
+ return detail::get_iterator(buf);
+}
+
+template <
+ typename OutputIt, typename Locale, typename S, typename... Args,
+ typename Char = char_t<S>,
+ bool enable = detail::is_output_iterator<OutputIt, Char>::value&&
+ detail::is_locale<Locale>::value&& detail::is_exotic_char<Char>::value>
+inline auto format_to(OutputIt out, const Locale& loc, const S& format_str,
+ Args&&... args) ->
+ typename std::enable_if<enable, OutputIt>::type {
+ const auto& vargs = fmt::make_args_checked<Args...>(format_str, args...);
+ return vformat_to(out, loc, to_string_view(format_str), vargs);
+}
+
+template <typename OutputIt, typename Char, typename... Args,
+ FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value&&
+ detail::is_exotic_char<Char>::value)>
+inline auto vformat_to_n(
+ OutputIt out, size_t n, basic_string_view<Char> format_str,
+ basic_format_args<buffer_context<type_identity_t<Char>>> args)
+ -> format_to_n_result<OutputIt> {
+ detail::iterator_buffer<OutputIt, Char, detail::fixed_buffer_traits> buf(out,
+ n);
+ detail::vformat_to(buf, format_str, args);
+ return {buf.out(), buf.count()};
+}
+
+template <typename OutputIt, typename S, typename... Args,
+ typename Char = char_t<S>,
+ FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value&&
+ detail::is_exotic_char<Char>::value)>
+inline auto format_to_n(OutputIt out, size_t n, const S& fmt,
+ const Args&... args) -> format_to_n_result<OutputIt> {
+ const auto& vargs = fmt::make_args_checked<Args...>(fmt, args...);
+ return vformat_to_n(out, n, to_string_view(fmt), vargs);
+}
+
+template <typename S, typename... Args, typename Char = char_t<S>,
+ FMT_ENABLE_IF(detail::is_exotic_char<Char>::value)>
+inline auto formatted_size(const S& fmt, Args&&... args) -> size_t {
+ detail::counting_buffer<Char> buf;
+ const auto& vargs = fmt::make_args_checked<Args...>(fmt, args...);
+ detail::vformat_to(buf, to_string_view(fmt), vargs);
+ return buf.count();
+}
+
+inline void vprint(std::FILE* f, wstring_view fmt, wformat_args args) {
+ wmemory_buffer buffer;
+ detail::vformat_to(buffer, fmt, args);
+ buffer.push_back(L'\0');
+ if (std::fputws(buffer.data(), f) == -1)
+ FMT_THROW(system_error(errno, FMT_STRING("cannot write to file")));
+}
+
+inline void vprint(wstring_view fmt, wformat_args args) {
+ vprint(stdout, fmt, args);
+}
+
+template <typename... T>
+void print(std::FILE* f, wformat_string<T...> fmt, T&&... args) {
+ return vprint(f, wstring_view(fmt), make_wformat_args(args...));
+}
+
+template <typename... T> void print(wformat_string<T...> fmt, T&&... args) {
+ return vprint(wstring_view(fmt), make_wformat_args(args...));
+}
+
+/**
+ Converts *value* to ``std::wstring`` using the default format for type *T*.
+ */
+template <typename T> inline auto to_wstring(const T& value) -> std::wstring {
+ return format(FMT_STRING(L"{}"), value);
+}
+FMT_MODULE_EXPORT_END
+FMT_END_NAMESPACE
+
+#endif // FMT_WCHAR_H_
diff --git a/deps/fmt/src/fmt.cc b/deps/fmt/src/fmt.cc
index b0d805da41..d0d6e7fb34 100644
--- a/deps/fmt/src/fmt.cc
+++ b/deps/fmt/src/fmt.cc
@@ -1,4 +1,8 @@
module;
+#ifndef __cpp_modules
+# error Module not supported.
+#endif
+
// put all implementation-provided headers into the global module fragment
// to prevent attachment to this module
#if !defined(_CRT_SECURE_NO_WARNINGS) && defined(_MSC_VER)
@@ -8,8 +12,10 @@ module;
# define WIN32_LEAN_AND_MEAN
#endif
+#include <algorithm>
#include <cctype>
#include <cerrno>
+#include <chrono>
#include <climits>
#include <clocale>
#include <cmath>
@@ -21,9 +27,6 @@ module;
#include <cstring>
#include <ctime>
#include <cwchar>
-
-#include <algorithm>
-#include <chrono>
#include <exception>
#include <functional>
#include <iterator>
@@ -79,16 +82,19 @@ export module fmt;
// all library-provided declarations and definitions
// must be in the module purview to be exported
-#include "fmt/format.h"
#include "fmt/args.h"
+#include "fmt/chrono.h"
#include "fmt/color.h"
#include "fmt/compile.h"
-#include "fmt/locale.h"
-#include "fmt/chrono.h"
-#include "fmt/printf.h"
+#include "fmt/format.h"
#include "fmt/os.h"
+#include "fmt/printf.h"
+#include "fmt/xchar.h"
+// gcc doesn't yet implement private module fragments
+#if !FMT_GCC_VERSION
module : private;
+#endif
#include "format.cc"
#include "os.cc"
diff --git a/deps/fmt/src/format.cc b/deps/fmt/src/format.cc
index 618aa07d0b..66925b4210 100644
--- a/deps/fmt/src/format.cc
+++ b/deps/fmt/src/format.cc
@@ -28,31 +28,6 @@ template FMT_API dragonbox::decimal_fp<float> dragonbox::to_decimal(float x)
FMT_NOEXCEPT;
template FMT_API dragonbox::decimal_fp<double> dragonbox::to_decimal(double x)
FMT_NOEXCEPT;
-
-// DEPRECATED! This function exists for ABI compatibility.
-template <typename Char>
-typename basic_format_context<std::back_insert_iterator<buffer<Char>>,
- Char>::iterator
-vformat_to(buffer<Char>& buf, basic_string_view<Char> format_str,
- basic_format_args<basic_format_context<
- std::back_insert_iterator<buffer<type_identity_t<Char>>>,
- type_identity_t<Char>>>
- args) {
- using iterator = std::back_insert_iterator<buffer<char>>;
- using context = basic_format_context<
- std::back_insert_iterator<buffer<type_identity_t<Char>>>,
- type_identity_t<Char>>;
- auto out = iterator(buf);
- format_handler<iterator, Char, context> h(out, format_str, args, {});
- parse_format_string<false>(format_str, h);
- return out;
-}
-template basic_format_context<std::back_insert_iterator<buffer<char>>,
- char>::iterator
-vformat_to(buffer<char>&, string_view,
- basic_format_args<basic_format_context<
- std::back_insert_iterator<buffer<type_identity_t<char>>>,
- type_identity_t<char>>>);
} // namespace detail
// Workaround a bug in MSVC2013 that prevents instantiation of format_float.
@@ -66,12 +41,15 @@ template FMT_API std::locale detail::locale_ref::get<std::locale>() const;
// Explicit instantiations for char.
-template FMT_API std::string detail::grouping_impl<char>(locale_ref);
-template FMT_API char detail::thousands_sep_impl(locale_ref);
+template FMT_API auto detail::thousands_sep_impl(locale_ref)
+ -> thousands_sep_result<char>;
template FMT_API char detail::decimal_point_impl(locale_ref);
template FMT_API void detail::buffer<char>::append(const char*, const char*);
+// DEPRECATED!
+// There is no correspondent extern template in format.h because of
+// incompatibility between clang and gcc (#2377).
template FMT_API void detail::vformat_to(
detail::buffer<char>&, string_view,
basic_format_args<FMT_BUFFER_CONTEXT(char)>, detail::locale_ref);
@@ -88,10 +66,13 @@ template FMT_API int detail::format_float(long double, int, detail::float_specs,
// Explicit instantiations for wchar_t.
-template FMT_API std::string detail::grouping_impl<wchar_t>(locale_ref);
-template FMT_API wchar_t detail::thousands_sep_impl(locale_ref);
+template FMT_API auto detail::thousands_sep_impl(locale_ref)
+ -> thousands_sep_result<wchar_t>;
template FMT_API wchar_t detail::decimal_point_impl(locale_ref);
template FMT_API void detail::buffer<wchar_t>::append(const wchar_t*,
const wchar_t*);
+
+template struct detail::basic_data<void>;
+
FMT_END_NAMESPACE
diff --git a/deps/fmt/src/os.cc b/deps/fmt/src/os.cc
index 6474d455e2..934629d71b 100644
--- a/deps/fmt/src/os.cc
+++ b/deps/fmt/src/os.cc
@@ -72,14 +72,14 @@ inline std::size_t convert_rwcount(std::size_t count) { return count; }
FMT_BEGIN_NAMESPACE
#ifdef _WIN32
-detail::utf16_to_utf8::utf16_to_utf8(wstring_view s) {
+detail::utf16_to_utf8::utf16_to_utf8(basic_string_view<wchar_t> s) {
if (int error_code = convert(s)) {
FMT_THROW(windows_error(error_code,
"cannot convert string from UTF-16 to UTF-8"));
}
}
-int detail::utf16_to_utf8::convert(wstring_view s) {
+int detail::utf16_to_utf8::convert(basic_string_view<wchar_t> s) {
if (s.size() > INT_MAX) return ERROR_INVALID_PARAMETER;
int s_size = static_cast<int>(s.size());
if (s_size == 0) {
@@ -129,8 +129,8 @@ class system_message {
}
~system_message() { LocalFree(message_); }
explicit operator bool() const FMT_NOEXCEPT { return result_ != 0; }
- operator wstring_view() const FMT_NOEXCEPT {
- return wstring_view(message_, result_);
+ operator basic_string_view<wchar_t>() const FMT_NOEXCEPT {
+ return basic_string_view<wchar_t>(message_, result_);
}
};
@@ -159,7 +159,7 @@ FMT_API const std::error_category& system_category() FMT_NOEXCEPT {
std::system_error vwindows_error(int err_code, string_view format_str,
format_args args) {
auto ec = std::error_code(err_code, system_category());
- throw std::system_error(ec, vformat(format_str, args));
+ return std::system_error(ec, vformat(format_str, args));
}
void detail::format_windows_error(detail::buffer<char>& out, int error_code,