mirror of
https://github.com/mod-playerbots/azerothcore-wotlk.git
synced 2026-01-13 01:08:35 +00:00
feat(Deps/Fmt): update fmt lib to 10.1.1 (#17643)
This commit is contained in:
29
deps/fmt/CMakeLists.txt
vendored
29
deps/fmt/CMakeLists.txt
vendored
@@ -34,22 +34,23 @@ endfunction()
|
|||||||
|
|
||||||
# Define the fmt library, its includes and the needed defines.
|
# Define the fmt library, its includes and the needed defines.
|
||||||
add_headers(FMT_HEADERS
|
add_headers(FMT_HEADERS
|
||||||
args.h
|
args.h
|
||||||
chrono.h
|
chrono.h
|
||||||
color.h
|
color.h
|
||||||
compile.h
|
compile.h
|
||||||
core.h
|
core.h
|
||||||
format.h
|
format.h
|
||||||
format-inl.h
|
format-inl.h
|
||||||
locale.h os.h
|
os.h
|
||||||
ostream.h
|
ostream.h
|
||||||
printf.h
|
printf.h
|
||||||
ranges.h
|
ranges.h
|
||||||
xchar.h)
|
std.h
|
||||||
|
xchar.h)
|
||||||
|
|
||||||
set(FMT_SOURCES
|
set(FMT_SOURCES
|
||||||
src/format.cc
|
src/format.cc
|
||||||
src/os.cc)
|
src/os.cc)
|
||||||
|
|
||||||
add_library(fmt STATIC ${FMT_SOURCES} ${FMT_HEADERS})
|
add_library(fmt STATIC ${FMT_SOURCES} ${FMT_HEADERS})
|
||||||
|
|
||||||
|
|||||||
1188
deps/fmt/ChangeLog.rst
vendored
1188
deps/fmt/ChangeLog.rst
vendored
File diff suppressed because it is too large
Load Diff
2
deps/fmt/LICENSE.rst
vendored
2
deps/fmt/LICENSE.rst
vendored
@@ -1,4 +1,4 @@
|
|||||||
Copyright (c) 2012 - present, Victor Zverovich
|
Copyright (c) 2012 - present, Victor Zverovich and {fmt} contributors
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
a copy of this software and associated documentation files (the
|
a copy of this software and associated documentation files (the
|
||||||
|
|||||||
93
deps/fmt/README.rst
vendored
93
deps/fmt/README.rst
vendored
@@ -1,5 +1,7 @@
|
|||||||
{fmt}
|
.. image:: https://user-images.githubusercontent.com/
|
||||||
=====
|
576385/156254208-f5b743a9-88cf-439d-b0c0-923d53e8d551.png
|
||||||
|
:width: 25%
|
||||||
|
:alt: {fmt}
|
||||||
|
|
||||||
.. image:: https://github.com/fmtlib/fmt/workflows/linux/badge.svg
|
.. image:: https://github.com/fmtlib/fmt/workflows/linux/badge.svg
|
||||||
:target: https://github.com/fmtlib/fmt/actions?query=workflow%3Alinux
|
:target: https://github.com/fmtlib/fmt/actions?query=workflow%3Alinux
|
||||||
@@ -10,9 +12,6 @@
|
|||||||
.. image:: https://github.com/fmtlib/fmt/workflows/windows/badge.svg
|
.. image:: https://github.com/fmtlib/fmt/workflows/windows/badge.svg
|
||||||
:target: https://github.com/fmtlib/fmt/actions?query=workflow%3Awindows
|
:target: https://github.com/fmtlib/fmt/actions?query=workflow%3Awindows
|
||||||
|
|
||||||
.. image:: https://ci.appveyor.com/api/projects/status/ehjkiefde6gucy1v?svg=true
|
|
||||||
:target: https://ci.appveyor.com/project/vitaut/fmt
|
|
||||||
|
|
||||||
.. image:: https://oss-fuzz-build-logs.storage.googleapis.com/badges/fmt.svg
|
.. image:: https://oss-fuzz-build-logs.storage.googleapis.com/badges/fmt.svg
|
||||||
:alt: fmt is continuously fuzzed at oss-fuzz
|
:alt: fmt is continuously fuzzed at oss-fuzz
|
||||||
:target: https://bugs.chromium.org/p/oss-fuzz/issues/list?\
|
:target: https://bugs.chromium.org/p/oss-fuzz/issues/list?\
|
||||||
@@ -23,15 +22,19 @@
|
|||||||
:alt: Ask questions at StackOverflow with the tag fmt
|
:alt: Ask questions at StackOverflow with the tag fmt
|
||||||
:target: https://stackoverflow.com/questions/tagged/fmt
|
:target: https://stackoverflow.com/questions/tagged/fmt
|
||||||
|
|
||||||
|
.. image:: https://api.securityscorecards.dev/projects/github.com/fmtlib/fmt/badge
|
||||||
|
:target: https://securityscorecards.dev/viewer/?uri=github.com/fmtlib/fmt
|
||||||
|
|
||||||
**{fmt}** is an open-source formatting library providing a fast and safe
|
**{fmt}** is an open-source formatting library providing a fast and safe
|
||||||
alternative to C stdio and C++ iostreams.
|
alternative to C stdio and C++ iostreams.
|
||||||
|
|
||||||
If you like this project, please consider donating to the BYSOL
|
If you like this project, please consider donating to one of the funds that
|
||||||
Foundation that helps victims of political repressions in Belarus:
|
help victims of the war in Ukraine: https://www.stopputin.net/.
|
||||||
https://bysol.org/en/bs/general/.
|
|
||||||
|
|
||||||
`Documentation <https://fmt.dev>`__
|
`Documentation <https://fmt.dev>`__
|
||||||
|
|
||||||
|
`Cheat Sheets <https://hackingcpp.com/cpp/libs/fmt.html>`__
|
||||||
|
|
||||||
Q&A: ask questions on `StackOverflow with the tag fmt
|
Q&A: ask questions on `StackOverflow with the tag fmt
|
||||||
<https://stackoverflow.com/questions/tagged/fmt>`_.
|
<https://stackoverflow.com/questions/tagged/fmt>`_.
|
||||||
|
|
||||||
@@ -47,7 +50,9 @@ Features
|
|||||||
* `Format string syntax <https://fmt.dev/latest/syntax.html>`_ similar to Python's
|
* `Format string syntax <https://fmt.dev/latest/syntax.html>`_ similar to Python's
|
||||||
`format <https://docs.python.org/3/library/stdtypes.html#str.format>`_
|
`format <https://docs.python.org/3/library/stdtypes.html#str.format>`_
|
||||||
* Fast IEEE 754 floating-point formatter with correct rounding, shortness and
|
* Fast IEEE 754 floating-point formatter with correct rounding, shortness and
|
||||||
round-trip guarantees
|
round-trip guarantees using the `Dragonbox <https://github.com/jk-jeon/dragonbox>`_
|
||||||
|
algorithm
|
||||||
|
* Portable Unicode support
|
||||||
* Safe `printf implementation
|
* Safe `printf implementation
|
||||||
<https://fmt.dev/latest/api.html#printf-formatting>`_ including the POSIX
|
<https://fmt.dev/latest/api.html#printf-formatting>`_ including the POSIX
|
||||||
extension for positional arguments
|
extension for positional arguments
|
||||||
@@ -64,7 +69,7 @@ Features
|
|||||||
<https://github.com/fmtlib/fmt/tree/master/test>`_ and is `continuously fuzzed
|
<https://github.com/fmtlib/fmt/tree/master/test>`_ and is `continuously fuzzed
|
||||||
<https://bugs.chromium.org/p/oss-fuzz/issues/list?colspec=ID%20Type%20
|
<https://bugs.chromium.org/p/oss-fuzz/issues/list?colspec=ID%20Type%20
|
||||||
Component%20Status%20Proj%20Reported%20Owner%20Summary&q=proj%3Dfmt&can=1>`_
|
Component%20Status%20Proj%20Reported%20Owner%20Summary&q=proj%3Dfmt&can=1>`_
|
||||||
* Safety: the library is fully type safe, errors in format strings can be
|
* Safety: the library is fully type-safe, errors in format strings can be
|
||||||
reported at compile time, automatic memory management prevents buffer overflow
|
reported at compile time, automatic memory management prevents buffer overflow
|
||||||
errors
|
errors
|
||||||
* Ease of use: small self-contained code base, no external dependencies,
|
* Ease of use: small self-contained code base, no external dependencies,
|
||||||
@@ -74,7 +79,7 @@ Features
|
|||||||
consistent output across platforms and support for older compilers
|
consistent output across platforms and support for older compilers
|
||||||
* Clean warning-free codebase even on high warning levels such as
|
* Clean warning-free codebase even on high warning levels such as
|
||||||
``-Wall -Wextra -pedantic``
|
``-Wall -Wextra -pedantic``
|
||||||
* Locale-independence by default
|
* Locale independence by default
|
||||||
* Optional header-only configuration enabled with the ``FMT_HEADER_ONLY`` macro
|
* Optional header-only configuration enabled with the ``FMT_HEADER_ONLY`` macro
|
||||||
|
|
||||||
See the `documentation <https://fmt.dev>`_ for more details.
|
See the `documentation <https://fmt.dev>`_ for more details.
|
||||||
@@ -123,7 +128,7 @@ Output::
|
|||||||
Default format: 42s 100ms
|
Default format: 42s 100ms
|
||||||
strftime-like format: 03:15:30
|
strftime-like format: 03:15:30
|
||||||
|
|
||||||
**Print a container** (`run <https://godbolt.org/z/MjsY7c>`_)
|
**Print a container** (`run <https://godbolt.org/z/MxM1YqjE7>`_)
|
||||||
|
|
||||||
.. code:: c++
|
.. code:: c++
|
||||||
|
|
||||||
@@ -191,24 +196,24 @@ Speed tests
|
|||||||
================= ============= ===========
|
================= ============= ===========
|
||||||
Library Method Run Time, s
|
Library Method Run Time, s
|
||||||
================= ============= ===========
|
================= ============= ===========
|
||||||
libc printf 1.04
|
libc printf 0.91
|
||||||
libc++ std::ostream 3.05
|
libc++ std::ostream 2.49
|
||||||
{fmt} 6.1.1 fmt::print 0.75
|
{fmt} 9.1 fmt::print 0.74
|
||||||
Boost Format 1.67 boost::format 7.24
|
Boost Format 1.80 boost::format 6.26
|
||||||
Folly Format folly::format 2.23
|
Folly Format folly::format 1.87
|
||||||
================= ============= ===========
|
================= ============= ===========
|
||||||
|
|
||||||
{fmt} is the fastest of the benchmarked methods, ~35% faster than ``printf``.
|
{fmt} is the fastest of the benchmarked methods, ~20% faster than ``printf``.
|
||||||
|
|
||||||
The above results were generated by building ``tinyformat_test.cpp`` on macOS
|
The above results were generated by building ``tinyformat_test.cpp`` on macOS
|
||||||
10.14.6 with ``clang++ -O3 -DNDEBUG -DSPEED_TEST -DHAVE_FORMAT``, and taking the
|
12.6.1 with ``clang++ -O3 -DNDEBUG -DSPEED_TEST -DHAVE_FORMAT``, and taking the
|
||||||
best of three runs. In the test, the format string ``"%0.10f:%04d:%+g:%s:%p:%c:%%\n"``
|
best of three runs. In the test, the format string ``"%0.10f:%04d:%+g:%s:%p:%c:%%\n"``
|
||||||
or equivalent is filled 2,000,000 times with output sent to ``/dev/null``; for
|
or equivalent is filled 2,000,000 times with output sent to ``/dev/null``; for
|
||||||
further details refer to the `source
|
further details refer to the `source
|
||||||
<https://github.com/fmtlib/format-benchmark/blob/master/src/tinyformat-test.cc>`_.
|
<https://github.com/fmtlib/format-benchmark/blob/master/src/tinyformat-test.cc>`_.
|
||||||
|
|
||||||
{fmt} is up to 20-30x faster than ``std::ostringstream`` and ``sprintf`` on
|
{fmt} is up to 20-30x faster than ``std::ostringstream`` and ``sprintf`` on
|
||||||
floating-point formatting (`dtoa-benchmark <https://github.com/fmtlib/dtoa-benchmark>`_)
|
IEEE754 ``float`` and ``double`` formatting (`dtoa-benchmark <https://github.com/fmtlib/dtoa-benchmark>`_)
|
||||||
and faster than `double-conversion <https://github.com/google/double-conversion>`_ and
|
and faster than `double-conversion <https://github.com/google/double-conversion>`_ and
|
||||||
`ryu <https://github.com/ulfjack/ryu>`_:
|
`ryu <https://github.com/ulfjack/ryu>`_:
|
||||||
|
|
||||||
@@ -224,7 +229,7 @@ The script `bloat-test.py
|
|||||||
from `format-benchmark <https://github.com/fmtlib/format-benchmark>`_
|
from `format-benchmark <https://github.com/fmtlib/format-benchmark>`_
|
||||||
tests compile time and code bloat for nontrivial projects.
|
tests compile time and code bloat for nontrivial projects.
|
||||||
It generates 100 translation units and uses ``printf()`` or its alternative
|
It generates 100 translation units and uses ``printf()`` or its alternative
|
||||||
five times in each to simulate a medium sized project. The resulting
|
five times in each to simulate a medium-sized project. The resulting
|
||||||
executable size and compile time (Apple LLVM version 8.1.0 (clang-802.0.42),
|
executable size and compile time (Apple LLVM version 8.1.0 (clang-802.0.42),
|
||||||
macOS Sierra, best of three) is shown in the following tables.
|
macOS Sierra, best of three) is shown in the following tables.
|
||||||
|
|
||||||
@@ -245,7 +250,7 @@ As you can see, {fmt} has 60% less overhead in terms of resulting binary code
|
|||||||
size compared to iostreams and comes pretty close to ``printf``. Boost Format
|
size compared to iostreams and comes pretty close to ``printf``. Boost Format
|
||||||
and Folly Format have the largest overheads.
|
and Folly Format have the largest overheads.
|
||||||
|
|
||||||
``printf+string`` is the same as ``printf`` but with extra ``<string>``
|
``printf+string`` is the same as ``printf`` but with an extra ``<string>``
|
||||||
include to measure the overhead of the latter.
|
include to measure the overhead of the latter.
|
||||||
|
|
||||||
**Non-optimized build**
|
**Non-optimized build**
|
||||||
@@ -261,14 +266,14 @@ Boost Format 54.1 365 303
|
|||||||
Folly Format 79.9 445 430
|
Folly Format 79.9 445 430
|
||||||
============= =============== ==================== ==================
|
============= =============== ==================== ==================
|
||||||
|
|
||||||
``libc``, ``lib(std)c++`` and ``libfmt`` are all linked as shared libraries to
|
``libc``, ``lib(std)c++``, and ``libfmt`` are all linked as shared libraries to
|
||||||
compare formatting function overhead only. Boost Format is a
|
compare formatting function overhead only. Boost Format is a
|
||||||
header-only library so it doesn't provide any linkage options.
|
header-only library so it doesn't provide any linkage options.
|
||||||
|
|
||||||
Running the tests
|
Running the tests
|
||||||
~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
Please refer to `Building the library`__ for the instructions on how to build
|
Please refer to `Building the library`__ for instructions on how to build
|
||||||
the library and run the unit tests.
|
the library and run the unit tests.
|
||||||
|
|
||||||
__ https://fmt.dev/latest/usage.html#building-the-library
|
__ https://fmt.dev/latest/usage.html#building-the-library
|
||||||
@@ -293,9 +298,12 @@ or the bloat test::
|
|||||||
Migrating code
|
Migrating code
|
||||||
--------------
|
--------------
|
||||||
|
|
||||||
`clang-tidy-fmt <https://github.com/mikecrowe/clang-tidy-fmt>`_ provides clang
|
`clang-tidy <https://clang.llvm.org/extra/clang-tidy/>`_ v17 (not yet
|
||||||
tidy checks for converting occurrences of ``printf`` and ``fprintf`` to
|
released) provides the `modernize-use-std-print
|
||||||
``fmt::print``.
|
<https://clang.llvm.org/extra/clang-tidy/checks/modernize/use-std-print.html>`_
|
||||||
|
check that is capable of converting occurrences of ``printf`` and
|
||||||
|
``fprintf`` to ``fmt::print`` if configured to do so. (By default it
|
||||||
|
converts to ``std::print``.)
|
||||||
|
|
||||||
Projects using this library
|
Projects using this library
|
||||||
---------------------------
|
---------------------------
|
||||||
@@ -303,8 +311,6 @@ Projects using this library
|
|||||||
* `0 A.D. <https://play0ad.com/>`_: a free, open-source, cross-platform
|
* `0 A.D. <https://play0ad.com/>`_: a free, open-source, cross-platform
|
||||||
real-time strategy game
|
real-time strategy game
|
||||||
|
|
||||||
* `2GIS <https://2gis.ru/>`_: free business listings with a city map
|
|
||||||
|
|
||||||
* `AMPL/MP <https://github.com/ampl/mp>`_:
|
* `AMPL/MP <https://github.com/ampl/mp>`_:
|
||||||
an open-source library for mathematical programming
|
an open-source library for mathematical programming
|
||||||
|
|
||||||
@@ -322,9 +328,11 @@ Projects using this library
|
|||||||
|
|
||||||
* `ccache <https://ccache.dev/>`_: a compiler cache
|
* `ccache <https://ccache.dev/>`_: a compiler cache
|
||||||
|
|
||||||
* `ClickHouse <https://github.com/ClickHouse/ClickHouse>`_: analytical database
|
* `ClickHouse <https://github.com/ClickHouse/ClickHouse>`_: an analytical database
|
||||||
management system
|
management system
|
||||||
|
|
||||||
|
* `Contour <https://github.com/contour-terminal/contour/>`_: a modern terminal emulator
|
||||||
|
|
||||||
* `CUAUV <https://cuauv.org/>`_: Cornell University's autonomous underwater
|
* `CUAUV <https://cuauv.org/>`_: Cornell University's autonomous underwater
|
||||||
vehicle
|
vehicle
|
||||||
|
|
||||||
@@ -341,9 +349,12 @@ Projects using this library
|
|||||||
|
|
||||||
* `Folly <https://github.com/facebook/folly>`_: Facebook open-source library
|
* `Folly <https://github.com/facebook/folly>`_: Facebook open-source library
|
||||||
|
|
||||||
|
* `GemRB <https://gemrb.org/>`_: a portable open-source implementation of
|
||||||
|
Bioware’s Infinity Engine
|
||||||
|
|
||||||
* `Grand Mountain Adventure
|
* `Grand Mountain Adventure
|
||||||
<https://store.steampowered.com/app/1247360/Grand_Mountain_Adventure/>`_:
|
<https://store.steampowered.com/app/1247360/Grand_Mountain_Adventure/>`_:
|
||||||
A beautiful open-world ski & snowboarding game
|
a beautiful open-world ski & snowboarding game
|
||||||
|
|
||||||
* `HarpyWar/pvpgn <https://github.com/pvpgn/pvpgn-server>`_:
|
* `HarpyWar/pvpgn <https://github.com/pvpgn/pvpgn-server>`_:
|
||||||
Player vs Player Gaming Network with tweaks
|
Player vs Player Gaming Network with tweaks
|
||||||
@@ -357,6 +368,10 @@ Projects using this library
|
|||||||
|
|
||||||
* `Knuth <https://kth.cash/>`_: high-performance Bitcoin full-node
|
* `Knuth <https://kth.cash/>`_: high-performance Bitcoin full-node
|
||||||
|
|
||||||
|
* `libunicode <https://github.com/contour-terminal/libunicode/>`_: a modern C++17 Unicode library
|
||||||
|
|
||||||
|
* `MariaDB <https://mariadb.org/>`_: relational database management system
|
||||||
|
|
||||||
* `Microsoft Verona <https://github.com/microsoft/verona>`_:
|
* `Microsoft Verona <https://github.com/microsoft/verona>`_:
|
||||||
research programming language for concurrent ownership
|
research programming language for concurrent ownership
|
||||||
|
|
||||||
@@ -386,7 +401,7 @@ Projects using this library
|
|||||||
proxy
|
proxy
|
||||||
|
|
||||||
* `redpanda <https://vectorized.io/redpanda>`_: a 10x faster Kafka® replacement
|
* `redpanda <https://vectorized.io/redpanda>`_: a 10x faster Kafka® replacement
|
||||||
for mission critical systems written in C++
|
for mission-critical systems written in C++
|
||||||
|
|
||||||
* `rpclib <http://rpclib.net/>`_: a modern C++ msgpack-RPC server and client
|
* `rpclib <http://rpclib.net/>`_: a modern C++ msgpack-RPC server and client
|
||||||
library
|
library
|
||||||
@@ -410,6 +425,9 @@ Projects using this library
|
|||||||
* `TrinityCore <https://github.com/TrinityCore/TrinityCore>`_: open-source
|
* `TrinityCore <https://github.com/TrinityCore/TrinityCore>`_: open-source
|
||||||
MMORPG framework
|
MMORPG framework
|
||||||
|
|
||||||
|
* `🐙 userver framework <https://userver.tech/>`_: open-source asynchronous
|
||||||
|
framework with a rich set of abstractions and database drivers
|
||||||
|
|
||||||
* `Windows Terminal <https://github.com/microsoft/terminal>`_: the new Windows
|
* `Windows Terminal <https://github.com/microsoft/terminal>`_: the new Windows
|
||||||
terminal
|
terminal
|
||||||
|
|
||||||
@@ -467,7 +485,7 @@ error handling is awkward.
|
|||||||
Boost Format
|
Boost Format
|
||||||
~~~~~~~~~~~~
|
~~~~~~~~~~~~
|
||||||
|
|
||||||
This is a very powerful library which supports both ``printf``-like format
|
This is a very powerful library that supports both ``printf``-like format
|
||||||
strings and positional arguments. Its main drawback is performance. According to
|
strings and positional arguments. Its main drawback is performance. According to
|
||||||
various benchmarks, it is much slower than other methods considered here. Boost
|
various benchmarks, it is much slower than other methods considered here. Boost
|
||||||
Format also has excessive build times and severe code bloat issues (see
|
Format also has excessive build times and severe code bloat issues (see
|
||||||
@@ -476,7 +494,7 @@ Format also has excessive build times and severe code bloat issues (see
|
|||||||
FastFormat
|
FastFormat
|
||||||
~~~~~~~~~~
|
~~~~~~~~~~
|
||||||
|
|
||||||
This is an interesting library which is fast, safe and has positional arguments.
|
This is an interesting library that is fast, safe, and has positional arguments.
|
||||||
However, it has significant limitations, citing its author:
|
However, it has significant limitations, citing its author:
|
||||||
|
|
||||||
Three features that have no hope of being accommodated within the
|
Three features that have no hope of being accommodated within the
|
||||||
@@ -492,7 +510,7 @@ restrictive for using it in some projects.
|
|||||||
Boost Spirit.Karma
|
Boost Spirit.Karma
|
||||||
~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
This is not really a formatting library but I decided to include it here for
|
This is not a formatting library but I decided to include it here for
|
||||||
completeness. As iostreams, it suffers from the problem of mixing verbatim text
|
completeness. As iostreams, it suffers from the problem of mixing verbatim text
|
||||||
with arguments. The library is pretty fast, but slower on integer formatting
|
with arguments. The library is pretty fast, but slower on integer formatting
|
||||||
than ``fmt::format_to`` with format string compilation on Karma's own benchmark,
|
than ``fmt::format_to`` with format string compilation on Karma's own benchmark,
|
||||||
@@ -511,7 +529,7 @@ Documentation License
|
|||||||
The `Format String Syntax <https://fmt.dev/latest/syntax.html>`_
|
The `Format String Syntax <https://fmt.dev/latest/syntax.html>`_
|
||||||
section in the documentation is based on the one from Python `string module
|
section in the documentation is based on the one from Python `string module
|
||||||
documentation <https://docs.python.org/3/library/string.html#module-string>`_.
|
documentation <https://docs.python.org/3/library/string.html#module-string>`_.
|
||||||
For this reason the documentation is distributed under the Python Software
|
For this reason, the documentation is distributed under the Python Software
|
||||||
Foundation license available in `doc/python-license.txt
|
Foundation license available in `doc/python-license.txt
|
||||||
<https://raw.github.com/fmtlib/fmt/master/doc/python-license.txt>`_.
|
<https://raw.github.com/fmtlib/fmt/master/doc/python-license.txt>`_.
|
||||||
It only applies if you distribute the documentation of {fmt}.
|
It only applies if you distribute the documentation of {fmt}.
|
||||||
@@ -520,8 +538,7 @@ Maintainers
|
|||||||
-----------
|
-----------
|
||||||
|
|
||||||
The {fmt} library is maintained by Victor Zverovich (`vitaut
|
The {fmt} library is maintained by Victor Zverovich (`vitaut
|
||||||
<https://github.com/vitaut>`_) and Jonathan Müller (`foonathan
|
<https://github.com/vitaut>`_) with contributions from many other people.
|
||||||
<https://github.com/foonathan>`_) with contributions from many other people.
|
|
||||||
See `Contributors <https://github.com/fmtlib/fmt/graphs/contributors>`_ and
|
See `Contributors <https://github.com/fmtlib/fmt/graphs/contributors>`_ and
|
||||||
`Releases <https://github.com/fmtlib/fmt/releases>`_ for some of the names.
|
`Releases <https://github.com/fmtlib/fmt/releases>`_ for some of the names.
|
||||||
Let us know if your contribution is not listed or mentioned incorrectly and
|
Let us know if your contribution is not listed or mentioned incorrectly and
|
||||||
|
|||||||
10
deps/fmt/include/fmt/args.h
vendored
10
deps/fmt/include/fmt/args.h
vendored
@@ -1,4 +1,4 @@
|
|||||||
// Formatting library for C++ - dynamic format arguments
|
// Formatting library for C++ - dynamic argument lists
|
||||||
//
|
//
|
||||||
// Copyright (c) 2012 - present, Victor Zverovich
|
// Copyright (c) 2012 - present, Victor Zverovich
|
||||||
// All rights reserved.
|
// All rights reserved.
|
||||||
@@ -95,10 +95,10 @@ class dynamic_format_arg_store
|
|||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
using stored_type = conditional_t<detail::is_string<T>::value &&
|
using stored_type = conditional_t<
|
||||||
!has_formatter<T, Context>::value &&
|
std::is_convertible<T, std::basic_string<char_type>>::value &&
|
||||||
!detail::is_reference_wrapper<T>::value,
|
!detail::is_reference_wrapper<T>::value,
|
||||||
std::basic_string<char_type>, T>;
|
std::basic_string<char_type>, T>;
|
||||||
|
|
||||||
// Storage of basic_format_arg must be contiguous.
|
// Storage of basic_format_arg must be contiguous.
|
||||||
std::vector<basic_format_arg<Context>> data_;
|
std::vector<basic_format_arg<Context>> data_;
|
||||||
|
|||||||
829
deps/fmt/include/fmt/chrono.h
vendored
829
deps/fmt/include/fmt/chrono.h
vendored
File diff suppressed because it is too large
Load Diff
237
deps/fmt/include/fmt/color.h
vendored
237
deps/fmt/include/fmt/color.h
vendored
@@ -10,15 +10,8 @@
|
|||||||
|
|
||||||
#include "format.h"
|
#include "format.h"
|
||||||
|
|
||||||
// __declspec(deprecated) is broken in some MSVC versions.
|
|
||||||
#if FMT_MSC_VER
|
|
||||||
# define FMT_DEPRECATED_NONMSVC
|
|
||||||
#else
|
|
||||||
# define FMT_DEPRECATED_NONMSVC FMT_DEPRECATED
|
|
||||||
#endif
|
|
||||||
|
|
||||||
FMT_BEGIN_NAMESPACE
|
FMT_BEGIN_NAMESPACE
|
||||||
FMT_MODULE_EXPORT_BEGIN
|
FMT_BEGIN_EXPORT
|
||||||
|
|
||||||
enum class color : uint32_t {
|
enum class color : uint32_t {
|
||||||
alice_blue = 0xF0F8FF, // rgb(240,248,255)
|
alice_blue = 0xF0F8FF, // rgb(240,248,255)
|
||||||
@@ -210,21 +203,20 @@ struct rgb {
|
|||||||
uint8_t b;
|
uint8_t b;
|
||||||
};
|
};
|
||||||
|
|
||||||
FMT_BEGIN_DETAIL_NAMESPACE
|
namespace detail {
|
||||||
|
|
||||||
// color is a struct of either a rgb color or a terminal color.
|
// color is a struct of either a rgb color or a terminal color.
|
||||||
struct color_type {
|
struct color_type {
|
||||||
FMT_CONSTEXPR color_type() FMT_NOEXCEPT : is_rgb(), value{} {}
|
FMT_CONSTEXPR color_type() noexcept : is_rgb(), value{} {}
|
||||||
FMT_CONSTEXPR color_type(color rgb_color) FMT_NOEXCEPT : is_rgb(true),
|
FMT_CONSTEXPR color_type(color rgb_color) noexcept : is_rgb(true), value{} {
|
||||||
value{} {
|
|
||||||
value.rgb_color = static_cast<uint32_t>(rgb_color);
|
value.rgb_color = static_cast<uint32_t>(rgb_color);
|
||||||
}
|
}
|
||||||
FMT_CONSTEXPR color_type(rgb rgb_color) FMT_NOEXCEPT : is_rgb(true), value{} {
|
FMT_CONSTEXPR color_type(rgb rgb_color) noexcept : is_rgb(true), value{} {
|
||||||
value.rgb_color = (static_cast<uint32_t>(rgb_color.r) << 16) |
|
value.rgb_color = (static_cast<uint32_t>(rgb_color.r) << 16) |
|
||||||
(static_cast<uint32_t>(rgb_color.g) << 8) | rgb_color.b;
|
(static_cast<uint32_t>(rgb_color.g) << 8) | rgb_color.b;
|
||||||
}
|
}
|
||||||
FMT_CONSTEXPR color_type(terminal_color term_color) FMT_NOEXCEPT : is_rgb(),
|
FMT_CONSTEXPR color_type(terminal_color term_color) noexcept
|
||||||
value{} {
|
: is_rgb(), value{} {
|
||||||
value.term_color = static_cast<uint8_t>(term_color);
|
value.term_color = static_cast<uint8_t>(term_color);
|
||||||
}
|
}
|
||||||
bool is_rgb;
|
bool is_rgb;
|
||||||
@@ -233,16 +225,13 @@ struct color_type {
|
|||||||
uint32_t rgb_color;
|
uint32_t rgb_color;
|
||||||
} value;
|
} value;
|
||||||
};
|
};
|
||||||
|
} // namespace detail
|
||||||
FMT_END_DETAIL_NAMESPACE
|
|
||||||
|
|
||||||
/** A text style consisting of foreground and background colors and emphasis. */
|
/** A text style consisting of foreground and background colors and emphasis. */
|
||||||
class text_style {
|
class text_style {
|
||||||
public:
|
public:
|
||||||
FMT_CONSTEXPR text_style(emphasis em = emphasis()) FMT_NOEXCEPT
|
FMT_CONSTEXPR text_style(emphasis em = emphasis()) noexcept
|
||||||
: set_foreground_color(),
|
: set_foreground_color(), set_background_color(), ems(em) {}
|
||||||
set_background_color(),
|
|
||||||
ems(em) {}
|
|
||||||
|
|
||||||
FMT_CONSTEXPR text_style& operator|=(const text_style& rhs) {
|
FMT_CONSTEXPR text_style& operator|=(const text_style& rhs) {
|
||||||
if (!set_foreground_color) {
|
if (!set_foreground_color) {
|
||||||
@@ -273,44 +262,32 @@ class text_style {
|
|||||||
return lhs |= rhs;
|
return lhs |= rhs;
|
||||||
}
|
}
|
||||||
|
|
||||||
FMT_DEPRECATED_NONMSVC FMT_CONSTEXPR text_style& operator&=(
|
FMT_CONSTEXPR bool has_foreground() const noexcept {
|
||||||
const text_style& rhs) {
|
|
||||||
return and_assign(rhs);
|
|
||||||
}
|
|
||||||
|
|
||||||
FMT_DEPRECATED_NONMSVC friend FMT_CONSTEXPR text_style
|
|
||||||
operator&(text_style lhs, const text_style& rhs) {
|
|
||||||
return lhs.and_assign(rhs);
|
|
||||||
}
|
|
||||||
|
|
||||||
FMT_CONSTEXPR bool has_foreground() const FMT_NOEXCEPT {
|
|
||||||
return set_foreground_color;
|
return set_foreground_color;
|
||||||
}
|
}
|
||||||
FMT_CONSTEXPR bool has_background() const FMT_NOEXCEPT {
|
FMT_CONSTEXPR bool has_background() const noexcept {
|
||||||
return set_background_color;
|
return set_background_color;
|
||||||
}
|
}
|
||||||
FMT_CONSTEXPR bool has_emphasis() const FMT_NOEXCEPT {
|
FMT_CONSTEXPR bool has_emphasis() const noexcept {
|
||||||
return static_cast<uint8_t>(ems) != 0;
|
return static_cast<uint8_t>(ems) != 0;
|
||||||
}
|
}
|
||||||
FMT_CONSTEXPR detail::color_type get_foreground() const FMT_NOEXCEPT {
|
FMT_CONSTEXPR detail::color_type get_foreground() const noexcept {
|
||||||
FMT_ASSERT(has_foreground(), "no foreground specified for this style");
|
FMT_ASSERT(has_foreground(), "no foreground specified for this style");
|
||||||
return foreground_color;
|
return foreground_color;
|
||||||
}
|
}
|
||||||
FMT_CONSTEXPR detail::color_type get_background() const FMT_NOEXCEPT {
|
FMT_CONSTEXPR detail::color_type get_background() const noexcept {
|
||||||
FMT_ASSERT(has_background(), "no background specified for this style");
|
FMT_ASSERT(has_background(), "no background specified for this style");
|
||||||
return background_color;
|
return background_color;
|
||||||
}
|
}
|
||||||
FMT_CONSTEXPR emphasis get_emphasis() const FMT_NOEXCEPT {
|
FMT_CONSTEXPR emphasis get_emphasis() const noexcept {
|
||||||
FMT_ASSERT(has_emphasis(), "no emphasis specified for this style");
|
FMT_ASSERT(has_emphasis(), "no emphasis specified for this style");
|
||||||
return ems;
|
return ems;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
FMT_CONSTEXPR text_style(bool is_foreground,
|
FMT_CONSTEXPR text_style(bool is_foreground,
|
||||||
detail::color_type text_color) FMT_NOEXCEPT
|
detail::color_type text_color) noexcept
|
||||||
: set_foreground_color(),
|
: set_foreground_color(), set_background_color(), ems() {
|
||||||
set_background_color(),
|
|
||||||
ems() {
|
|
||||||
if (is_foreground) {
|
if (is_foreground) {
|
||||||
foreground_color = text_color;
|
foreground_color = text_color;
|
||||||
set_foreground_color = true;
|
set_foreground_color = true;
|
||||||
@@ -320,36 +297,9 @@ class text_style {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// DEPRECATED!
|
friend FMT_CONSTEXPR text_style fg(detail::color_type foreground) noexcept;
|
||||||
FMT_CONSTEXPR text_style& and_assign(const text_style& rhs) {
|
|
||||||
if (!set_foreground_color) {
|
|
||||||
set_foreground_color = rhs.set_foreground_color;
|
|
||||||
foreground_color = rhs.foreground_color;
|
|
||||||
} else if (rhs.set_foreground_color) {
|
|
||||||
if (!foreground_color.is_rgb || !rhs.foreground_color.is_rgb)
|
|
||||||
FMT_THROW(format_error("can't AND a terminal color"));
|
|
||||||
foreground_color.value.rgb_color &= rhs.foreground_color.value.rgb_color;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!set_background_color) {
|
friend FMT_CONSTEXPR text_style bg(detail::color_type background) noexcept;
|
||||||
set_background_color = rhs.set_background_color;
|
|
||||||
background_color = rhs.background_color;
|
|
||||||
} else if (rhs.set_background_color) {
|
|
||||||
if (!background_color.is_rgb || !rhs.background_color.is_rgb)
|
|
||||||
FMT_THROW(format_error("can't AND a terminal color"));
|
|
||||||
background_color.value.rgb_color &= rhs.background_color.value.rgb_color;
|
|
||||||
}
|
|
||||||
|
|
||||||
ems = static_cast<emphasis>(static_cast<uint8_t>(ems) &
|
|
||||||
static_cast<uint8_t>(rhs.ems));
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
friend FMT_CONSTEXPR_DECL text_style fg(detail::color_type foreground)
|
|
||||||
FMT_NOEXCEPT;
|
|
||||||
|
|
||||||
friend FMT_CONSTEXPR_DECL text_style bg(detail::color_type background)
|
|
||||||
FMT_NOEXCEPT;
|
|
||||||
|
|
||||||
detail::color_type foreground_color;
|
detail::color_type foreground_color;
|
||||||
detail::color_type background_color;
|
detail::color_type background_color;
|
||||||
@@ -359,25 +309,24 @@ class text_style {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/** Creates a text style from the foreground (text) color. */
|
/** Creates a text style from the foreground (text) color. */
|
||||||
FMT_CONSTEXPR inline text_style fg(detail::color_type foreground) FMT_NOEXCEPT {
|
FMT_CONSTEXPR inline text_style fg(detail::color_type foreground) noexcept {
|
||||||
return text_style(true, foreground);
|
return text_style(true, foreground);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Creates a text style from the background color. */
|
/** Creates a text style from the background color. */
|
||||||
FMT_CONSTEXPR inline text_style bg(detail::color_type background) FMT_NOEXCEPT {
|
FMT_CONSTEXPR inline text_style bg(detail::color_type background) noexcept {
|
||||||
return text_style(false, background);
|
return text_style(false, background);
|
||||||
}
|
}
|
||||||
|
|
||||||
FMT_CONSTEXPR inline text_style operator|(emphasis lhs,
|
FMT_CONSTEXPR inline text_style operator|(emphasis lhs, emphasis rhs) noexcept {
|
||||||
emphasis rhs) FMT_NOEXCEPT {
|
|
||||||
return text_style(lhs) | rhs;
|
return text_style(lhs) | rhs;
|
||||||
}
|
}
|
||||||
|
|
||||||
FMT_BEGIN_DETAIL_NAMESPACE
|
namespace detail {
|
||||||
|
|
||||||
template <typename Char> struct ansi_color_escape {
|
template <typename Char> struct ansi_color_escape {
|
||||||
FMT_CONSTEXPR ansi_color_escape(detail::color_type text_color,
|
FMT_CONSTEXPR ansi_color_escape(detail::color_type text_color,
|
||||||
const char* esc) FMT_NOEXCEPT {
|
const char* esc) noexcept {
|
||||||
// If we have a terminal color, we need to output another escape code
|
// If we have a terminal color, we need to output another escape code
|
||||||
// sequence.
|
// sequence.
|
||||||
if (!text_color.is_rgb) {
|
if (!text_color.is_rgb) {
|
||||||
@@ -412,7 +361,7 @@ template <typename Char> struct ansi_color_escape {
|
|||||||
to_esc(color.b, buffer + 15, 'm');
|
to_esc(color.b, buffer + 15, 'm');
|
||||||
buffer[19] = static_cast<Char>(0);
|
buffer[19] = static_cast<Char>(0);
|
||||||
}
|
}
|
||||||
FMT_CONSTEXPR ansi_color_escape(emphasis em) FMT_NOEXCEPT {
|
FMT_CONSTEXPR ansi_color_escape(emphasis em) noexcept {
|
||||||
uint8_t em_codes[num_emphases] = {};
|
uint8_t em_codes[num_emphases] = {};
|
||||||
if (has_emphasis(em, emphasis::bold)) em_codes[0] = 1;
|
if (has_emphasis(em, emphasis::bold)) em_codes[0] = 1;
|
||||||
if (has_emphasis(em, emphasis::faint)) em_codes[1] = 2;
|
if (has_emphasis(em, emphasis::faint)) em_codes[1] = 2;
|
||||||
@@ -433,10 +382,10 @@ template <typename Char> struct ansi_color_escape {
|
|||||||
}
|
}
|
||||||
buffer[index++] = static_cast<Char>(0);
|
buffer[index++] = static_cast<Char>(0);
|
||||||
}
|
}
|
||||||
FMT_CONSTEXPR operator const Char*() const FMT_NOEXCEPT { return buffer; }
|
FMT_CONSTEXPR operator const Char*() const noexcept { return buffer; }
|
||||||
|
|
||||||
FMT_CONSTEXPR const Char* begin() const FMT_NOEXCEPT { return buffer; }
|
FMT_CONSTEXPR const Char* begin() const noexcept { return buffer; }
|
||||||
FMT_CONSTEXPR_CHAR_TRAITS const Char* end() const FMT_NOEXCEPT {
|
FMT_CONSTEXPR_CHAR_TRAITS const Char* end() const noexcept {
|
||||||
return buffer + std::char_traits<Char>::length(buffer);
|
return buffer + std::char_traits<Char>::length(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -445,60 +394,44 @@ template <typename Char> struct ansi_color_escape {
|
|||||||
Char buffer[7u + 3u * num_emphases + 1u];
|
Char buffer[7u + 3u * num_emphases + 1u];
|
||||||
|
|
||||||
static FMT_CONSTEXPR void to_esc(uint8_t c, Char* out,
|
static FMT_CONSTEXPR void to_esc(uint8_t c, Char* out,
|
||||||
char delimiter) FMT_NOEXCEPT {
|
char delimiter) noexcept {
|
||||||
out[0] = static_cast<Char>('0' + c / 100);
|
out[0] = static_cast<Char>('0' + c / 100);
|
||||||
out[1] = static_cast<Char>('0' + c / 10 % 10);
|
out[1] = static_cast<Char>('0' + c / 10 % 10);
|
||||||
out[2] = static_cast<Char>('0' + c % 10);
|
out[2] = static_cast<Char>('0' + c % 10);
|
||||||
out[3] = static_cast<Char>(delimiter);
|
out[3] = static_cast<Char>(delimiter);
|
||||||
}
|
}
|
||||||
static FMT_CONSTEXPR bool has_emphasis(emphasis em,
|
static FMT_CONSTEXPR bool has_emphasis(emphasis em, emphasis mask) noexcept {
|
||||||
emphasis mask) FMT_NOEXCEPT {
|
|
||||||
return static_cast<uint8_t>(em) & static_cast<uint8_t>(mask);
|
return static_cast<uint8_t>(em) & static_cast<uint8_t>(mask);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename Char>
|
template <typename Char>
|
||||||
FMT_CONSTEXPR ansi_color_escape<Char> make_foreground_color(
|
FMT_CONSTEXPR ansi_color_escape<Char> make_foreground_color(
|
||||||
detail::color_type foreground) FMT_NOEXCEPT {
|
detail::color_type foreground) noexcept {
|
||||||
return ansi_color_escape<Char>(foreground, "\x1b[38;2;");
|
return ansi_color_escape<Char>(foreground, "\x1b[38;2;");
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Char>
|
template <typename Char>
|
||||||
FMT_CONSTEXPR ansi_color_escape<Char> make_background_color(
|
FMT_CONSTEXPR ansi_color_escape<Char> make_background_color(
|
||||||
detail::color_type background) FMT_NOEXCEPT {
|
detail::color_type background) noexcept {
|
||||||
return ansi_color_escape<Char>(background, "\x1b[48;2;");
|
return ansi_color_escape<Char>(background, "\x1b[48;2;");
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Char>
|
template <typename Char>
|
||||||
FMT_CONSTEXPR ansi_color_escape<Char> make_emphasis(emphasis em) FMT_NOEXCEPT {
|
FMT_CONSTEXPR ansi_color_escape<Char> make_emphasis(emphasis em) noexcept {
|
||||||
return ansi_color_escape<Char>(em);
|
return ansi_color_escape<Char>(em);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Char> inline void fputs(const Char* chars, FILE* stream) {
|
|
||||||
int result = std::fputs(chars, stream);
|
|
||||||
if (result < 0)
|
|
||||||
FMT_THROW(system_error(errno, FMT_STRING("cannot write to file")));
|
|
||||||
}
|
|
||||||
|
|
||||||
template <> inline void fputs<wchar_t>(const wchar_t* chars, FILE* stream) {
|
|
||||||
int result = std::fputws(chars, stream);
|
|
||||||
if (result < 0)
|
|
||||||
FMT_THROW(system_error(errno, FMT_STRING("cannot write to file")));
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename Char> inline void reset_color(FILE* stream) {
|
|
||||||
fputs("\x1b[0m", stream);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <> inline void reset_color<wchar_t>(FILE* stream) {
|
|
||||||
fputs(L"\x1b[0m", stream);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename Char> inline void reset_color(buffer<Char>& buffer) {
|
template <typename Char> inline void reset_color(buffer<Char>& buffer) {
|
||||||
auto reset_color = string_view("\x1b[0m");
|
auto reset_color = string_view("\x1b[0m");
|
||||||
buffer.append(reset_color.begin(), reset_color.end());
|
buffer.append(reset_color.begin(), reset_color.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename T> struct styled_arg {
|
||||||
|
const T& value;
|
||||||
|
text_style style;
|
||||||
|
};
|
||||||
|
|
||||||
template <typename Char>
|
template <typename Char>
|
||||||
void vformat_to(buffer<Char>& buf, const text_style& ts,
|
void vformat_to(buffer<Char>& buf, const text_style& ts,
|
||||||
basic_string_view<Char> format_str,
|
basic_string_view<Char> format_str,
|
||||||
@@ -523,19 +456,21 @@ void vformat_to(buffer<Char>& buf, const text_style& ts,
|
|||||||
if (has_style) detail::reset_color<Char>(buf);
|
if (has_style) detail::reset_color<Char>(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
FMT_END_DETAIL_NAMESPACE
|
} // namespace detail
|
||||||
|
|
||||||
template <typename S, typename Char = char_t<S>>
|
inline void vprint(std::FILE* f, const text_style& ts, string_view fmt,
|
||||||
void vprint(std::FILE* f, const text_style& ts, const S& format,
|
format_args args) {
|
||||||
basic_format_args<buffer_context<type_identity_t<Char>>> args) {
|
// Legacy wide streams are not supported.
|
||||||
basic_memory_buffer<Char> buf;
|
auto buf = memory_buffer();
|
||||||
detail::vformat_to(buf, ts, to_string_view(format), args);
|
detail::vformat_to(buf, ts, fmt, args);
|
||||||
if (detail::is_utf8()) {
|
if (detail::is_utf8()) {
|
||||||
detail::print(f, basic_string_view<Char>(buf.begin(), buf.size()));
|
detail::print(f, string_view(buf.begin(), buf.size()));
|
||||||
} else {
|
return;
|
||||||
buf.push_back(Char(0));
|
|
||||||
detail::fputs(buf.data(), f);
|
|
||||||
}
|
}
|
||||||
|
buf.push_back('\0');
|
||||||
|
int result = std::fputs(buf.data(), f);
|
||||||
|
if (result < 0)
|
||||||
|
FMT_THROW(system_error(errno, FMT_STRING("cannot write to file")));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -554,7 +489,7 @@ template <typename S, typename... Args,
|
|||||||
void print(std::FILE* f, const text_style& ts, const S& format_str,
|
void print(std::FILE* f, const text_style& ts, const S& format_str,
|
||||||
const Args&... args) {
|
const Args&... args) {
|
||||||
vprint(f, ts, format_str,
|
vprint(f, ts, format_str,
|
||||||
fmt::make_args_checked<Args...>(format_str, args...));
|
fmt::make_format_args<buffer_context<char_t<S>>>(args...));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -579,7 +514,7 @@ inline std::basic_string<Char> vformat(
|
|||||||
const text_style& ts, const S& format_str,
|
const text_style& ts, const S& format_str,
|
||||||
basic_format_args<buffer_context<type_identity_t<Char>>> args) {
|
basic_format_args<buffer_context<type_identity_t<Char>>> args) {
|
||||||
basic_memory_buffer<Char> buf;
|
basic_memory_buffer<Char> buf;
|
||||||
detail::vformat_to(buf, ts, to_string_view(format_str), args);
|
detail::vformat_to(buf, ts, detail::to_string_view(format_str), args);
|
||||||
return fmt::to_string(buf);
|
return fmt::to_string(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -598,8 +533,8 @@ inline std::basic_string<Char> vformat(
|
|||||||
template <typename S, typename... Args, typename Char = char_t<S>>
|
template <typename S, typename... Args, typename Char = char_t<S>>
|
||||||
inline std::basic_string<Char> format(const text_style& ts, const S& format_str,
|
inline std::basic_string<Char> format(const text_style& ts, const S& format_str,
|
||||||
const Args&... args) {
|
const Args&... args) {
|
||||||
return fmt::vformat(ts, to_string_view(format_str),
|
return fmt::vformat(ts, detail::to_string_view(format_str),
|
||||||
fmt::make_args_checked<Args...>(format_str, args...));
|
fmt::make_format_args<buffer_context<Char>>(args...));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -612,7 +547,7 @@ OutputIt vformat_to(
|
|||||||
basic_format_args<buffer_context<type_identity_t<Char>>> args) {
|
basic_format_args<buffer_context<type_identity_t<Char>>> args) {
|
||||||
auto&& buf = detail::get_buffer<Char>(out);
|
auto&& buf = detail::get_buffer<Char>(out);
|
||||||
detail::vformat_to(buf, ts, format_str, args);
|
detail::vformat_to(buf, ts, format_str, args);
|
||||||
return detail::get_iterator(buf);
|
return detail::get_iterator(buf, out);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -633,11 +568,65 @@ template <typename OutputIt, typename S, typename... Args,
|
|||||||
inline auto format_to(OutputIt out, const text_style& ts, const S& format_str,
|
inline auto format_to(OutputIt out, const text_style& ts, const S& format_str,
|
||||||
Args&&... args) ->
|
Args&&... args) ->
|
||||||
typename std::enable_if<enable, OutputIt>::type {
|
typename std::enable_if<enable, OutputIt>::type {
|
||||||
return vformat_to(out, ts, to_string_view(format_str),
|
return vformat_to(out, ts, detail::to_string_view(format_str),
|
||||||
fmt::make_args_checked<Args...>(format_str, args...));
|
fmt::make_format_args<buffer_context<char_t<S>>>(args...));
|
||||||
}
|
}
|
||||||
|
|
||||||
FMT_MODULE_EXPORT_END
|
template <typename T, typename Char>
|
||||||
|
struct formatter<detail::styled_arg<T>, Char> : formatter<T, Char> {
|
||||||
|
template <typename FormatContext>
|
||||||
|
auto format(const detail::styled_arg<T>& arg, FormatContext& ctx) const
|
||||||
|
-> decltype(ctx.out()) {
|
||||||
|
const auto& ts = arg.style;
|
||||||
|
const auto& value = arg.value;
|
||||||
|
auto out = ctx.out();
|
||||||
|
|
||||||
|
bool has_style = false;
|
||||||
|
if (ts.has_emphasis()) {
|
||||||
|
has_style = true;
|
||||||
|
auto emphasis = detail::make_emphasis<Char>(ts.get_emphasis());
|
||||||
|
out = std::copy(emphasis.begin(), emphasis.end(), out);
|
||||||
|
}
|
||||||
|
if (ts.has_foreground()) {
|
||||||
|
has_style = true;
|
||||||
|
auto foreground =
|
||||||
|
detail::make_foreground_color<Char>(ts.get_foreground());
|
||||||
|
out = std::copy(foreground.begin(), foreground.end(), out);
|
||||||
|
}
|
||||||
|
if (ts.has_background()) {
|
||||||
|
has_style = true;
|
||||||
|
auto background =
|
||||||
|
detail::make_background_color<Char>(ts.get_background());
|
||||||
|
out = std::copy(background.begin(), background.end(), out);
|
||||||
|
}
|
||||||
|
out = formatter<T, Char>::format(value, ctx);
|
||||||
|
if (has_style) {
|
||||||
|
auto reset_color = string_view("\x1b[0m");
|
||||||
|
out = std::copy(reset_color.begin(), reset_color.end(), out);
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
\rst
|
||||||
|
Returns an argument that will be formatted using ANSI escape sequences,
|
||||||
|
to be used in a formatting function.
|
||||||
|
|
||||||
|
**Example**::
|
||||||
|
|
||||||
|
fmt::print("Elapsed time: {0:.2f} seconds",
|
||||||
|
fmt::styled(1.23, fmt::fg(fmt::color::green) |
|
||||||
|
fmt::bg(fmt::color::blue)));
|
||||||
|
\endrst
|
||||||
|
*/
|
||||||
|
template <typename T>
|
||||||
|
FMT_CONSTEXPR auto styled(const T& value, text_style ts)
|
||||||
|
-> detail::styled_arg<remove_cvref_t<T>> {
|
||||||
|
return detail::styled_arg<remove_cvref_t<T>>{value, ts};
|
||||||
|
}
|
||||||
|
|
||||||
|
FMT_END_EXPORT
|
||||||
FMT_END_NAMESPACE
|
FMT_END_NAMESPACE
|
||||||
|
|
||||||
#endif // FMT_COLOR_H_
|
#endif // FMT_COLOR_H_
|
||||||
|
|||||||
232
deps/fmt/include/fmt/compile.h
vendored
232
deps/fmt/include/fmt/compile.h
vendored
@@ -13,130 +13,12 @@
|
|||||||
FMT_BEGIN_NAMESPACE
|
FMT_BEGIN_NAMESPACE
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
|
||||||
// An output iterator that counts the number of objects written to it and
|
|
||||||
// discards them.
|
|
||||||
class counting_iterator {
|
|
||||||
private:
|
|
||||||
size_t count_;
|
|
||||||
|
|
||||||
public:
|
|
||||||
using iterator_category = std::output_iterator_tag;
|
|
||||||
using difference_type = std::ptrdiff_t;
|
|
||||||
using pointer = void;
|
|
||||||
using reference = void;
|
|
||||||
using _Unchecked_type = counting_iterator; // Mark iterator as checked.
|
|
||||||
|
|
||||||
struct value_type {
|
|
||||||
template <typename T> void operator=(const T&) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
counting_iterator() : count_(0) {}
|
|
||||||
|
|
||||||
size_t count() const { return count_; }
|
|
||||||
|
|
||||||
counting_iterator& operator++() {
|
|
||||||
++count_;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
counting_iterator operator++(int) {
|
|
||||||
auto it = *this;
|
|
||||||
++*this;
|
|
||||||
return it;
|
|
||||||
}
|
|
||||||
|
|
||||||
friend counting_iterator operator+(counting_iterator it, difference_type n) {
|
|
||||||
it.count_ += static_cast<size_t>(n);
|
|
||||||
return it;
|
|
||||||
}
|
|
||||||
|
|
||||||
value_type operator*() const { return {}; }
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename Char, typename InputIt>
|
template <typename Char, typename InputIt>
|
||||||
inline counting_iterator copy_str(InputIt begin, InputIt end,
|
FMT_CONSTEXPR inline counting_iterator copy_str(InputIt begin, InputIt end,
|
||||||
counting_iterator it) {
|
counting_iterator it) {
|
||||||
return it + (end - begin);
|
return it + (end - begin);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename OutputIt> class truncating_iterator_base {
|
|
||||||
protected:
|
|
||||||
OutputIt out_;
|
|
||||||
size_t limit_;
|
|
||||||
size_t count_ = 0;
|
|
||||||
|
|
||||||
truncating_iterator_base() : out_(), limit_(0) {}
|
|
||||||
|
|
||||||
truncating_iterator_base(OutputIt out, size_t limit)
|
|
||||||
: out_(out), limit_(limit) {}
|
|
||||||
|
|
||||||
public:
|
|
||||||
using iterator_category = std::output_iterator_tag;
|
|
||||||
using value_type = typename std::iterator_traits<OutputIt>::value_type;
|
|
||||||
using difference_type = std::ptrdiff_t;
|
|
||||||
using pointer = void;
|
|
||||||
using reference = void;
|
|
||||||
using _Unchecked_type =
|
|
||||||
truncating_iterator_base; // Mark iterator as checked.
|
|
||||||
|
|
||||||
OutputIt base() const { return out_; }
|
|
||||||
size_t count() const { return count_; }
|
|
||||||
};
|
|
||||||
|
|
||||||
// An output iterator that truncates the output and counts the number of objects
|
|
||||||
// written to it.
|
|
||||||
template <typename OutputIt,
|
|
||||||
typename Enable = typename std::is_void<
|
|
||||||
typename std::iterator_traits<OutputIt>::value_type>::type>
|
|
||||||
class truncating_iterator;
|
|
||||||
|
|
||||||
template <typename OutputIt>
|
|
||||||
class truncating_iterator<OutputIt, std::false_type>
|
|
||||||
: public truncating_iterator_base<OutputIt> {
|
|
||||||
mutable typename truncating_iterator_base<OutputIt>::value_type blackhole_;
|
|
||||||
|
|
||||||
public:
|
|
||||||
using value_type = typename truncating_iterator_base<OutputIt>::value_type;
|
|
||||||
|
|
||||||
truncating_iterator() = default;
|
|
||||||
|
|
||||||
truncating_iterator(OutputIt out, size_t limit)
|
|
||||||
: truncating_iterator_base<OutputIt>(out, limit) {}
|
|
||||||
|
|
||||||
truncating_iterator& operator++() {
|
|
||||||
if (this->count_++ < this->limit_) ++this->out_;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
truncating_iterator operator++(int) {
|
|
||||||
auto it = *this;
|
|
||||||
++*this;
|
|
||||||
return it;
|
|
||||||
}
|
|
||||||
|
|
||||||
value_type& operator*() const {
|
|
||||||
return this->count_ < this->limit_ ? *this->out_ : blackhole_;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename OutputIt>
|
|
||||||
class truncating_iterator<OutputIt, std::true_type>
|
|
||||||
: public truncating_iterator_base<OutputIt> {
|
|
||||||
public:
|
|
||||||
truncating_iterator() = default;
|
|
||||||
|
|
||||||
truncating_iterator(OutputIt out, size_t limit)
|
|
||||||
: truncating_iterator_base<OutputIt>(out, limit) {}
|
|
||||||
|
|
||||||
template <typename T> truncating_iterator& operator=(T val) {
|
|
||||||
if (this->count_++ < this->limit_) *this->out_++ = val;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
truncating_iterator& operator++() { return *this; }
|
|
||||||
truncating_iterator& operator++(int) { return *this; }
|
|
||||||
truncating_iterator& operator*() { return *this; }
|
|
||||||
};
|
|
||||||
|
|
||||||
// A compile-time string which is compiled into fast formatting code.
|
// A compile-time string which is compiled into fast formatting code.
|
||||||
class compiled_string {};
|
class compiled_string {};
|
||||||
|
|
||||||
@@ -163,12 +45,12 @@ struct is_compiled_string : std::is_base_of<compiled_string, S> {};
|
|||||||
# define FMT_COMPILE(s) FMT_STRING(s)
|
# define FMT_COMPILE(s) FMT_STRING(s)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if FMT_USE_NONTYPE_TEMPLATE_PARAMETERS
|
#if FMT_USE_NONTYPE_TEMPLATE_ARGS
|
||||||
template <typename Char, size_t N,
|
template <typename Char, size_t N,
|
||||||
fmt::detail_exported::fixed_string<Char, N> Str>
|
fmt::detail_exported::fixed_string<Char, N> Str>
|
||||||
struct udl_compiled_string : compiled_string {
|
struct udl_compiled_string : compiled_string {
|
||||||
using char_type = Char;
|
using char_type = Char;
|
||||||
constexpr operator basic_string_view<char_type>() const {
|
explicit constexpr operator basic_string_view<char_type>() const {
|
||||||
return {Str.data, N - 1};
|
return {Str.data, N - 1};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -236,7 +118,8 @@ template <typename Char> struct code_unit {
|
|||||||
|
|
||||||
template <typename OutputIt, typename... Args>
|
template <typename OutputIt, typename... Args>
|
||||||
constexpr OutputIt format(OutputIt out, const Args&...) const {
|
constexpr OutputIt format(OutputIt out, const Args&...) const {
|
||||||
return write<Char>(out, value);
|
*out++ = value;
|
||||||
|
return out;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -260,7 +143,12 @@ template <typename Char, typename T, int N> struct field {
|
|||||||
|
|
||||||
template <typename OutputIt, typename... Args>
|
template <typename OutputIt, typename... Args>
|
||||||
constexpr OutputIt format(OutputIt out, const Args&... args) const {
|
constexpr OutputIt format(OutputIt out, const Args&... args) const {
|
||||||
return write<Char>(out, get_arg_checked<T, N>(args...));
|
const T& arg = get_arg_checked<T, N>(args...);
|
||||||
|
if constexpr (std::is_convertible_v<T, basic_string_view<Char>>) {
|
||||||
|
auto s = basic_string_view<Char>(arg);
|
||||||
|
return copy_str<Char>(s.begin(), s.end(), out);
|
||||||
|
}
|
||||||
|
return write<Char>(out, arg);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -371,38 +259,35 @@ template <typename T, typename Char> struct parse_specs_result {
|
|||||||
int next_arg_id;
|
int next_arg_id;
|
||||||
};
|
};
|
||||||
|
|
||||||
constexpr int manual_indexing_id = -1;
|
enum { manual_indexing_id = -1 };
|
||||||
|
|
||||||
template <typename T, typename Char>
|
template <typename T, typename Char>
|
||||||
constexpr parse_specs_result<T, Char> parse_specs(basic_string_view<Char> str,
|
constexpr parse_specs_result<T, Char> parse_specs(basic_string_view<Char> str,
|
||||||
size_t pos, int next_arg_id) {
|
size_t pos, int next_arg_id) {
|
||||||
str.remove_prefix(pos);
|
str.remove_prefix(pos);
|
||||||
auto ctx = basic_format_parse_context<Char>(str, {}, next_arg_id);
|
auto ctx =
|
||||||
|
compile_parse_context<Char>(str, max_value<int>(), nullptr, next_arg_id);
|
||||||
auto f = formatter<T, Char>();
|
auto f = formatter<T, Char>();
|
||||||
auto end = f.parse(ctx);
|
auto end = f.parse(ctx);
|
||||||
return {f, pos + fmt::detail::to_unsigned(end - str.data()) + 1,
|
return {f, pos + fmt::detail::to_unsigned(end - str.data()),
|
||||||
next_arg_id == 0 ? manual_indexing_id : ctx.next_arg_id()};
|
next_arg_id == 0 ? manual_indexing_id : ctx.next_arg_id()};
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Char> struct arg_id_handler {
|
template <typename Char> struct arg_id_handler {
|
||||||
arg_ref<Char> arg_id;
|
arg_ref<Char> arg_id;
|
||||||
|
|
||||||
constexpr int operator()() {
|
constexpr int on_auto() {
|
||||||
FMT_ASSERT(false, "handler cannot be used with automatic indexing");
|
FMT_ASSERT(false, "handler cannot be used with automatic indexing");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
constexpr int operator()(int id) {
|
constexpr int on_index(int id) {
|
||||||
arg_id = arg_ref<Char>(id);
|
arg_id = arg_ref<Char>(id);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
constexpr int operator()(basic_string_view<Char> id) {
|
constexpr int on_name(basic_string_view<Char> id) {
|
||||||
arg_id = arg_ref<Char>(id);
|
arg_id = arg_ref<Char>(id);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr void on_error(const char* message) {
|
|
||||||
FMT_THROW(format_error(message));
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename Char> struct parse_arg_id_result {
|
template <typename Char> struct parse_arg_id_result {
|
||||||
@@ -436,13 +321,20 @@ constexpr auto parse_replacement_field_then_tail(S format_str) {
|
|||||||
return parse_tail<Args, END_POS + 1, NEXT_ID>(
|
return parse_tail<Args, END_POS + 1, NEXT_ID>(
|
||||||
field<char_type, typename field_type<T>::type, ARG_INDEX>(),
|
field<char_type, typename field_type<T>::type, ARG_INDEX>(),
|
||||||
format_str);
|
format_str);
|
||||||
} else if constexpr (c == ':') {
|
} else if constexpr (c != ':') {
|
||||||
|
FMT_THROW(format_error("expected ':'"));
|
||||||
|
} else {
|
||||||
constexpr auto result = parse_specs<typename field_type<T>::type>(
|
constexpr auto result = parse_specs<typename field_type<T>::type>(
|
||||||
str, END_POS + 1, NEXT_ID == manual_indexing_id ? 0 : NEXT_ID);
|
str, END_POS + 1, NEXT_ID == manual_indexing_id ? 0 : NEXT_ID);
|
||||||
return parse_tail<Args, result.end, result.next_arg_id>(
|
if constexpr (result.end >= str.size() || str[result.end] != '}') {
|
||||||
spec_field<char_type, typename field_type<T>::type, ARG_INDEX>{
|
FMT_THROW(format_error("expected '}'"));
|
||||||
result.fmt},
|
return 0;
|
||||||
format_str);
|
} else {
|
||||||
|
return parse_tail<Args, result.end + 1, result.next_arg_id>(
|
||||||
|
spec_field<char_type, typename field_type<T>::type, ARG_INDEX>{
|
||||||
|
result.fmt},
|
||||||
|
format_str);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -484,20 +376,18 @@ constexpr auto compile_format_string(S format_str) {
|
|||||||
} else if constexpr (arg_id_result.arg_id.kind == arg_id_kind::name) {
|
} else if constexpr (arg_id_result.arg_id.kind == arg_id_kind::name) {
|
||||||
constexpr auto arg_index =
|
constexpr auto arg_index =
|
||||||
get_arg_index_by_name(arg_id_result.arg_id.val.name, Args{});
|
get_arg_index_by_name(arg_id_result.arg_id.val.name, Args{});
|
||||||
if constexpr (arg_index != invalid_arg_index) {
|
if constexpr (arg_index >= 0) {
|
||||||
constexpr auto next_id =
|
constexpr auto next_id =
|
||||||
ID != manual_indexing_id ? ID + 1 : manual_indexing_id;
|
ID != manual_indexing_id ? ID + 1 : manual_indexing_id;
|
||||||
return parse_replacement_field_then_tail<
|
return parse_replacement_field_then_tail<
|
||||||
decltype(get_type<arg_index, Args>::value), Args, arg_id_end_pos,
|
decltype(get_type<arg_index, Args>::value), Args, arg_id_end_pos,
|
||||||
arg_index, next_id>(format_str);
|
arg_index, next_id>(format_str);
|
||||||
} else {
|
} else if constexpr (c == '}') {
|
||||||
if constexpr (c == '}') {
|
return parse_tail<Args, arg_id_end_pos + 1, ID>(
|
||||||
return parse_tail<Args, arg_id_end_pos + 1, ID>(
|
runtime_named_field<char_type>{arg_id_result.arg_id.val.name},
|
||||||
runtime_named_field<char_type>{arg_id_result.arg_id.val.name},
|
format_str);
|
||||||
format_str);
|
} else if constexpr (c == ':') {
|
||||||
} else if constexpr (c == ':') {
|
return unknown_format(); // no type info for specs parsing
|
||||||
return unknown_format(); // no type info for specs parsing
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -533,7 +423,7 @@ constexpr auto compile(S format_str) {
|
|||||||
#endif // defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction)
|
#endif // defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction)
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
|
|
||||||
FMT_MODULE_EXPORT_BEGIN
|
FMT_BEGIN_EXPORT
|
||||||
|
|
||||||
#if defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction)
|
#if defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction)
|
||||||
|
|
||||||
@@ -573,10 +463,11 @@ FMT_INLINE std::basic_string<typename S::char_type> format(const S&,
|
|||||||
constexpr auto compiled = detail::compile<Args...>(S());
|
constexpr auto compiled = detail::compile<Args...>(S());
|
||||||
if constexpr (std::is_same<remove_cvref_t<decltype(compiled)>,
|
if constexpr (std::is_same<remove_cvref_t<decltype(compiled)>,
|
||||||
detail::unknown_format>()) {
|
detail::unknown_format>()) {
|
||||||
return format(static_cast<basic_string_view<typename S::char_type>>(S()),
|
return fmt::format(
|
||||||
std::forward<Args>(args)...);
|
static_cast<basic_string_view<typename S::char_type>>(S()),
|
||||||
|
std::forward<Args>(args)...);
|
||||||
} else {
|
} else {
|
||||||
return format(compiled, std::forward<Args>(args)...);
|
return fmt::format(compiled, std::forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -586,11 +477,11 @@ FMT_CONSTEXPR OutputIt format_to(OutputIt out, const S&, Args&&... args) {
|
|||||||
constexpr auto compiled = detail::compile<Args...>(S());
|
constexpr auto compiled = detail::compile<Args...>(S());
|
||||||
if constexpr (std::is_same<remove_cvref_t<decltype(compiled)>,
|
if constexpr (std::is_same<remove_cvref_t<decltype(compiled)>,
|
||||||
detail::unknown_format>()) {
|
detail::unknown_format>()) {
|
||||||
return format_to(out,
|
return fmt::format_to(
|
||||||
static_cast<basic_string_view<typename S::char_type>>(S()),
|
out, static_cast<basic_string_view<typename S::char_type>>(S()),
|
||||||
std::forward<Args>(args)...);
|
std::forward<Args>(args)...);
|
||||||
} else {
|
} else {
|
||||||
return format_to(out, compiled, std::forward<Args>(args)...);
|
return fmt::format_to(out, compiled, std::forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -599,22 +490,25 @@ template <typename OutputIt, typename S, typename... Args,
|
|||||||
FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
|
FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
|
||||||
format_to_n_result<OutputIt> format_to_n(OutputIt out, size_t n,
|
format_to_n_result<OutputIt> format_to_n(OutputIt out, size_t n,
|
||||||
const S& format_str, Args&&... args) {
|
const S& format_str, Args&&... args) {
|
||||||
auto it = format_to(detail::truncating_iterator<OutputIt>(out, n), format_str,
|
using traits = detail::fixed_buffer_traits;
|
||||||
std::forward<Args>(args)...);
|
auto buf = detail::iterator_buffer<OutputIt, char, traits>(out, n);
|
||||||
return {it.base(), it.count()};
|
format_to(std::back_inserter(buf), format_str, std::forward<Args>(args)...);
|
||||||
|
return {buf.out(), buf.count()};
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename S, typename... Args,
|
template <typename S, typename... Args,
|
||||||
FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
|
FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
|
||||||
size_t formatted_size(const S& format_str, const Args&... args) {
|
FMT_CONSTEXPR20 size_t formatted_size(const S& format_str,
|
||||||
return format_to(detail::counting_iterator(), format_str, args...).count();
|
const Args&... args) {
|
||||||
|
return fmt::format_to(detail::counting_iterator(), format_str, args...)
|
||||||
|
.count();
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename S, typename... Args,
|
template <typename S, typename... Args,
|
||||||
FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
|
FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
|
||||||
void print(std::FILE* f, const S& format_str, const Args&... args) {
|
void print(std::FILE* f, const S& format_str, const Args&... args) {
|
||||||
memory_buffer buffer;
|
memory_buffer buffer;
|
||||||
format_to(std::back_inserter(buffer), format_str, args...);
|
fmt::format_to(std::back_inserter(buffer), format_str, args...);
|
||||||
detail::print(f, {buffer.data(), buffer.size()});
|
detail::print(f, {buffer.data(), buffer.size()});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -624,19 +518,17 @@ void print(const S& format_str, const Args&... args) {
|
|||||||
print(stdout, format_str, args...);
|
print(stdout, format_str, args...);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if FMT_USE_NONTYPE_TEMPLATE_PARAMETERS
|
#if FMT_USE_NONTYPE_TEMPLATE_ARGS
|
||||||
inline namespace literals {
|
inline namespace literals {
|
||||||
template <detail_exported::fixed_string Str>
|
template <detail_exported::fixed_string Str> constexpr auto operator""_cf() {
|
||||||
constexpr detail::udl_compiled_string<
|
using char_t = remove_cvref_t<decltype(Str.data[0])>;
|
||||||
remove_cvref_t<decltype(Str.data[0])>,
|
return detail::udl_compiled_string<char_t, sizeof(Str.data) / sizeof(char_t),
|
||||||
sizeof(Str.data) / sizeof(decltype(Str.data[0])), Str>
|
Str>();
|
||||||
operator""_cf() {
|
|
||||||
return {};
|
|
||||||
}
|
}
|
||||||
} // namespace literals
|
} // namespace literals
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
FMT_MODULE_EXPORT_END
|
FMT_END_EXPORT
|
||||||
FMT_END_NAMESPACE
|
FMT_END_NAMESPACE
|
||||||
|
|
||||||
#endif // FMT_COMPILE_H_
|
#endif // FMT_COMPILE_H_
|
||||||
|
|||||||
2248
deps/fmt/include/fmt/core.h
vendored
2248
deps/fmt/include/fmt/core.h
vendored
File diff suppressed because it is too large
Load Diff
2620
deps/fmt/include/fmt/format-inl.h
vendored
2620
deps/fmt/include/fmt/format-inl.h
vendored
File diff suppressed because it is too large
Load Diff
3052
deps/fmt/include/fmt/format.h
vendored
3052
deps/fmt/include/fmt/format.h
vendored
File diff suppressed because it is too large
Load Diff
2
deps/fmt/include/fmt/locale.h
vendored
2
deps/fmt/include/fmt/locale.h
vendored
@@ -1,2 +0,0 @@
|
|||||||
#include "xchar.h"
|
|
||||||
#warning fmt/locale.h is deprecated, include fmt/format.h or fmt/xchar.h instead
|
|
||||||
217
deps/fmt/include/fmt/os.h
vendored
217
deps/fmt/include/fmt/os.h
vendored
@@ -9,10 +9,8 @@
|
|||||||
#define FMT_OS_H_
|
#define FMT_OS_H_
|
||||||
|
|
||||||
#include <cerrno>
|
#include <cerrno>
|
||||||
#include <clocale> // locale_t
|
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <cstdlib> // strtod_l
|
|
||||||
#include <system_error> // std::system_error
|
#include <system_error> // std::system_error
|
||||||
|
|
||||||
#if defined __APPLE__ || defined(__FreeBSD__)
|
#if defined __APPLE__ || defined(__FreeBSD__)
|
||||||
@@ -73,7 +71,7 @@
|
|||||||
#define FMT_RETRY(result, expression) FMT_RETRY_VAL(result, expression, -1)
|
#define FMT_RETRY(result, expression) FMT_RETRY_VAL(result, expression, -1)
|
||||||
|
|
||||||
FMT_BEGIN_NAMESPACE
|
FMT_BEGIN_NAMESPACE
|
||||||
FMT_MODULE_EXPORT_BEGIN
|
FMT_BEGIN_EXPORT
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\rst
|
\rst
|
||||||
@@ -122,51 +120,13 @@ template <typename Char> class basic_cstring_view {
|
|||||||
using cstring_view = basic_cstring_view<char>;
|
using cstring_view = basic_cstring_view<char>;
|
||||||
using wcstring_view = basic_cstring_view<wchar_t>;
|
using wcstring_view = basic_cstring_view<wchar_t>;
|
||||||
|
|
||||||
template <typename Char> struct formatter<std::error_code, Char> {
|
|
||||||
template <typename ParseContext>
|
|
||||||
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
|
|
||||||
return ctx.begin();
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename FormatContext>
|
|
||||||
FMT_CONSTEXPR auto format(const std::error_code& ec, FormatContext& ctx) const
|
|
||||||
-> decltype(ctx.out()) {
|
|
||||||
auto out = ctx.out();
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
FMT_API const std::error_category& system_category() FMT_NOEXCEPT;
|
FMT_API const std::error_category& system_category() noexcept;
|
||||||
|
|
||||||
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 {
|
|
||||||
private:
|
|
||||||
memory_buffer buffer_;
|
|
||||||
|
|
||||||
public:
|
|
||||||
utf16_to_utf8() {}
|
|
||||||
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]; }
|
|
||||||
std::string str() const { return std::string(&buffer_[0], size()); }
|
|
||||||
|
|
||||||
// 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(basic_string_view<wchar_t> s);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
FMT_API void format_windows_error(buffer<char>& out, int error_code,
|
FMT_API void format_windows_error(buffer<char>& out, int error_code,
|
||||||
const char* message) FMT_NOEXCEPT;
|
const char* message) noexcept;
|
||||||
FMT_END_DETAIL_NAMESPACE
|
}
|
||||||
|
|
||||||
FMT_API std::system_error vwindows_error(int error_code, string_view format_str,
|
FMT_API std::system_error vwindows_error(int error_code, string_view format_str,
|
||||||
format_args args);
|
format_args args);
|
||||||
@@ -207,10 +167,9 @@ std::system_error windows_error(int error_code, string_view message,
|
|||||||
|
|
||||||
// Reports a Windows error without throwing an exception.
|
// Reports a Windows error without throwing an exception.
|
||||||
// Can be used to report errors from destructors.
|
// Can be used to report errors from destructors.
|
||||||
FMT_API void report_windows_error(int error_code,
|
FMT_API void report_windows_error(int error_code, const char* message) noexcept;
|
||||||
const char* message) FMT_NOEXCEPT;
|
|
||||||
#else
|
#else
|
||||||
inline const std::error_category& system_category() FMT_NOEXCEPT {
|
inline const std::error_category& system_category() noexcept {
|
||||||
return std::system_category();
|
return std::system_category();
|
||||||
}
|
}
|
||||||
#endif // _WIN32
|
#endif // _WIN32
|
||||||
@@ -237,13 +196,13 @@ class buffered_file {
|
|||||||
void operator=(const buffered_file&) = delete;
|
void operator=(const buffered_file&) = delete;
|
||||||
|
|
||||||
// Constructs a buffered_file object which doesn't represent any file.
|
// Constructs a buffered_file object which doesn't represent any file.
|
||||||
buffered_file() FMT_NOEXCEPT : file_(nullptr) {}
|
buffered_file() noexcept : file_(nullptr) {}
|
||||||
|
|
||||||
// Destroys the object closing the file it represents if any.
|
// Destroys the object closing the file it represents if any.
|
||||||
FMT_API ~buffered_file() FMT_NOEXCEPT;
|
FMT_API ~buffered_file() noexcept;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
buffered_file(buffered_file&& other) FMT_NOEXCEPT : file_(other.file_) {
|
buffered_file(buffered_file&& other) noexcept : file_(other.file_) {
|
||||||
other.file_ = nullptr;
|
other.file_ = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -261,12 +220,9 @@ class buffered_file {
|
|||||||
FMT_API void close();
|
FMT_API void close();
|
||||||
|
|
||||||
// Returns the pointer to a FILE object representing this file.
|
// Returns the pointer to a FILE object representing this file.
|
||||||
FILE* get() const FMT_NOEXCEPT { return file_; }
|
FILE* get() const noexcept { return file_; }
|
||||||
|
|
||||||
// We place parentheses around fileno to workaround a bug in some versions
|
FMT_API int descriptor() const;
|
||||||
// of MinGW that define fileno as a macro.
|
|
||||||
// DEPRECATED! Rename to descriptor to avoid issues with macros.
|
|
||||||
FMT_API int(fileno)() const;
|
|
||||||
|
|
||||||
void vprint(string_view format_str, format_args args) {
|
void vprint(string_view format_str, format_args args) {
|
||||||
fmt::vprint(file_, format_str, args);
|
fmt::vprint(file_, format_str, args);
|
||||||
@@ -280,12 +236,12 @@ class buffered_file {
|
|||||||
|
|
||||||
#if FMT_USE_FCNTL
|
#if FMT_USE_FCNTL
|
||||||
// A file. Closed file is represented by a file object with descriptor -1.
|
// A file. Closed file is represented by a file object with descriptor -1.
|
||||||
// Methods that are not declared with FMT_NOEXCEPT may throw
|
// Methods that are not declared with noexcept may throw
|
||||||
// fmt::system_error in case of failure. Note that some errors such as
|
// fmt::system_error in case of failure. Note that some errors such as
|
||||||
// closing the file multiple times will cause a crash on Windows rather
|
// closing the file multiple times will cause a crash on Windows rather
|
||||||
// than an exception. You can get standard behavior by overriding the
|
// than an exception. You can get standard behavior by overriding the
|
||||||
// invalid parameter handler with _set_invalid_parameter_handler.
|
// invalid parameter handler with _set_invalid_parameter_handler.
|
||||||
class file {
|
class FMT_API file {
|
||||||
private:
|
private:
|
||||||
int fd_; // File descriptor.
|
int fd_; // File descriptor.
|
||||||
|
|
||||||
@@ -304,16 +260,16 @@ class file {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Constructs a file object which doesn't represent any file.
|
// Constructs a file object which doesn't represent any file.
|
||||||
file() FMT_NOEXCEPT : fd_(-1) {}
|
file() noexcept : fd_(-1) {}
|
||||||
|
|
||||||
// Opens a file and constructs a file object representing this file.
|
// Opens a file and constructs a file object representing this file.
|
||||||
FMT_API file(cstring_view path, int oflag);
|
file(cstring_view path, int oflag);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
file(const file&) = delete;
|
file(const file&) = delete;
|
||||||
void operator=(const file&) = delete;
|
void operator=(const file&) = delete;
|
||||||
|
|
||||||
file(file&& other) FMT_NOEXCEPT : fd_(other.fd_) { other.fd_ = -1; }
|
file(file&& other) noexcept : fd_(other.fd_) { other.fd_ = -1; }
|
||||||
|
|
||||||
// Move assignment is not noexcept because close may throw.
|
// Move assignment is not noexcept because close may throw.
|
||||||
file& operator=(file&& other) {
|
file& operator=(file&& other) {
|
||||||
@@ -324,49 +280,55 @@ class file {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Destroys the object closing the file it represents if any.
|
// Destroys the object closing the file it represents if any.
|
||||||
FMT_API ~file() FMT_NOEXCEPT;
|
~file() noexcept;
|
||||||
|
|
||||||
// Returns the file descriptor.
|
// Returns the file descriptor.
|
||||||
int descriptor() const FMT_NOEXCEPT { return fd_; }
|
int descriptor() const noexcept { return fd_; }
|
||||||
|
|
||||||
// Closes the file.
|
// Closes the file.
|
||||||
FMT_API void close();
|
void close();
|
||||||
|
|
||||||
// Returns the file size. The size has signed type for consistency with
|
// Returns the file size. The size has signed type for consistency with
|
||||||
// stat::st_size.
|
// stat::st_size.
|
||||||
FMT_API long long size() const;
|
long long size() const;
|
||||||
|
|
||||||
// Attempts to read count bytes from the file into the specified buffer.
|
// Attempts to read count bytes from the file into the specified buffer.
|
||||||
FMT_API size_t read(void* buffer, size_t count);
|
size_t read(void* buffer, size_t count);
|
||||||
|
|
||||||
// Attempts to write count bytes from the specified buffer to the file.
|
// Attempts to write count bytes from the specified buffer to the file.
|
||||||
FMT_API size_t write(const void* buffer, size_t count);
|
size_t write(const void* buffer, size_t count);
|
||||||
|
|
||||||
// Duplicates a file descriptor with the dup function and returns
|
// Duplicates a file descriptor with the dup function and returns
|
||||||
// the duplicate as a file object.
|
// the duplicate as a file object.
|
||||||
FMT_API static file dup(int fd);
|
static file dup(int fd);
|
||||||
|
|
||||||
// Makes fd be the copy of this file descriptor, closing fd first if
|
// Makes fd be the copy of this file descriptor, closing fd first if
|
||||||
// necessary.
|
// necessary.
|
||||||
FMT_API void dup2(int fd);
|
void dup2(int fd);
|
||||||
|
|
||||||
// Makes fd be the copy of this file descriptor, closing fd first if
|
// Makes fd be the copy of this file descriptor, closing fd first if
|
||||||
// necessary.
|
// necessary.
|
||||||
FMT_API void dup2(int fd, std::error_code& ec) FMT_NOEXCEPT;
|
void dup2(int fd, std::error_code& ec) noexcept;
|
||||||
|
|
||||||
// Creates a pipe setting up read_end and write_end file objects for reading
|
// Creates a pipe setting up read_end and write_end file objects for reading
|
||||||
// and writing respectively.
|
// and writing respectively.
|
||||||
FMT_API static void pipe(file& read_end, file& write_end);
|
static void pipe(file& read_end, file& write_end);
|
||||||
|
|
||||||
// Creates a buffered_file object associated with this file and detaches
|
// Creates a buffered_file object associated with this file and detaches
|
||||||
// this file object from the file.
|
// this file object from the file.
|
||||||
FMT_API buffered_file fdopen(const char* mode);
|
buffered_file fdopen(const char* mode);
|
||||||
|
|
||||||
|
# if defined(_WIN32) && !defined(__MINGW32__)
|
||||||
|
// Opens a file and constructs a file object representing this file by
|
||||||
|
// wcstring_view filename. Windows only.
|
||||||
|
static file open_windows_file(wcstring_view path, int oflag);
|
||||||
|
# endif
|
||||||
};
|
};
|
||||||
|
|
||||||
// Returns the memory page size.
|
// Returns the memory page size.
|
||||||
long getpagesize();
|
long getpagesize();
|
||||||
|
|
||||||
FMT_BEGIN_DETAIL_NAMESPACE
|
namespace detail {
|
||||||
|
|
||||||
struct buffer_size {
|
struct buffer_size {
|
||||||
buffer_size() = default;
|
buffer_size() = default;
|
||||||
@@ -403,56 +365,61 @@ struct ostream_params {
|
|||||||
# endif
|
# endif
|
||||||
};
|
};
|
||||||
|
|
||||||
FMT_END_DETAIL_NAMESPACE
|
class file_buffer final : public buffer<char> {
|
||||||
|
file file_;
|
||||||
|
|
||||||
|
FMT_API void grow(size_t) override;
|
||||||
|
|
||||||
|
public:
|
||||||
|
FMT_API file_buffer(cstring_view path, const ostream_params& params);
|
||||||
|
FMT_API file_buffer(file_buffer&& other);
|
||||||
|
FMT_API ~file_buffer();
|
||||||
|
|
||||||
|
void flush() {
|
||||||
|
if (size() == 0) return;
|
||||||
|
file_.write(data(), size() * sizeof(data()[0]));
|
||||||
|
clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void close() {
|
||||||
|
flush();
|
||||||
|
file_.close();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
// Added {} below to work around default constructor error known to
|
// Added {} below to work around default constructor error known to
|
||||||
// occur in Xcode versions 7.2.1 and 8.2.1.
|
// occur in Xcode versions 7.2.1 and 8.2.1.
|
||||||
constexpr detail::buffer_size buffer_size{};
|
constexpr detail::buffer_size buffer_size{};
|
||||||
|
|
||||||
/** A fast output stream which is not thread-safe. */
|
/** A fast output stream which is not thread-safe. */
|
||||||
class FMT_API ostream final : private detail::buffer<char> {
|
class FMT_API ostream {
|
||||||
private:
|
private:
|
||||||
file file_;
|
FMT_MSC_WARNING(suppress : 4251)
|
||||||
|
detail::file_buffer buffer_;
|
||||||
void grow(size_t) override;
|
|
||||||
|
|
||||||
ostream(cstring_view path, const detail::ostream_params& params)
|
ostream(cstring_view path, const detail::ostream_params& params)
|
||||||
: file_(path, params.oflag) {
|
: buffer_(path, params) {}
|
||||||
set(new char[params.buffer_size], params.buffer_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ostream(ostream&& other)
|
ostream(ostream&& other) : buffer_(std::move(other.buffer_)) {}
|
||||||
: detail::buffer<char>(other.data(), other.size(), other.capacity()),
|
|
||||||
file_(std::move(other.file_)) {
|
|
||||||
other.clear();
|
|
||||||
other.set(nullptr, 0);
|
|
||||||
}
|
|
||||||
~ostream() {
|
|
||||||
flush();
|
|
||||||
delete[] data();
|
|
||||||
}
|
|
||||||
|
|
||||||
void flush() {
|
~ostream();
|
||||||
if (size() == 0) return;
|
|
||||||
file_.write(data(), size());
|
void flush() { buffer_.flush(); }
|
||||||
clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename... T>
|
template <typename... T>
|
||||||
friend ostream output_file(cstring_view path, T... params);
|
friend ostream output_file(cstring_view path, T... params);
|
||||||
|
|
||||||
void close() {
|
void close() { buffer_.close(); }
|
||||||
flush();
|
|
||||||
file_.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Formats ``args`` according to specifications in ``fmt`` and writes the
|
Formats ``args`` according to specifications in ``fmt`` and writes the
|
||||||
output to the file.
|
output to the file.
|
||||||
*/
|
*/
|
||||||
template <typename... T> void print(format_string<T...> fmt, T&&... args) {
|
template <typename... T> void print(format_string<T...> fmt, T&&... args) {
|
||||||
vformat_to(detail::buffer_appender<char>(*this), fmt,
|
vformat_to(detail::buffer_appender<char>(buffer_), fmt,
|
||||||
fmt::make_format_args(args...));
|
fmt::make_format_args(args...));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -463,7 +430,7 @@ class FMT_API ostream final : private detail::buffer<char> {
|
|||||||
|
|
||||||
* ``<integer>``: Flags passed to `open
|
* ``<integer>``: Flags passed to `open
|
||||||
<https://pubs.opengroup.org/onlinepubs/007904875/functions/open.html>`_
|
<https://pubs.opengroup.org/onlinepubs/007904875/functions/open.html>`_
|
||||||
(``file::WRONLY | file::CREATE`` by default)
|
(``file::WRONLY | file::CREATE | file::TRUNC`` by default)
|
||||||
* ``buffer_size=<integer>``: Output buffer size
|
* ``buffer_size=<integer>``: Output buffer size
|
||||||
|
|
||||||
**Example**::
|
**Example**::
|
||||||
@@ -478,51 +445,7 @@ inline ostream output_file(cstring_view path, T... params) {
|
|||||||
}
|
}
|
||||||
#endif // FMT_USE_FCNTL
|
#endif // FMT_USE_FCNTL
|
||||||
|
|
||||||
#ifdef FMT_LOCALE
|
FMT_END_EXPORT
|
||||||
// A "C" numeric locale.
|
|
||||||
class locale {
|
|
||||||
private:
|
|
||||||
# ifdef _WIN32
|
|
||||||
using locale_t = _locale_t;
|
|
||||||
|
|
||||||
static void freelocale(locale_t loc) { _free_locale(loc); }
|
|
||||||
|
|
||||||
static double strtod_l(const char* nptr, char** endptr, _locale_t loc) {
|
|
||||||
return _strtod_l(nptr, endptr, loc);
|
|
||||||
}
|
|
||||||
# endif
|
|
||||||
|
|
||||||
locale_t locale_;
|
|
||||||
|
|
||||||
public:
|
|
||||||
using type = locale_t;
|
|
||||||
locale(const locale&) = delete;
|
|
||||||
void operator=(const locale&) = delete;
|
|
||||||
|
|
||||||
locale() {
|
|
||||||
# ifndef _WIN32
|
|
||||||
locale_ = FMT_SYSTEM(newlocale(LC_NUMERIC_MASK, "C", nullptr));
|
|
||||||
# else
|
|
||||||
locale_ = _create_locale(LC_NUMERIC, "C");
|
|
||||||
# endif
|
|
||||||
if (!locale_) FMT_THROW(system_error(errno, "cannot create locale"));
|
|
||||||
}
|
|
||||||
~locale() { freelocale(locale_); }
|
|
||||||
|
|
||||||
type get() const { return locale_; }
|
|
||||||
|
|
||||||
// Converts string to floating-point number and advances str past the end
|
|
||||||
// of the parsed input.
|
|
||||||
FMT_DEPRECATED double strtod(const char*& str) const {
|
|
||||||
char* end = nullptr;
|
|
||||||
double result = strtod_l(str, &end, locale_);
|
|
||||||
str = end;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
using Locale FMT_DEPRECATED_ALIAS = locale;
|
|
||||||
#endif // FMT_LOCALE
|
|
||||||
FMT_MODULE_EXPORT_END
|
|
||||||
FMT_END_NAMESPACE
|
FMT_END_NAMESPACE
|
||||||
|
|
||||||
#endif // FMT_OS_H_
|
#endif // FMT_OS_H_
|
||||||
|
|||||||
184
deps/fmt/include/fmt/ostream.h
vendored
184
deps/fmt/include/fmt/ostream.h
vendored
@@ -8,47 +8,67 @@
|
|||||||
#ifndef FMT_OSTREAM_H_
|
#ifndef FMT_OSTREAM_H_
|
||||||
#define FMT_OSTREAM_H_
|
#define FMT_OSTREAM_H_
|
||||||
|
|
||||||
#include <ostream>
|
#include <fstream> // std::filebuf
|
||||||
|
|
||||||
|
#if defined(_WIN32) && defined(__GLIBCXX__)
|
||||||
|
# include <ext/stdio_filebuf.h>
|
||||||
|
# include <ext/stdio_sync_filebuf.h>
|
||||||
|
#elif defined(_WIN32) && defined(_LIBCPP_VERSION)
|
||||||
|
# include <__std_stream>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "format.h"
|
#include "format.h"
|
||||||
|
|
||||||
FMT_BEGIN_NAMESPACE
|
FMT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
template <typename OutputIt, typename Char> class basic_printf_context;
|
|
||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
|
||||||
// Checks if T has a user-defined operator<<.
|
// Generate a unique explicit instantion in every translation unit using a tag
|
||||||
template <typename T, typename Char, typename Enable = void>
|
// type in an anonymous namespace.
|
||||||
class is_streamable {
|
namespace {
|
||||||
private:
|
struct file_access_tag {};
|
||||||
template <typename U>
|
} // namespace
|
||||||
static auto test(int)
|
template <typename Tag, typename BufType, FILE* BufType::*FileMemberPtr>
|
||||||
-> bool_constant<sizeof(std::declval<std::basic_ostream<Char>&>()
|
class file_access {
|
||||||
<< std::declval<U>()) != 0>;
|
friend auto get_file(BufType& obj) -> FILE* { return obj.*FileMemberPtr; }
|
||||||
|
|
||||||
template <typename> static auto test(...) -> std::false_type;
|
|
||||||
|
|
||||||
using result = decltype(test<T>(0));
|
|
||||||
|
|
||||||
public:
|
|
||||||
is_streamable() = default;
|
|
||||||
|
|
||||||
static const bool value = result::value;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Formatting of built-in types and arrays is intentionally disabled because
|
#if FMT_MSC_VERSION
|
||||||
// it's handled by standard (non-ostream) formatters.
|
template class file_access<file_access_tag, std::filebuf,
|
||||||
template <typename T, typename Char>
|
&std::filebuf::_Myfile>;
|
||||||
struct is_streamable<
|
auto get_file(std::filebuf&) -> FILE*;
|
||||||
T, Char,
|
#elif defined(_WIN32) && defined(_LIBCPP_VERSION)
|
||||||
enable_if_t<
|
template class file_access<file_access_tag, std::__stdoutbuf<char>,
|
||||||
std::is_arithmetic<T>::value || std::is_array<T>::value ||
|
&std::__stdoutbuf<char>::__file_>;
|
||||||
std::is_pointer<T>::value || std::is_same<T, char8_type>::value ||
|
auto get_file(std::__stdoutbuf<char>&) -> FILE*;
|
||||||
std::is_same<T, std::basic_string<Char>>::value ||
|
#endif
|
||||||
std::is_same<T, std_string_view<Char>>::value ||
|
|
||||||
(std::is_convertible<T, int>::value && !std::is_enum<T>::value)>>
|
inline bool write_ostream_unicode(std::ostream& os, fmt::string_view data) {
|
||||||
: std::false_type {};
|
#if FMT_MSC_VERSION
|
||||||
|
if (auto* buf = dynamic_cast<std::filebuf*>(os.rdbuf()))
|
||||||
|
if (FILE* f = get_file(*buf)) return write_console(f, data);
|
||||||
|
#elif defined(_WIN32) && defined(__GLIBCXX__)
|
||||||
|
auto* rdbuf = os.rdbuf();
|
||||||
|
FILE* c_file;
|
||||||
|
if (auto* sfbuf = dynamic_cast<__gnu_cxx::stdio_sync_filebuf<char>*>(rdbuf))
|
||||||
|
c_file = sfbuf->file();
|
||||||
|
else if (auto* fbuf = dynamic_cast<__gnu_cxx::stdio_filebuf<char>*>(rdbuf))
|
||||||
|
c_file = fbuf->file();
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
if (c_file) return write_console(c_file, data);
|
||||||
|
#elif defined(_WIN32) && defined(_LIBCPP_VERSION)
|
||||||
|
if (auto* buf = dynamic_cast<std::__stdoutbuf<char>*>(os.rdbuf()))
|
||||||
|
if (FILE* f = get_file(*buf)) return write_console(f, data);
|
||||||
|
#else
|
||||||
|
ignore_unused(os, data);
|
||||||
|
#endif
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
inline bool write_ostream_unicode(std::wostream&,
|
||||||
|
fmt::basic_string_view<wchar_t>) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// Write the content of buf to os.
|
// Write the content of buf to os.
|
||||||
// It is a separate function rather than a part of vprint to simplify testing.
|
// It is a separate function rather than a part of vprint to simplify testing.
|
||||||
@@ -76,41 +96,72 @@ void format_value(buffer<Char>& buf, const T& value,
|
|||||||
#endif
|
#endif
|
||||||
output << value;
|
output << value;
|
||||||
output.exceptions(std::ios_base::failbit | std::ios_base::badbit);
|
output.exceptions(std::ios_base::failbit | std::ios_base::badbit);
|
||||||
buf.try_resize(buf.size());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Formats an object of type T that has an overloaded ostream operator<<.
|
template <typename T> struct streamed_view { const T& value; };
|
||||||
template <typename T, typename Char>
|
|
||||||
struct fallback_formatter<T, Char, enable_if_t<is_streamable<T, Char>::value>>
|
|
||||||
: private formatter<basic_string_view<Char>, Char> {
|
|
||||||
using formatter<basic_string_view<Char>, Char>::parse;
|
|
||||||
|
|
||||||
template <typename OutputIt>
|
} // namespace detail
|
||||||
|
|
||||||
|
// Formats an object of type T that has an overloaded ostream operator<<.
|
||||||
|
template <typename Char>
|
||||||
|
struct basic_ostream_formatter : formatter<basic_string_view<Char>, Char> {
|
||||||
|
void set_debug_format() = delete;
|
||||||
|
|
||||||
|
template <typename T, typename OutputIt>
|
||||||
auto format(const T& value, basic_format_context<OutputIt, Char>& ctx) const
|
auto format(const T& value, basic_format_context<OutputIt, Char>& ctx) const
|
||||||
-> OutputIt {
|
-> OutputIt {
|
||||||
auto buffer = basic_memory_buffer<Char>();
|
auto buffer = basic_memory_buffer<Char>();
|
||||||
format_value(buffer, value, ctx.locale());
|
detail::format_value(buffer, value, ctx.locale());
|
||||||
return formatter<basic_string_view<Char>, Char>::format(
|
return formatter<basic_string_view<Char>, Char>::format(
|
||||||
{buffer.data(), buffer.size()}, ctx);
|
{buffer.data(), buffer.size()}, ctx);
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// DEPRECATED!
|
using ostream_formatter = basic_ostream_formatter<char>;
|
||||||
|
|
||||||
|
template <typename T, typename Char>
|
||||||
|
struct formatter<detail::streamed_view<T>, Char>
|
||||||
|
: basic_ostream_formatter<Char> {
|
||||||
template <typename OutputIt>
|
template <typename OutputIt>
|
||||||
auto format(const T& value, basic_printf_context<OutputIt, Char>& ctx) const
|
auto format(detail::streamed_view<T> view,
|
||||||
-> OutputIt {
|
basic_format_context<OutputIt, Char>& ctx) const -> OutputIt {
|
||||||
auto buffer = basic_memory_buffer<Char>();
|
return basic_ostream_formatter<Char>::format(view.value, ctx);
|
||||||
format_value(buffer, value, ctx.locale());
|
|
||||||
return std::copy(buffer.begin(), buffer.end(), ctx.out());
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
\rst
|
||||||
|
Returns a view that formats `value` via an ostream ``operator<<``.
|
||||||
|
|
||||||
|
**Example**::
|
||||||
|
|
||||||
|
fmt::print("Current thread id: {}\n",
|
||||||
|
fmt::streamed(std::this_thread::get_id()));
|
||||||
|
\endrst
|
||||||
|
*/
|
||||||
|
template <typename T>
|
||||||
|
auto streamed(const T& value) -> detail::streamed_view<T> {
|
||||||
|
return {value};
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
inline void vprint_directly(std::ostream& os, string_view format_str,
|
||||||
|
format_args args) {
|
||||||
|
auto buffer = memory_buffer();
|
||||||
|
detail::vformat_to(buffer, format_str, args);
|
||||||
|
detail::write_buffer(os, buffer);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
|
|
||||||
FMT_MODULE_EXPORT
|
FMT_EXPORT template <typename Char>
|
||||||
template <typename Char>
|
void vprint(std::basic_ostream<Char>& os,
|
||||||
void vprint(std::basic_ostream<Char>& os, basic_string_view<Char> format_str,
|
basic_string_view<type_identity_t<Char>> format_str,
|
||||||
basic_format_args<buffer_context<type_identity_t<Char>>> args) {
|
basic_format_args<buffer_context<type_identity_t<Char>>> args) {
|
||||||
auto buffer = basic_memory_buffer<Char>();
|
auto buffer = basic_memory_buffer<Char>();
|
||||||
detail::vformat_to(buffer, format_str, args);
|
detail::vformat_to(buffer, format_str, args);
|
||||||
|
if (detail::write_ostream_unicode(os, {buffer.data(), buffer.size()})) return;
|
||||||
detail::write_buffer(os, buffer);
|
detail::write_buffer(os, buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -123,13 +174,36 @@ void vprint(std::basic_ostream<Char>& os, basic_string_view<Char> format_str,
|
|||||||
fmt::print(cerr, "Don't {}!", "panic");
|
fmt::print(cerr, "Don't {}!", "panic");
|
||||||
\endrst
|
\endrst
|
||||||
*/
|
*/
|
||||||
FMT_MODULE_EXPORT
|
FMT_EXPORT template <typename... T>
|
||||||
template <typename S, typename... Args,
|
void print(std::ostream& os, format_string<T...> fmt, T&&... args) {
|
||||||
typename Char = enable_if_t<detail::is_string<S>::value, char_t<S>>>
|
const auto& vargs = fmt::make_format_args(args...);
|
||||||
void print(std::basic_ostream<Char>& os, const S& format_str, Args&&... args) {
|
if (detail::is_utf8())
|
||||||
vprint(os, to_string_view(format_str),
|
vprint(os, fmt, vargs);
|
||||||
fmt::make_args_checked<Args...>(format_str, args...));
|
else
|
||||||
|
detail::vprint_directly(os, fmt, vargs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FMT_EXPORT
|
||||||
|
template <typename... Args>
|
||||||
|
void print(std::wostream& os,
|
||||||
|
basic_format_string<wchar_t, type_identity_t<Args>...> fmt,
|
||||||
|
Args&&... args) {
|
||||||
|
vprint(os, fmt, fmt::make_format_args<buffer_context<wchar_t>>(args...));
|
||||||
|
}
|
||||||
|
|
||||||
|
FMT_EXPORT template <typename... T>
|
||||||
|
void println(std::ostream& os, format_string<T...> fmt, T&&... args) {
|
||||||
|
fmt::print(os, "{}\n", fmt::format(fmt, std::forward<T>(args)...));
|
||||||
|
}
|
||||||
|
|
||||||
|
FMT_EXPORT
|
||||||
|
template <typename... Args>
|
||||||
|
void println(std::wostream& os,
|
||||||
|
basic_format_string<wchar_t, type_identity_t<Args>...> fmt,
|
||||||
|
Args&&... args) {
|
||||||
|
print(os, L"{}\n", fmt::format(fmt, std::forward<Args>(args)...));
|
||||||
|
}
|
||||||
|
|
||||||
FMT_END_NAMESPACE
|
FMT_END_NAMESPACE
|
||||||
|
|
||||||
#endif // FMT_OSTREAM_H_
|
#endif // FMT_OSTREAM_H_
|
||||||
|
|||||||
396
deps/fmt/include/fmt/printf.h
vendored
396
deps/fmt/include/fmt/printf.h
vendored
@@ -10,29 +10,22 @@
|
|||||||
|
|
||||||
#include <algorithm> // std::max
|
#include <algorithm> // std::max
|
||||||
#include <limits> // std::numeric_limits
|
#include <limits> // std::numeric_limits
|
||||||
#include <ostream>
|
|
||||||
|
|
||||||
#include "format.h"
|
#include "format.h"
|
||||||
|
|
||||||
FMT_BEGIN_NAMESPACE
|
FMT_BEGIN_NAMESPACE
|
||||||
FMT_MODULE_EXPORT_BEGIN
|
FMT_BEGIN_EXPORT
|
||||||
|
|
||||||
template <typename T> struct printf_formatter { printf_formatter() = delete; };
|
template <typename T> struct printf_formatter { printf_formatter() = delete; };
|
||||||
|
|
||||||
template <typename Char>
|
template <typename Char> class basic_printf_context {
|
||||||
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:
|
private:
|
||||||
OutputIt out_;
|
detail::buffer_appender<Char> out_;
|
||||||
basic_format_args<basic_printf_context> args_;
|
basic_format_args<basic_printf_context> args_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
using char_type = Char;
|
using char_type = Char;
|
||||||
using format_arg = basic_format_arg<basic_printf_context>;
|
using parse_context_type = basic_format_parse_context<Char>;
|
||||||
using parse_context_type = basic_printf_parse_context<Char>;
|
|
||||||
template <typename T> using formatter_type = printf_formatter<T>;
|
template <typename T> using formatter_type = printf_formatter<T>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -41,68 +34,68 @@ template <typename OutputIt, typename Char> class basic_printf_context {
|
|||||||
stored in the context object so make sure they have appropriate lifetimes.
|
stored in the context object so make sure they have appropriate lifetimes.
|
||||||
\endrst
|
\endrst
|
||||||
*/
|
*/
|
||||||
basic_printf_context(OutputIt out,
|
basic_printf_context(detail::buffer_appender<Char> out,
|
||||||
basic_format_args<basic_printf_context> args)
|
basic_format_args<basic_printf_context> args)
|
||||||
: out_(out), args_(args) {}
|
: out_(out), args_(args) {}
|
||||||
|
|
||||||
OutputIt out() { return out_; }
|
auto out() -> detail::buffer_appender<Char> { return out_; }
|
||||||
void advance_to(OutputIt it) { out_ = it; }
|
void advance_to(detail::buffer_appender<Char>) {}
|
||||||
|
|
||||||
detail::locale_ref locale() { return {}; }
|
auto locale() -> detail::locale_ref { return {}; }
|
||||||
|
|
||||||
format_arg arg(int id) const { return args_.get(id); }
|
auto arg(int id) const -> basic_format_arg<basic_printf_context> {
|
||||||
|
return args_.get(id);
|
||||||
|
}
|
||||||
|
|
||||||
FMT_CONSTEXPR void on_error(const char* message) {
|
FMT_CONSTEXPR void on_error(const char* message) {
|
||||||
detail::error_handler().on_error(message);
|
detail::error_handler().on_error(message);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
FMT_BEGIN_DETAIL_NAMESPACE
|
namespace detail {
|
||||||
|
|
||||||
// Checks if a value fits in int - used to avoid warnings about comparing
|
// Checks if a value fits in int - used to avoid warnings about comparing
|
||||||
// signed and unsigned integers.
|
// signed and unsigned integers.
|
||||||
template <bool IsSigned> struct int_checker {
|
template <bool IsSigned> struct int_checker {
|
||||||
template <typename T> static bool fits_in_int(T value) {
|
template <typename T> static auto fits_in_int(T value) -> bool {
|
||||||
unsigned max = max_value<int>();
|
unsigned max = max_value<int>();
|
||||||
return value <= max;
|
return value <= max;
|
||||||
}
|
}
|
||||||
static bool fits_in_int(bool) { return true; }
|
static auto fits_in_int(bool) -> bool { return true; }
|
||||||
};
|
};
|
||||||
|
|
||||||
template <> struct int_checker<true> {
|
template <> struct int_checker<true> {
|
||||||
template <typename T> static bool fits_in_int(T value) {
|
template <typename T> static auto fits_in_int(T value) -> bool {
|
||||||
return value >= (std::numeric_limits<int>::min)() &&
|
return value >= (std::numeric_limits<int>::min)() &&
|
||||||
value <= max_value<int>();
|
value <= max_value<int>();
|
||||||
}
|
}
|
||||||
static bool fits_in_int(int) { return true; }
|
static auto fits_in_int(int) -> bool { return true; }
|
||||||
};
|
};
|
||||||
|
|
||||||
class printf_precision_handler {
|
struct printf_precision_handler {
|
||||||
public:
|
|
||||||
template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
|
template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
|
||||||
int operator()(T value) {
|
auto operator()(T value) -> int {
|
||||||
if (!int_checker<std::numeric_limits<T>::is_signed>::fits_in_int(value))
|
if (!int_checker<std::numeric_limits<T>::is_signed>::fits_in_int(value))
|
||||||
FMT_THROW(format_error("number is too big"));
|
throw_format_error("number is too big");
|
||||||
return (std::max)(static_cast<int>(value), 0);
|
return (std::max)(static_cast<int>(value), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T, FMT_ENABLE_IF(!std::is_integral<T>::value)>
|
template <typename T, FMT_ENABLE_IF(!std::is_integral<T>::value)>
|
||||||
int operator()(T) {
|
auto operator()(T) -> int {
|
||||||
FMT_THROW(format_error("precision is not integer"));
|
throw_format_error("precision is not integer");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// An argument visitor that returns true iff arg is a zero integer.
|
// An argument visitor that returns true iff arg is a zero integer.
|
||||||
class is_zero_int {
|
struct is_zero_int {
|
||||||
public:
|
|
||||||
template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
|
template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
|
||||||
bool operator()(T value) {
|
auto operator()(T value) -> bool {
|
||||||
return value == 0;
|
return value == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T, FMT_ENABLE_IF(!std::is_integral<T>::value)>
|
template <typename T, FMT_ENABLE_IF(!std::is_integral<T>::value)>
|
||||||
bool operator()(T) {
|
auto operator()(T) -> bool {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -133,22 +126,23 @@ template <typename T, typename Context> class arg_converter {
|
|||||||
if (const_check(sizeof(target_type) <= sizeof(int))) {
|
if (const_check(sizeof(target_type) <= sizeof(int))) {
|
||||||
// Extra casts are used to silence warnings.
|
// Extra casts are used to silence warnings.
|
||||||
if (is_signed) {
|
if (is_signed) {
|
||||||
arg_ = detail::make_arg<Context>(
|
auto n = static_cast<int>(static_cast<target_type>(value));
|
||||||
static_cast<int>(static_cast<target_type>(value)));
|
arg_ = detail::make_arg<Context>(n);
|
||||||
} else {
|
} else {
|
||||||
using unsigned_type = typename make_unsigned_or_bool<target_type>::type;
|
using unsigned_type = typename make_unsigned_or_bool<target_type>::type;
|
||||||
arg_ = detail::make_arg<Context>(
|
auto n = static_cast<unsigned>(static_cast<unsigned_type>(value));
|
||||||
static_cast<unsigned>(static_cast<unsigned_type>(value)));
|
arg_ = detail::make_arg<Context>(n);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (is_signed) {
|
if (is_signed) {
|
||||||
// glibc's printf doesn't sign extend arguments of smaller types:
|
// glibc's printf doesn't sign extend arguments of smaller types:
|
||||||
// std::printf("%lld", -42); // prints "4294967254"
|
// std::printf("%lld", -42); // prints "4294967254"
|
||||||
// but we don't have to do the same because it's a UB.
|
// but we don't have to do the same because it's a UB.
|
||||||
arg_ = detail::make_arg<Context>(static_cast<long long>(value));
|
auto n = static_cast<long long>(value);
|
||||||
|
arg_ = detail::make_arg<Context>(n);
|
||||||
} else {
|
} else {
|
||||||
arg_ = detail::make_arg<Context>(
|
auto n = static_cast<typename make_unsigned_or_bool<U>::type>(value);
|
||||||
static_cast<typename make_unsigned_or_bool<U>::type>(value));
|
arg_ = detail::make_arg<Context>(n);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -176,8 +170,8 @@ template <typename Context> class char_converter {
|
|||||||
|
|
||||||
template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
|
template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
|
||||||
void operator()(T value) {
|
void operator()(T value) {
|
||||||
arg_ = detail::make_arg<Context>(
|
auto c = static_cast<typename Context::char_type>(value);
|
||||||
static_cast<typename Context::char_type>(value));
|
arg_ = detail::make_arg<Context>(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T, FMT_ENABLE_IF(!std::is_integral<T>::value)>
|
template <typename T, FMT_ENABLE_IF(!std::is_integral<T>::value)>
|
||||||
@@ -187,122 +181,131 @@ template <typename Context> class char_converter {
|
|||||||
// An argument visitor that return a pointer to a C string if argument is a
|
// An argument visitor that return a pointer to a C string if argument is a
|
||||||
// string or null otherwise.
|
// string or null otherwise.
|
||||||
template <typename Char> struct get_cstring {
|
template <typename Char> struct get_cstring {
|
||||||
template <typename T> const Char* operator()(T) { return nullptr; }
|
template <typename T> auto operator()(T) -> const Char* { return nullptr; }
|
||||||
const Char* operator()(const Char* s) { return s; }
|
auto operator()(const Char* s) -> const Char* { return s; }
|
||||||
};
|
};
|
||||||
|
|
||||||
// Checks if an argument is a valid printf width specifier and sets
|
// Checks if an argument is a valid printf width specifier and sets
|
||||||
// left alignment if it is negative.
|
// left alignment if it is negative.
|
||||||
template <typename Char> class printf_width_handler {
|
template <typename Char> class printf_width_handler {
|
||||||
private:
|
private:
|
||||||
using format_specs = basic_format_specs<Char>;
|
format_specs<Char>& specs_;
|
||||||
|
|
||||||
format_specs& specs_;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit printf_width_handler(format_specs& specs) : specs_(specs) {}
|
explicit printf_width_handler(format_specs<Char>& specs) : specs_(specs) {}
|
||||||
|
|
||||||
template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
|
template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
|
||||||
unsigned operator()(T value) {
|
auto operator()(T value) -> unsigned {
|
||||||
auto width = static_cast<uint32_or_64_or_128_t<T>>(value);
|
auto width = static_cast<uint32_or_64_or_128_t<T>>(value);
|
||||||
if (detail::is_negative(value)) {
|
if (detail::is_negative(value)) {
|
||||||
specs_.align = align::left;
|
specs_.align = align::left;
|
||||||
width = 0 - width;
|
width = 0 - width;
|
||||||
}
|
}
|
||||||
unsigned int_max = max_value<int>();
|
unsigned int_max = max_value<int>();
|
||||||
if (width > int_max) FMT_THROW(format_error("number is too big"));
|
if (width > int_max) throw_format_error("number is too big");
|
||||||
return static_cast<unsigned>(width);
|
return static_cast<unsigned>(width);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T, FMT_ENABLE_IF(!std::is_integral<T>::value)>
|
template <typename T, FMT_ENABLE_IF(!std::is_integral<T>::value)>
|
||||||
unsigned operator()(T) {
|
auto operator()(T) -> unsigned {
|
||||||
FMT_THROW(format_error("width is not integer"));
|
throw_format_error("width is not integer");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Workaround for a bug with the XL compiler when initializing
|
||||||
|
// printf_arg_formatter's base class.
|
||||||
|
template <typename Char>
|
||||||
|
auto make_arg_formatter(buffer_appender<Char> iter, format_specs<Char>& s)
|
||||||
|
-> arg_formatter<Char> {
|
||||||
|
return {iter, s, locale_ref()};
|
||||||
|
}
|
||||||
|
|
||||||
// The ``printf`` argument formatter.
|
// The ``printf`` argument formatter.
|
||||||
template <typename OutputIt, typename Char>
|
template <typename Char>
|
||||||
class printf_arg_formatter : public arg_formatter<Char> {
|
class printf_arg_formatter : public arg_formatter<Char> {
|
||||||
private:
|
private:
|
||||||
using base = arg_formatter<Char>;
|
using base = arg_formatter<Char>;
|
||||||
using context_type = basic_printf_context<OutputIt, Char>;
|
using context_type = basic_printf_context<Char>;
|
||||||
using format_specs = basic_format_specs<Char>;
|
|
||||||
|
|
||||||
context_type& context_;
|
context_type& context_;
|
||||||
|
|
||||||
OutputIt write_null_pointer(bool is_string = false) {
|
void write_null_pointer(bool is_string = false) {
|
||||||
auto s = this->specs;
|
auto s = this->specs;
|
||||||
s.type = presentation_type::none;
|
s.type = presentation_type::none;
|
||||||
return write_bytes(this->out, is_string ? "(null)" : "(nil)", s);
|
write_bytes(this->out, is_string ? "(null)" : "(nil)", s);
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
printf_arg_formatter(OutputIt iter, format_specs& s, context_type& ctx)
|
printf_arg_formatter(buffer_appender<Char> iter, format_specs<Char>& s,
|
||||||
: base{iter, s, locale_ref()}, context_(ctx) {}
|
context_type& ctx)
|
||||||
|
: base(make_arg_formatter(iter, s)), context_(ctx) {}
|
||||||
|
|
||||||
OutputIt operator()(monostate value) { return base::operator()(value); }
|
void operator()(monostate value) { base::operator()(value); }
|
||||||
|
|
||||||
template <typename T, FMT_ENABLE_IF(detail::is_integral<T>::value)>
|
template <typename T, FMT_ENABLE_IF(detail::is_integral<T>::value)>
|
||||||
OutputIt operator()(T value) {
|
void operator()(T value) {
|
||||||
// MSVC2013 fails to compile separate overloads for bool and Char so use
|
// MSVC2013 fails to compile separate overloads for bool and Char so use
|
||||||
// std::is_same instead.
|
// std::is_same instead.
|
||||||
if (std::is_same<T, Char>::value) {
|
if (!std::is_same<T, Char>::value) {
|
||||||
format_specs fmt_specs = this->specs;
|
base::operator()(value);
|
||||||
if (fmt_specs.type != presentation_type::none &&
|
return;
|
||||||
fmt_specs.type != presentation_type::chr) {
|
|
||||||
return (*this)(static_cast<int>(value));
|
|
||||||
}
|
|
||||||
fmt_specs.sign = sign::none;
|
|
||||||
fmt_specs.alt = false;
|
|
||||||
fmt_specs.fill[0] = ' '; // Ignore '0' flag for char types.
|
|
||||||
// align::numeric needs to be overwritten here since the '0' flag is
|
|
||||||
// ignored for non-numeric types
|
|
||||||
if (fmt_specs.align == align::none || fmt_specs.align == align::numeric)
|
|
||||||
fmt_specs.align = align::right;
|
|
||||||
return write<Char>(this->out, static_cast<Char>(value), fmt_specs);
|
|
||||||
}
|
}
|
||||||
return base::operator()(value);
|
format_specs<Char> fmt_specs = this->specs;
|
||||||
|
if (fmt_specs.type != presentation_type::none &&
|
||||||
|
fmt_specs.type != presentation_type::chr) {
|
||||||
|
return (*this)(static_cast<int>(value));
|
||||||
|
}
|
||||||
|
fmt_specs.sign = sign::none;
|
||||||
|
fmt_specs.alt = false;
|
||||||
|
fmt_specs.fill[0] = ' '; // Ignore '0' flag for char types.
|
||||||
|
// align::numeric needs to be overwritten here since the '0' flag is
|
||||||
|
// ignored for non-numeric types
|
||||||
|
if (fmt_specs.align == align::none || fmt_specs.align == align::numeric)
|
||||||
|
fmt_specs.align = align::right;
|
||||||
|
write<Char>(this->out, static_cast<Char>(value), fmt_specs);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T, FMT_ENABLE_IF(std::is_floating_point<T>::value)>
|
template <typename T, FMT_ENABLE_IF(std::is_floating_point<T>::value)>
|
||||||
OutputIt operator()(T value) {
|
void operator()(T value) {
|
||||||
return base::operator()(value);
|
base::operator()(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Formats a null-terminated C string. */
|
/** Formats a null-terminated C string. */
|
||||||
OutputIt operator()(const char* value) {
|
void operator()(const char* value) {
|
||||||
if (value) return base::operator()(value);
|
if (value)
|
||||||
return write_null_pointer(this->specs.type != presentation_type::pointer);
|
base::operator()(value);
|
||||||
|
else
|
||||||
|
write_null_pointer(this->specs.type != presentation_type::pointer);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Formats a null-terminated wide C string. */
|
/** Formats a null-terminated wide C string. */
|
||||||
OutputIt operator()(const wchar_t* value) {
|
void operator()(const wchar_t* value) {
|
||||||
if (value) return base::operator()(value);
|
if (value)
|
||||||
return write_null_pointer(this->specs.type != presentation_type::pointer);
|
base::operator()(value);
|
||||||
|
else
|
||||||
|
write_null_pointer(this->specs.type != presentation_type::pointer);
|
||||||
}
|
}
|
||||||
|
|
||||||
OutputIt operator()(basic_string_view<Char> value) {
|
void operator()(basic_string_view<Char> value) { base::operator()(value); }
|
||||||
return base::operator()(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Formats a pointer. */
|
/** Formats a pointer. */
|
||||||
OutputIt operator()(const void* value) {
|
void operator()(const void* value) {
|
||||||
return value ? base::operator()(value) : write_null_pointer();
|
if (value)
|
||||||
|
base::operator()(value);
|
||||||
|
else
|
||||||
|
write_null_pointer();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Formats an argument of a custom (user-defined) type. */
|
/** Formats an argument of a custom (user-defined) type. */
|
||||||
OutputIt operator()(typename basic_format_arg<context_type>::handle handle) {
|
void operator()(typename basic_format_arg<context_type>::handle handle) {
|
||||||
auto parse_ctx =
|
auto parse_ctx = basic_format_parse_context<Char>({});
|
||||||
basic_printf_parse_context<Char>(basic_string_view<Char>());
|
|
||||||
handle.format(parse_ctx, context_);
|
handle.format(parse_ctx, context_);
|
||||||
return this->out;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename Char>
|
template <typename Char>
|
||||||
void parse_flags(basic_format_specs<Char>& specs, const Char*& it,
|
void parse_flags(format_specs<Char>& specs, const Char*& it, const Char* end) {
|
||||||
const Char* end) {
|
|
||||||
for (; it != end; ++it) {
|
for (; it != end; ++it) {
|
||||||
switch (*it) {
|
switch (*it) {
|
||||||
case '-':
|
case '-':
|
||||||
@@ -315,9 +318,7 @@ void parse_flags(basic_format_specs<Char>& specs, const Char*& it,
|
|||||||
specs.fill[0] = '0';
|
specs.fill[0] = '0';
|
||||||
break;
|
break;
|
||||||
case ' ':
|
case ' ':
|
||||||
if (specs.sign != sign::plus) {
|
if (specs.sign != sign::plus) specs.sign = sign::space;
|
||||||
specs.sign = sign::space;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case '#':
|
case '#':
|
||||||
specs.alt = true;
|
specs.alt = true;
|
||||||
@@ -329,8 +330,8 @@ void parse_flags(basic_format_specs<Char>& specs, const Char*& it,
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename Char, typename GetArg>
|
template <typename Char, typename GetArg>
|
||||||
int parse_header(const Char*& it, const Char* end,
|
auto parse_header(const Char*& it, const Char* end, format_specs<Char>& specs,
|
||||||
basic_format_specs<Char>& specs, GetArg get_arg) {
|
GetArg get_arg) -> int {
|
||||||
int arg_index = -1;
|
int arg_index = -1;
|
||||||
Char c = *it;
|
Char c = *it;
|
||||||
if (c >= '0' && c <= '9') {
|
if (c >= '0' && c <= '9') {
|
||||||
@@ -345,7 +346,7 @@ int parse_header(const Char*& it, const Char* end,
|
|||||||
if (value != 0) {
|
if (value != 0) {
|
||||||
// Nonzero value means that we parsed width and don't need to
|
// Nonzero value means that we parsed width and don't need to
|
||||||
// parse it or flags again, so return now.
|
// parse it or flags again, so return now.
|
||||||
if (value == -1) FMT_THROW(format_error("number is too big"));
|
if (value == -1) throw_format_error("number is too big");
|
||||||
specs.width = value;
|
specs.width = value;
|
||||||
return arg_index;
|
return arg_index;
|
||||||
}
|
}
|
||||||
@@ -356,7 +357,7 @@ int parse_header(const Char*& it, const Char* end,
|
|||||||
if (it != end) {
|
if (it != end) {
|
||||||
if (*it >= '0' && *it <= '9') {
|
if (*it >= '0' && *it <= '9') {
|
||||||
specs.width = parse_nonnegative_int(it, end, -1);
|
specs.width = parse_nonnegative_int(it, end, -1);
|
||||||
if (specs.width == -1) FMT_THROW(format_error("number is too big"));
|
if (specs.width == -1) throw_format_error("number is too big");
|
||||||
} else if (*it == '*') {
|
} else if (*it == '*') {
|
||||||
++it;
|
++it;
|
||||||
specs.width = static_cast<int>(visit_format_arg(
|
specs.width = static_cast<int>(visit_format_arg(
|
||||||
@@ -366,13 +367,53 @@ int parse_header(const Char*& it, const Char* end,
|
|||||||
return arg_index;
|
return arg_index;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline auto parse_printf_presentation_type(char c, type t)
|
||||||
|
-> presentation_type {
|
||||||
|
using pt = presentation_type;
|
||||||
|
constexpr auto integral_set = sint_set | uint_set | bool_set | char_set;
|
||||||
|
switch (c) {
|
||||||
|
case 'd':
|
||||||
|
return in(t, integral_set) ? pt::dec : pt::none;
|
||||||
|
case 'o':
|
||||||
|
return in(t, integral_set) ? pt::oct : pt::none;
|
||||||
|
case 'x':
|
||||||
|
return in(t, integral_set) ? pt::hex_lower : pt::none;
|
||||||
|
case 'X':
|
||||||
|
return in(t, integral_set) ? pt::hex_upper : pt::none;
|
||||||
|
case 'a':
|
||||||
|
return in(t, float_set) ? pt::hexfloat_lower : pt::none;
|
||||||
|
case 'A':
|
||||||
|
return in(t, float_set) ? pt::hexfloat_upper : pt::none;
|
||||||
|
case 'e':
|
||||||
|
return in(t, float_set) ? pt::exp_lower : pt::none;
|
||||||
|
case 'E':
|
||||||
|
return in(t, float_set) ? pt::exp_upper : pt::none;
|
||||||
|
case 'f':
|
||||||
|
return in(t, float_set) ? pt::fixed_lower : pt::none;
|
||||||
|
case 'F':
|
||||||
|
return in(t, float_set) ? pt::fixed_upper : pt::none;
|
||||||
|
case 'g':
|
||||||
|
return in(t, float_set) ? pt::general_lower : pt::none;
|
||||||
|
case 'G':
|
||||||
|
return in(t, float_set) ? pt::general_upper : pt::none;
|
||||||
|
case 'c':
|
||||||
|
return in(t, integral_set) ? pt::chr : pt::none;
|
||||||
|
case 's':
|
||||||
|
return in(t, string_set | cstring_set) ? pt::string : pt::none;
|
||||||
|
case 'p':
|
||||||
|
return in(t, pointer_set | cstring_set) ? pt::pointer : pt::none;
|
||||||
|
default:
|
||||||
|
return pt::none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
template <typename Char, typename Context>
|
template <typename Char, typename Context>
|
||||||
void vprintf(buffer<Char>& buf, basic_string_view<Char> format,
|
void vprintf(buffer<Char>& buf, basic_string_view<Char> format,
|
||||||
basic_format_args<Context> args) {
|
basic_format_args<Context> args) {
|
||||||
using OutputIt = buffer_appender<Char>;
|
using iterator = buffer_appender<Char>;
|
||||||
auto out = OutputIt(buf);
|
auto out = iterator(buf);
|
||||||
auto context = basic_printf_context<OutputIt, Char>(out, args);
|
auto context = basic_printf_context<Char>(out, args);
|
||||||
auto parse_ctx = basic_printf_parse_context<Char>(format);
|
auto parse_ctx = basic_format_parse_context<Char>(format);
|
||||||
|
|
||||||
// Returns the argument with specified index or, if arg_index is -1, the next
|
// Returns the argument with specified index or, if arg_index is -1, the next
|
||||||
// argument.
|
// argument.
|
||||||
@@ -388,26 +429,24 @@ void vprintf(buffer<Char>& buf, basic_string_view<Char> format,
|
|||||||
const Char* end = parse_ctx.end();
|
const Char* end = parse_ctx.end();
|
||||||
auto it = start;
|
auto it = start;
|
||||||
while (it != end) {
|
while (it != end) {
|
||||||
if (!detail::find<false, Char>(it, end, '%', it)) {
|
if (!find<false, Char>(it, end, '%', it)) {
|
||||||
it = end; // detail::find leaves it == nullptr if it doesn't find '%'
|
it = end; // find leaves it == nullptr if it doesn't find '%'.
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
Char c = *it++;
|
Char c = *it++;
|
||||||
if (it != end && *it == c) {
|
if (it != end && *it == c) {
|
||||||
out = detail::write(
|
write(out, basic_string_view<Char>(start, to_unsigned(it - start)));
|
||||||
out, basic_string_view<Char>(start, detail::to_unsigned(it - start)));
|
|
||||||
start = ++it;
|
start = ++it;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
out = detail::write(out, basic_string_view<Char>(
|
write(out, basic_string_view<Char>(start, to_unsigned(it - 1 - start)));
|
||||||
start, detail::to_unsigned(it - 1 - start)));
|
|
||||||
|
|
||||||
basic_format_specs<Char> specs;
|
auto specs = format_specs<Char>();
|
||||||
specs.align = align::right;
|
specs.align = align::right;
|
||||||
|
|
||||||
// Parse argument index, flags and width.
|
// Parse argument index, flags and width.
|
||||||
int arg_index = parse_header(it, end, specs, get_arg);
|
int arg_index = parse_header(it, end, specs, get_arg);
|
||||||
if (arg_index == 0) parse_ctx.on_error("argument not found");
|
if (arg_index == 0) throw_format_error("argument not found");
|
||||||
|
|
||||||
// Parse precision.
|
// Parse precision.
|
||||||
if (it != end && *it == '.') {
|
if (it != end && *it == '.') {
|
||||||
@@ -418,7 +457,7 @@ void vprintf(buffer<Char>& buf, basic_string_view<Char> format,
|
|||||||
} else if (c == '*') {
|
} else if (c == '*') {
|
||||||
++it;
|
++it;
|
||||||
specs.precision = static_cast<int>(
|
specs.precision = static_cast<int>(
|
||||||
visit_format_arg(detail::printf_precision_handler(), get_arg(-1)));
|
visit_format_arg(printf_precision_handler(), get_arg(-1)));
|
||||||
} else {
|
} else {
|
||||||
specs.precision = 0;
|
specs.precision = 0;
|
||||||
}
|
}
|
||||||
@@ -427,20 +466,19 @@ void vprintf(buffer<Char>& buf, basic_string_view<Char> format,
|
|||||||
auto 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
|
// For d, i, o, u, x, and X conversion specifiers, if a precision is
|
||||||
// specified, the '0' flag is ignored
|
// specified, the '0' flag is ignored
|
||||||
if (specs.precision >= 0 && arg.is_integral())
|
if (specs.precision >= 0 && arg.is_integral()) {
|
||||||
specs.fill[0] =
|
// Ignore '0' for non-numeric types or if '-' present.
|
||||||
' '; // Ignore '0' flag for non-numeric types or if '-' present.
|
specs.fill[0] = ' ';
|
||||||
if (specs.precision >= 0 && arg.type() == detail::type::cstring_type) {
|
}
|
||||||
auto str = visit_format_arg(detail::get_cstring<Char>(), arg);
|
if (specs.precision >= 0 && arg.type() == type::cstring_type) {
|
||||||
|
auto str = visit_format_arg(get_cstring<Char>(), arg);
|
||||||
auto str_end = str + specs.precision;
|
auto str_end = str + specs.precision;
|
||||||
auto nul = std::find(str, str_end, Char());
|
auto nul = std::find(str, str_end, Char());
|
||||||
arg = detail::make_arg<basic_printf_context<OutputIt, Char>>(
|
auto sv = basic_string_view<Char>(
|
||||||
basic_string_view<Char>(
|
str, to_unsigned(nul != str_end ? nul - str : specs.precision));
|
||||||
str, detail::to_unsigned(nul != str_end ? nul - str
|
arg = make_arg<basic_printf_context<Char>>(sv);
|
||||||
: specs.precision)));
|
|
||||||
}
|
}
|
||||||
if (specs.alt && visit_format_arg(detail::is_zero_int(), arg))
|
if (specs.alt && visit_format_arg(is_zero_int(), arg)) specs.alt = false;
|
||||||
specs.alt = false;
|
|
||||||
if (specs.fill[0] == '0') {
|
if (specs.fill[0] == '0') {
|
||||||
if (arg.is_arithmetic() && specs.align != align::left)
|
if (arg.is_arithmetic() && specs.align != align::left)
|
||||||
specs.align = align::numeric;
|
specs.align = align::numeric;
|
||||||
@@ -452,7 +490,6 @@ void vprintf(buffer<Char>& buf, basic_string_view<Char> format,
|
|||||||
// Parse length and convert the argument to the required type.
|
// Parse length and convert the argument to the required type.
|
||||||
c = it != end ? *it++ : 0;
|
c = it != end ? *it++ : 0;
|
||||||
Char t = it != end ? *it : 0;
|
Char t = it != end ? *it : 0;
|
||||||
using detail::convert_arg;
|
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case 'h':
|
case 'h':
|
||||||
if (t == 'h') {
|
if (t == 'h') {
|
||||||
@@ -491,7 +528,7 @@ void vprintf(buffer<Char>& buf, basic_string_view<Char> format,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Parse type.
|
// Parse type.
|
||||||
if (it == end) FMT_THROW(format_error("invalid format string"));
|
if (it == end) throw_format_error("invalid format string");
|
||||||
char type = static_cast<char>(*it++);
|
char type = static_cast<char>(*it++);
|
||||||
if (arg.is_integral()) {
|
if (arg.is_integral()) {
|
||||||
// Normalize type.
|
// Normalize type.
|
||||||
@@ -501,32 +538,25 @@ void vprintf(buffer<Char>& buf, basic_string_view<Char> format,
|
|||||||
type = 'd';
|
type = 'd';
|
||||||
break;
|
break;
|
||||||
case 'c':
|
case 'c':
|
||||||
visit_format_arg(
|
visit_format_arg(char_converter<basic_printf_context<Char>>(arg), arg);
|
||||||
detail::char_converter<basic_printf_context<OutputIt, Char>>(arg),
|
|
||||||
arg);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
specs.type = parse_presentation_type(type);
|
specs.type = parse_printf_presentation_type(type, arg.type());
|
||||||
if (specs.type == presentation_type::none)
|
if (specs.type == presentation_type::none)
|
||||||
parse_ctx.on_error("invalid type specifier");
|
throw_format_error("invalid format specifier");
|
||||||
|
|
||||||
start = it;
|
start = it;
|
||||||
|
|
||||||
// Format argument.
|
// Format argument.
|
||||||
out = visit_format_arg(
|
visit_format_arg(printf_arg_formatter<Char>(out, specs, context), arg);
|
||||||
detail::printf_arg_formatter<OutputIt, Char>(out, specs, context), arg);
|
|
||||||
}
|
}
|
||||||
detail::write(out, basic_string_view<Char>(start, to_unsigned(it - start)));
|
write(out, basic_string_view<Char>(start, to_unsigned(it - start)));
|
||||||
}
|
}
|
||||||
FMT_END_DETAIL_NAMESPACE
|
} // namespace detail
|
||||||
|
|
||||||
template <typename Char>
|
using printf_context = basic_printf_context<char>;
|
||||||
using basic_printf_context_t =
|
using wprintf_context = basic_printf_context<wchar_t>;
|
||||||
basic_printf_context<detail::buffer_appender<Char>, Char>;
|
|
||||||
|
|
||||||
using printf_context = basic_printf_context_t<char>;
|
|
||||||
using wprintf_context = basic_printf_context_t<wchar_t>;
|
|
||||||
|
|
||||||
using printf_args = basic_format_args<printf_context>;
|
using printf_args = basic_format_args<printf_context>;
|
||||||
using wprintf_args = basic_format_args<wprintf_context>;
|
using wprintf_args = basic_format_args<wprintf_context>;
|
||||||
@@ -543,26 +573,21 @@ inline auto make_printf_args(const T&... args)
|
|||||||
return {args...};
|
return {args...};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
// DEPRECATED!
|
||||||
\rst
|
|
||||||
Constructs an `~fmt::format_arg_store` object that contains references to
|
|
||||||
arguments and can be implicitly converted to `~fmt::wprintf_args`.
|
|
||||||
\endrst
|
|
||||||
*/
|
|
||||||
template <typename... T>
|
template <typename... T>
|
||||||
inline auto make_wprintf_args(const T&... args)
|
inline auto make_wprintf_args(const T&... args)
|
||||||
-> format_arg_store<wprintf_context, T...> {
|
-> format_arg_store<wprintf_context, T...> {
|
||||||
return {args...};
|
return {args...};
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename S, typename Char = char_t<S>>
|
template <typename Char>
|
||||||
inline auto vsprintf(
|
inline auto vsprintf(
|
||||||
const S& fmt,
|
basic_string_view<Char> fmt,
|
||||||
basic_format_args<basic_printf_context_t<type_identity_t<Char>>> args)
|
basic_format_args<basic_printf_context<type_identity_t<Char>>> args)
|
||||||
-> std::basic_string<Char> {
|
-> std::basic_string<Char> {
|
||||||
basic_memory_buffer<Char> buffer;
|
auto buf = basic_memory_buffer<Char>();
|
||||||
vprintf(buffer, to_string_view(fmt), args);
|
detail::vprintf(buf, fmt, args);
|
||||||
return to_string(buffer);
|
return to_string(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -577,19 +602,19 @@ inline auto vsprintf(
|
|||||||
template <typename S, typename... T,
|
template <typename S, typename... T,
|
||||||
typename Char = enable_if_t<detail::is_string<S>::value, char_t<S>>>
|
typename Char = enable_if_t<detail::is_string<S>::value, char_t<S>>>
|
||||||
inline auto sprintf(const S& fmt, const T&... args) -> std::basic_string<Char> {
|
inline auto sprintf(const S& fmt, const T&... args) -> std::basic_string<Char> {
|
||||||
using context = basic_printf_context_t<Char>;
|
return vsprintf(detail::to_string_view(fmt),
|
||||||
return vsprintf(to_string_view(fmt), fmt::make_format_args<context>(args...));
|
fmt::make_format_args<basic_printf_context<Char>>(args...));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename S, typename Char = char_t<S>>
|
template <typename Char>
|
||||||
inline auto vfprintf(
|
inline auto vfprintf(
|
||||||
std::FILE* f, const S& fmt,
|
std::FILE* f, basic_string_view<Char> fmt,
|
||||||
basic_format_args<basic_printf_context_t<type_identity_t<Char>>> args)
|
basic_format_args<basic_printf_context<type_identity_t<Char>>> args)
|
||||||
-> int {
|
-> int {
|
||||||
basic_memory_buffer<Char> buffer;
|
auto buf = basic_memory_buffer<Char>();
|
||||||
vprintf(buffer, to_string_view(fmt), args);
|
detail::vprintf(buf, fmt, args);
|
||||||
size_t size = buffer.size();
|
size_t size = buf.size();
|
||||||
return std::fwrite(buffer.data(), sizeof(Char), size, f) < size
|
return std::fwrite(buf.data(), sizeof(Char), size, f) < size
|
||||||
? -1
|
? -1
|
||||||
: static_cast<int>(size);
|
: static_cast<int>(size);
|
||||||
}
|
}
|
||||||
@@ -605,17 +630,16 @@ inline auto vfprintf(
|
|||||||
*/
|
*/
|
||||||
template <typename S, typename... T, typename Char = char_t<S>>
|
template <typename S, typename... T, typename Char = char_t<S>>
|
||||||
inline auto fprintf(std::FILE* f, const S& fmt, const T&... args) -> int {
|
inline auto fprintf(std::FILE* f, const S& fmt, const T&... args) -> int {
|
||||||
using context = basic_printf_context_t<Char>;
|
return vfprintf(f, detail::to_string_view(fmt),
|
||||||
return vfprintf(f, to_string_view(fmt),
|
fmt::make_format_args<basic_printf_context<Char>>(args...));
|
||||||
fmt::make_format_args<context>(args...));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename S, typename Char = char_t<S>>
|
template <typename Char>
|
||||||
inline auto vprintf(
|
FMT_DEPRECATED inline auto vprintf(
|
||||||
const S& fmt,
|
basic_string_view<Char> fmt,
|
||||||
basic_format_args<basic_printf_context_t<type_identity_t<Char>>> args)
|
basic_format_args<basic_printf_context<type_identity_t<Char>>> args)
|
||||||
-> int {
|
-> int {
|
||||||
return vfprintf(stdout, to_string_view(fmt), args);
|
return vfprintf(stdout, fmt, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -627,31 +651,17 @@ inline auto vprintf(
|
|||||||
fmt::printf("Elapsed time: %.2f seconds", 1.23);
|
fmt::printf("Elapsed time: %.2f seconds", 1.23);
|
||||||
\endrst
|
\endrst
|
||||||
*/
|
*/
|
||||||
template <typename S, typename... T, FMT_ENABLE_IF(detail::is_string<S>::value)>
|
template <typename... T>
|
||||||
inline auto printf(const S& fmt, const T&... args) -> int {
|
inline auto printf(string_view fmt, const T&... args) -> int {
|
||||||
return vprintf(
|
return vfprintf(stdout, fmt, make_printf_args(args...));
|
||||||
to_string_view(fmt),
|
}
|
||||||
fmt::make_format_args<basic_printf_context_t<char_t<S>>>(args...));
|
template <typename... T>
|
||||||
|
FMT_DEPRECATED inline auto printf(basic_string_view<wchar_t> fmt,
|
||||||
|
const T&... args) -> int {
|
||||||
|
return vfprintf(stdout, fmt, make_wprintf_args(args...));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename S, typename Char = char_t<S>>
|
FMT_END_EXPORT
|
||||||
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(fmt), args);
|
|
||||||
os.write(buffer.data(), static_cast<std::streamsize>(buffer.size()));
|
|
||||||
return static_cast<int>(buffer.size());
|
|
||||||
}
|
|
||||||
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
|
|
||||||
FMT_END_NAMESPACE
|
FMT_END_NAMESPACE
|
||||||
|
|
||||||
#endif // FMT_PRINTF_H_
|
#endif // FMT_PRINTF_H_
|
||||||
|
|||||||
780
deps/fmt/include/fmt/ranges.h
vendored
780
deps/fmt/include/fmt/ranges.h
vendored
@@ -22,27 +22,25 @@ FMT_BEGIN_NAMESPACE
|
|||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
|
||||||
template <typename RangeT, typename OutputIterator>
|
template <typename Range, typename OutputIt>
|
||||||
OutputIterator copy(const RangeT& range, OutputIterator out) {
|
auto copy(const Range& range, OutputIt out) -> OutputIt {
|
||||||
for (auto it = range.begin(), end = range.end(); it != end; ++it)
|
for (auto it = range.begin(), end = range.end(); it != end; ++it)
|
||||||
*out++ = *it;
|
*out++ = *it;
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename OutputIterator>
|
template <typename OutputIt>
|
||||||
OutputIterator copy(const char* str, OutputIterator out) {
|
auto copy(const char* str, OutputIt out) -> OutputIt {
|
||||||
while (*str) *out++ = *str++;
|
while (*str) *out++ = *str++;
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename OutputIterator>
|
template <typename OutputIt> auto copy(char ch, OutputIt out) -> OutputIt {
|
||||||
OutputIterator copy(char ch, OutputIterator out) {
|
|
||||||
*out++ = ch;
|
*out++ = ch;
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename OutputIterator>
|
template <typename OutputIt> auto copy(wchar_t ch, OutputIt out) -> OutputIt {
|
||||||
OutputIterator copy(wchar_t ch, OutputIterator out) {
|
|
||||||
*out++ = ch;
|
*out++ = ch;
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
@@ -55,7 +53,7 @@ template <typename T> class is_std_string_like {
|
|||||||
template <typename> static void check(...);
|
template <typename> static void check(...);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static FMT_CONSTEXPR_DECL const bool value =
|
static constexpr const bool value =
|
||||||
is_string<T>::value ||
|
is_string<T>::value ||
|
||||||
std::is_convertible<T, std_string_view<char>>::value ||
|
std::is_convertible<T, std_string_view<char>>::value ||
|
||||||
!std::is_void<decltype(check<T>(nullptr))>::value;
|
!std::is_void<decltype(check<T>(nullptr))>::value;
|
||||||
@@ -69,10 +67,10 @@ template <typename T> class is_map {
|
|||||||
template <typename> static void check(...);
|
template <typename> static void check(...);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
#ifdef FMT_FORMAT_MAP_AS_LIST
|
#ifdef FMT_FORMAT_MAP_AS_LIST // DEPRECATED!
|
||||||
static FMT_CONSTEXPR_DECL const bool value = false;
|
static constexpr const bool value = false;
|
||||||
#else
|
#else
|
||||||
static FMT_CONSTEXPR_DECL const bool value =
|
static constexpr const bool value =
|
||||||
!std::is_void<decltype(check<T>(nullptr))>::value;
|
!std::is_void<decltype(check<T>(nullptr))>::value;
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
@@ -82,10 +80,10 @@ template <typename T> class is_set {
|
|||||||
template <typename> static void check(...);
|
template <typename> static void check(...);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
#ifdef FMT_FORMAT_SET_AS_LIST
|
#ifdef FMT_FORMAT_SET_AS_LIST // DEPRECATED!
|
||||||
static FMT_CONSTEXPR_DECL const bool value = false;
|
static constexpr const bool value = false;
|
||||||
#else
|
#else
|
||||||
static FMT_CONSTEXPR_DECL const bool value =
|
static constexpr const bool value =
|
||||||
!std::is_void<decltype(check<T>(nullptr))>::value && !is_map<T>::value;
|
!std::is_void<decltype(check<T>(nullptr))>::value && !is_map<T>::value;
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
@@ -94,7 +92,7 @@ template <typename... Ts> struct conditional_helper {};
|
|||||||
|
|
||||||
template <typename T, typename _ = void> struct is_range_ : std::false_type {};
|
template <typename T, typename _ = void> struct is_range_ : std::false_type {};
|
||||||
|
|
||||||
#if !FMT_MSC_VER || FMT_MSC_VER > 1800
|
#if !FMT_MSC_VERSION || FMT_MSC_VERSION > 1800
|
||||||
|
|
||||||
# define FMT_DECLTYPE_RETURN(val) \
|
# define FMT_DECLTYPE_RETURN(val) \
|
||||||
->decltype(val) { return val; } \
|
->decltype(val) { return val; } \
|
||||||
@@ -157,8 +155,9 @@ template <typename T>
|
|||||||
struct has_mutable_begin_end<
|
struct has_mutable_begin_end<
|
||||||
T, void_t<decltype(detail::range_begin(std::declval<T>())),
|
T, void_t<decltype(detail::range_begin(std::declval<T>())),
|
||||||
decltype(detail::range_end(std::declval<T>())),
|
decltype(detail::range_end(std::declval<T>())),
|
||||||
enable_if_t<std::is_copy_constructible<T>::value>>>
|
// the extra int here is because older versions of MSVC don't
|
||||||
: std::true_type {};
|
// SFINAE properly unless there are distinct types
|
||||||
|
int>> : std::true_type {};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct is_range_<T, void>
|
struct is_range_<T, void>
|
||||||
@@ -174,12 +173,12 @@ template <typename T> class is_tuple_like_ {
|
|||||||
template <typename> static void check(...);
|
template <typename> static void check(...);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static FMT_CONSTEXPR_DECL const bool value =
|
static constexpr const bool value =
|
||||||
!std::is_void<decltype(check<T>(nullptr))>::value;
|
!std::is_void<decltype(check<T>(nullptr))>::value;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Check for integer_sequence
|
// Check for integer_sequence
|
||||||
#if defined(__cpp_lib_integer_sequence) || FMT_MSC_VER >= 1900
|
#if defined(__cpp_lib_integer_sequence) || FMT_MSC_VERSION >= 1900
|
||||||
template <typename T, T... N>
|
template <typename T, T... N>
|
||||||
using integer_sequence = std::integer_sequence<T, N...>;
|
using integer_sequence = std::integer_sequence<T, N...>;
|
||||||
template <size_t... N> using index_sequence = std::index_sequence<N...>;
|
template <size_t... N> using index_sequence = std::index_sequence<N...>;
|
||||||
@@ -202,26 +201,71 @@ template <size_t N>
|
|||||||
using make_index_sequence = make_integer_sequence<size_t, N>;
|
using make_index_sequence = make_integer_sequence<size_t, N>;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
template <class Tuple, class F, size_t... Is>
|
template <typename T>
|
||||||
void for_each(index_sequence<Is...>, Tuple&& tup, F&& f) FMT_NOEXCEPT {
|
using tuple_index_sequence = make_index_sequence<std::tuple_size<T>::value>;
|
||||||
|
|
||||||
|
template <typename T, typename C, bool = is_tuple_like_<T>::value>
|
||||||
|
class is_tuple_formattable_ {
|
||||||
|
public:
|
||||||
|
static constexpr const bool value = false;
|
||||||
|
};
|
||||||
|
template <typename T, typename C> class is_tuple_formattable_<T, C, true> {
|
||||||
|
template <std::size_t... Is>
|
||||||
|
static std::true_type check2(index_sequence<Is...>,
|
||||||
|
integer_sequence<bool, (Is == Is)...>);
|
||||||
|
static std::false_type check2(...);
|
||||||
|
template <std::size_t... Is>
|
||||||
|
static decltype(check2(
|
||||||
|
index_sequence<Is...>{},
|
||||||
|
integer_sequence<
|
||||||
|
bool, (is_formattable<typename std::tuple_element<Is, T>::type,
|
||||||
|
C>::value)...>{})) check(index_sequence<Is...>);
|
||||||
|
|
||||||
|
public:
|
||||||
|
static constexpr const bool value =
|
||||||
|
decltype(check(tuple_index_sequence<T>{}))::value;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Tuple, typename F, size_t... Is>
|
||||||
|
FMT_CONSTEXPR void for_each(index_sequence<Is...>, Tuple&& t, F&& f) {
|
||||||
using std::get;
|
using std::get;
|
||||||
// using free function get<I>(T) now.
|
// Using a free function get<Is>(Tuple) now.
|
||||||
const int _[] = {0, ((void)f(get<Is>(tup)), 0)...};
|
const int unused[] = {0, ((void)f(get<Is>(t)), 0)...};
|
||||||
(void)_; // blocks warnings
|
ignore_unused(unused);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T>
|
template <typename Tuple, typename F>
|
||||||
FMT_CONSTEXPR make_index_sequence<std::tuple_size<T>::value> get_indexes(
|
FMT_CONSTEXPR void for_each(Tuple&& t, F&& f) {
|
||||||
T const&) {
|
for_each(tuple_index_sequence<remove_cvref_t<Tuple>>(),
|
||||||
return {};
|
std::forward<Tuple>(t), std::forward<F>(f));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Tuple, class F> void for_each(Tuple&& tup, F&& f) {
|
template <typename Tuple1, typename Tuple2, typename F, size_t... Is>
|
||||||
const auto indexes = get_indexes(tup);
|
void for_each2(index_sequence<Is...>, Tuple1&& t1, Tuple2&& t2, F&& f) {
|
||||||
for_each(indexes, std::forward<Tuple>(tup), std::forward<F>(f));
|
using std::get;
|
||||||
|
const int unused[] = {0, ((void)f(get<Is>(t1), get<Is>(t2)), 0)...};
|
||||||
|
ignore_unused(unused);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if FMT_MSC_VER
|
template <typename Tuple1, typename Tuple2, typename F>
|
||||||
|
void for_each2(Tuple1&& t1, Tuple2&& t2, F&& f) {
|
||||||
|
for_each2(tuple_index_sequence<remove_cvref_t<Tuple1>>(),
|
||||||
|
std::forward<Tuple1>(t1), std::forward<Tuple2>(t2),
|
||||||
|
std::forward<F>(f));
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace tuple {
|
||||||
|
// Workaround a bug in MSVC 2019 (v140).
|
||||||
|
template <typename Char, typename... T>
|
||||||
|
using result_t = std::tuple<formatter<remove_cvref_t<T>, Char>...>;
|
||||||
|
|
||||||
|
using std::get;
|
||||||
|
template <typename Tuple, typename Char, std::size_t... Is>
|
||||||
|
auto get_formatters(index_sequence<Is...>)
|
||||||
|
-> result_t<Char, decltype(get<Is>(std::declval<Tuple>()))...>;
|
||||||
|
} // namespace tuple
|
||||||
|
|
||||||
|
#if FMT_MSC_VERSION && FMT_MSC_VERSION < 1920
|
||||||
// Older MSVC doesn't get the reference type correctly for arrays.
|
// Older MSVC doesn't get the reference type correctly for arrays.
|
||||||
template <typename R> struct range_reference_type_impl {
|
template <typename R> struct range_reference_type_impl {
|
||||||
using type = decltype(*detail::range_begin(std::declval<R&>()));
|
using type = decltype(*detail::range_begin(std::declval<R&>()));
|
||||||
@@ -244,365 +288,106 @@ using range_reference_type =
|
|||||||
template <typename Range>
|
template <typename Range>
|
||||||
using uncvref_type = remove_cvref_t<range_reference_type<Range>>;
|
using uncvref_type = remove_cvref_t<range_reference_type<Range>>;
|
||||||
|
|
||||||
template <typename OutputIt> OutputIt write_delimiter(OutputIt out) {
|
template <typename Formatter>
|
||||||
*out++ = ',';
|
FMT_CONSTEXPR auto maybe_set_debug_format(Formatter& f, bool set)
|
||||||
*out++ = ' ';
|
-> decltype(f.set_debug_format(set)) {
|
||||||
return out;
|
f.set_debug_format(set);
|
||||||
}
|
}
|
||||||
|
template <typename Formatter>
|
||||||
|
FMT_CONSTEXPR void maybe_set_debug_format(Formatter&, ...) {}
|
||||||
|
|
||||||
struct singleton {
|
// These are not generic lambdas for compatibility with C++11.
|
||||||
unsigned char upper;
|
template <typename ParseContext> struct parse_empty_specs {
|
||||||
unsigned char lower_count;
|
template <typename Formatter> FMT_CONSTEXPR void operator()(Formatter& f) {
|
||||||
|
f.parse(ctx);
|
||||||
|
detail::maybe_set_debug_format(f, true);
|
||||||
|
}
|
||||||
|
ParseContext& ctx;
|
||||||
};
|
};
|
||||||
|
template <typename FormatContext> struct format_tuple_element {
|
||||||
|
using char_type = typename FormatContext::char_type;
|
||||||
|
|
||||||
inline auto is_printable(uint16_t x, const singleton* singletons,
|
template <typename T>
|
||||||
size_t singletons_size,
|
void operator()(const formatter<T, char_type>& f, const T& v) {
|
||||||
const unsigned char* singleton_lowers,
|
if (i > 0)
|
||||||
const unsigned char* normal, size_t normal_size)
|
ctx.advance_to(detail::copy_str<char_type>(separator, ctx.out()));
|
||||||
-> bool {
|
ctx.advance_to(f.format(v, ctx));
|
||||||
auto upper = x >> 8;
|
++i;
|
||||||
auto lower_start = 0;
|
|
||||||
for (size_t i = 0; i < singletons_size; ++i) {
|
|
||||||
auto s = singletons[i];
|
|
||||||
auto lower_end = lower_start + s.lower_count;
|
|
||||||
if (upper < s.upper) break;
|
|
||||||
if (upper == s.upper) {
|
|
||||||
for (auto j = lower_start; j < lower_end; ++j) {
|
|
||||||
if (singleton_lowers[j] == (x & 0xff)) return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
lower_start = lower_end;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto xsigned = static_cast<int>(x);
|
int i;
|
||||||
auto current = true;
|
FormatContext& ctx;
|
||||||
for (size_t i = 0; i < normal_size; ++i) {
|
basic_string_view<char_type> separator;
|
||||||
auto v = static_cast<int>(normal[i]);
|
|
||||||
auto len = (v & 0x80) != 0 ? (v & 0x7f) << 8 | normal[++i] : v;
|
|
||||||
xsigned -= len;
|
|
||||||
if (xsigned < 0) break;
|
|
||||||
current = !current;
|
|
||||||
}
|
|
||||||
return current;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns true iff the code point cp is printable.
|
|
||||||
// This code is generated by support/printable.py.
|
|
||||||
inline auto is_printable(uint32_t cp) -> bool {
|
|
||||||
static constexpr singleton singletons0[] = {
|
|
||||||
{0x00, 1}, {0x03, 5}, {0x05, 6}, {0x06, 3}, {0x07, 6}, {0x08, 8},
|
|
||||||
{0x09, 17}, {0x0a, 28}, {0x0b, 25}, {0x0c, 20}, {0x0d, 16}, {0x0e, 13},
|
|
||||||
{0x0f, 4}, {0x10, 3}, {0x12, 18}, {0x13, 9}, {0x16, 1}, {0x17, 5},
|
|
||||||
{0x18, 2}, {0x19, 3}, {0x1a, 7}, {0x1c, 2}, {0x1d, 1}, {0x1f, 22},
|
|
||||||
{0x20, 3}, {0x2b, 3}, {0x2c, 2}, {0x2d, 11}, {0x2e, 1}, {0x30, 3},
|
|
||||||
{0x31, 2}, {0x32, 1}, {0xa7, 2}, {0xa9, 2}, {0xaa, 4}, {0xab, 8},
|
|
||||||
{0xfa, 2}, {0xfb, 5}, {0xfd, 4}, {0xfe, 3}, {0xff, 9},
|
|
||||||
};
|
|
||||||
static constexpr unsigned char singletons0_lower[] = {
|
|
||||||
0xad, 0x78, 0x79, 0x8b, 0x8d, 0xa2, 0x30, 0x57, 0x58, 0x8b, 0x8c, 0x90,
|
|
||||||
0x1c, 0x1d, 0xdd, 0x0e, 0x0f, 0x4b, 0x4c, 0xfb, 0xfc, 0x2e, 0x2f, 0x3f,
|
|
||||||
0x5c, 0x5d, 0x5f, 0xb5, 0xe2, 0x84, 0x8d, 0x8e, 0x91, 0x92, 0xa9, 0xb1,
|
|
||||||
0xba, 0xbb, 0xc5, 0xc6, 0xc9, 0xca, 0xde, 0xe4, 0xe5, 0xff, 0x00, 0x04,
|
|
||||||
0x11, 0x12, 0x29, 0x31, 0x34, 0x37, 0x3a, 0x3b, 0x3d, 0x49, 0x4a, 0x5d,
|
|
||||||
0x84, 0x8e, 0x92, 0xa9, 0xb1, 0xb4, 0xba, 0xbb, 0xc6, 0xca, 0xce, 0xcf,
|
|
||||||
0xe4, 0xe5, 0x00, 0x04, 0x0d, 0x0e, 0x11, 0x12, 0x29, 0x31, 0x34, 0x3a,
|
|
||||||
0x3b, 0x45, 0x46, 0x49, 0x4a, 0x5e, 0x64, 0x65, 0x84, 0x91, 0x9b, 0x9d,
|
|
||||||
0xc9, 0xce, 0xcf, 0x0d, 0x11, 0x29, 0x45, 0x49, 0x57, 0x64, 0x65, 0x8d,
|
|
||||||
0x91, 0xa9, 0xb4, 0xba, 0xbb, 0xc5, 0xc9, 0xdf, 0xe4, 0xe5, 0xf0, 0x0d,
|
|
||||||
0x11, 0x45, 0x49, 0x64, 0x65, 0x80, 0x84, 0xb2, 0xbc, 0xbe, 0xbf, 0xd5,
|
|
||||||
0xd7, 0xf0, 0xf1, 0x83, 0x85, 0x8b, 0xa4, 0xa6, 0xbe, 0xbf, 0xc5, 0xc7,
|
|
||||||
0xce, 0xcf, 0xda, 0xdb, 0x48, 0x98, 0xbd, 0xcd, 0xc6, 0xce, 0xcf, 0x49,
|
|
||||||
0x4e, 0x4f, 0x57, 0x59, 0x5e, 0x5f, 0x89, 0x8e, 0x8f, 0xb1, 0xb6, 0xb7,
|
|
||||||
0xbf, 0xc1, 0xc6, 0xc7, 0xd7, 0x11, 0x16, 0x17, 0x5b, 0x5c, 0xf6, 0xf7,
|
|
||||||
0xfe, 0xff, 0x80, 0x0d, 0x6d, 0x71, 0xde, 0xdf, 0x0e, 0x0f, 0x1f, 0x6e,
|
|
||||||
0x6f, 0x1c, 0x1d, 0x5f, 0x7d, 0x7e, 0xae, 0xaf, 0xbb, 0xbc, 0xfa, 0x16,
|
|
||||||
0x17, 0x1e, 0x1f, 0x46, 0x47, 0x4e, 0x4f, 0x58, 0x5a, 0x5c, 0x5e, 0x7e,
|
|
||||||
0x7f, 0xb5, 0xc5, 0xd4, 0xd5, 0xdc, 0xf0, 0xf1, 0xf5, 0x72, 0x73, 0x8f,
|
|
||||||
0x74, 0x75, 0x96, 0x2f, 0x5f, 0x26, 0x2e, 0x2f, 0xa7, 0xaf, 0xb7, 0xbf,
|
|
||||||
0xc7, 0xcf, 0xd7, 0xdf, 0x9a, 0x40, 0x97, 0x98, 0x30, 0x8f, 0x1f, 0xc0,
|
|
||||||
0xc1, 0xce, 0xff, 0x4e, 0x4f, 0x5a, 0x5b, 0x07, 0x08, 0x0f, 0x10, 0x27,
|
|
||||||
0x2f, 0xee, 0xef, 0x6e, 0x6f, 0x37, 0x3d, 0x3f, 0x42, 0x45, 0x90, 0x91,
|
|
||||||
0xfe, 0xff, 0x53, 0x67, 0x75, 0xc8, 0xc9, 0xd0, 0xd1, 0xd8, 0xd9, 0xe7,
|
|
||||||
0xfe, 0xff,
|
|
||||||
};
|
|
||||||
static constexpr singleton singletons1[] = {
|
|
||||||
{0x00, 6}, {0x01, 1}, {0x03, 1}, {0x04, 2}, {0x08, 8}, {0x09, 2},
|
|
||||||
{0x0a, 5}, {0x0b, 2}, {0x0e, 4}, {0x10, 1}, {0x11, 2}, {0x12, 5},
|
|
||||||
{0x13, 17}, {0x14, 1}, {0x15, 2}, {0x17, 2}, {0x19, 13}, {0x1c, 5},
|
|
||||||
{0x1d, 8}, {0x24, 1}, {0x6a, 3}, {0x6b, 2}, {0xbc, 2}, {0xd1, 2},
|
|
||||||
{0xd4, 12}, {0xd5, 9}, {0xd6, 2}, {0xd7, 2}, {0xda, 1}, {0xe0, 5},
|
|
||||||
{0xe1, 2}, {0xe8, 2}, {0xee, 32}, {0xf0, 4}, {0xf8, 2}, {0xf9, 2},
|
|
||||||
{0xfa, 2}, {0xfb, 1},
|
|
||||||
};
|
|
||||||
static constexpr unsigned char singletons1_lower[] = {
|
|
||||||
0x0c, 0x27, 0x3b, 0x3e, 0x4e, 0x4f, 0x8f, 0x9e, 0x9e, 0x9f, 0x06, 0x07,
|
|
||||||
0x09, 0x36, 0x3d, 0x3e, 0x56, 0xf3, 0xd0, 0xd1, 0x04, 0x14, 0x18, 0x36,
|
|
||||||
0x37, 0x56, 0x57, 0x7f, 0xaa, 0xae, 0xaf, 0xbd, 0x35, 0xe0, 0x12, 0x87,
|
|
||||||
0x89, 0x8e, 0x9e, 0x04, 0x0d, 0x0e, 0x11, 0x12, 0x29, 0x31, 0x34, 0x3a,
|
|
||||||
0x45, 0x46, 0x49, 0x4a, 0x4e, 0x4f, 0x64, 0x65, 0x5c, 0xb6, 0xb7, 0x1b,
|
|
||||||
0x1c, 0x07, 0x08, 0x0a, 0x0b, 0x14, 0x17, 0x36, 0x39, 0x3a, 0xa8, 0xa9,
|
|
||||||
0xd8, 0xd9, 0x09, 0x37, 0x90, 0x91, 0xa8, 0x07, 0x0a, 0x3b, 0x3e, 0x66,
|
|
||||||
0x69, 0x8f, 0x92, 0x6f, 0x5f, 0xee, 0xef, 0x5a, 0x62, 0x9a, 0x9b, 0x27,
|
|
||||||
0x28, 0x55, 0x9d, 0xa0, 0xa1, 0xa3, 0xa4, 0xa7, 0xa8, 0xad, 0xba, 0xbc,
|
|
||||||
0xc4, 0x06, 0x0b, 0x0c, 0x15, 0x1d, 0x3a, 0x3f, 0x45, 0x51, 0xa6, 0xa7,
|
|
||||||
0xcc, 0xcd, 0xa0, 0x07, 0x19, 0x1a, 0x22, 0x25, 0x3e, 0x3f, 0xc5, 0xc6,
|
|
||||||
0x04, 0x20, 0x23, 0x25, 0x26, 0x28, 0x33, 0x38, 0x3a, 0x48, 0x4a, 0x4c,
|
|
||||||
0x50, 0x53, 0x55, 0x56, 0x58, 0x5a, 0x5c, 0x5e, 0x60, 0x63, 0x65, 0x66,
|
|
||||||
0x6b, 0x73, 0x78, 0x7d, 0x7f, 0x8a, 0xa4, 0xaa, 0xaf, 0xb0, 0xc0, 0xd0,
|
|
||||||
0xae, 0xaf, 0x79, 0xcc, 0x6e, 0x6f, 0x93,
|
|
||||||
};
|
|
||||||
static constexpr unsigned char normal0[] = {
|
|
||||||
0x00, 0x20, 0x5f, 0x22, 0x82, 0xdf, 0x04, 0x82, 0x44, 0x08, 0x1b, 0x04,
|
|
||||||
0x06, 0x11, 0x81, 0xac, 0x0e, 0x80, 0xab, 0x35, 0x28, 0x0b, 0x80, 0xe0,
|
|
||||||
0x03, 0x19, 0x08, 0x01, 0x04, 0x2f, 0x04, 0x34, 0x04, 0x07, 0x03, 0x01,
|
|
||||||
0x07, 0x06, 0x07, 0x11, 0x0a, 0x50, 0x0f, 0x12, 0x07, 0x55, 0x07, 0x03,
|
|
||||||
0x04, 0x1c, 0x0a, 0x09, 0x03, 0x08, 0x03, 0x07, 0x03, 0x02, 0x03, 0x03,
|
|
||||||
0x03, 0x0c, 0x04, 0x05, 0x03, 0x0b, 0x06, 0x01, 0x0e, 0x15, 0x05, 0x3a,
|
|
||||||
0x03, 0x11, 0x07, 0x06, 0x05, 0x10, 0x07, 0x57, 0x07, 0x02, 0x07, 0x15,
|
|
||||||
0x0d, 0x50, 0x04, 0x43, 0x03, 0x2d, 0x03, 0x01, 0x04, 0x11, 0x06, 0x0f,
|
|
||||||
0x0c, 0x3a, 0x04, 0x1d, 0x25, 0x5f, 0x20, 0x6d, 0x04, 0x6a, 0x25, 0x80,
|
|
||||||
0xc8, 0x05, 0x82, 0xb0, 0x03, 0x1a, 0x06, 0x82, 0xfd, 0x03, 0x59, 0x07,
|
|
||||||
0x15, 0x0b, 0x17, 0x09, 0x14, 0x0c, 0x14, 0x0c, 0x6a, 0x06, 0x0a, 0x06,
|
|
||||||
0x1a, 0x06, 0x59, 0x07, 0x2b, 0x05, 0x46, 0x0a, 0x2c, 0x04, 0x0c, 0x04,
|
|
||||||
0x01, 0x03, 0x31, 0x0b, 0x2c, 0x04, 0x1a, 0x06, 0x0b, 0x03, 0x80, 0xac,
|
|
||||||
0x06, 0x0a, 0x06, 0x21, 0x3f, 0x4c, 0x04, 0x2d, 0x03, 0x74, 0x08, 0x3c,
|
|
||||||
0x03, 0x0f, 0x03, 0x3c, 0x07, 0x38, 0x08, 0x2b, 0x05, 0x82, 0xff, 0x11,
|
|
||||||
0x18, 0x08, 0x2f, 0x11, 0x2d, 0x03, 0x20, 0x10, 0x21, 0x0f, 0x80, 0x8c,
|
|
||||||
0x04, 0x82, 0x97, 0x19, 0x0b, 0x15, 0x88, 0x94, 0x05, 0x2f, 0x05, 0x3b,
|
|
||||||
0x07, 0x02, 0x0e, 0x18, 0x09, 0x80, 0xb3, 0x2d, 0x74, 0x0c, 0x80, 0xd6,
|
|
||||||
0x1a, 0x0c, 0x05, 0x80, 0xff, 0x05, 0x80, 0xdf, 0x0c, 0xee, 0x0d, 0x03,
|
|
||||||
0x84, 0x8d, 0x03, 0x37, 0x09, 0x81, 0x5c, 0x14, 0x80, 0xb8, 0x08, 0x80,
|
|
||||||
0xcb, 0x2a, 0x38, 0x03, 0x0a, 0x06, 0x38, 0x08, 0x46, 0x08, 0x0c, 0x06,
|
|
||||||
0x74, 0x0b, 0x1e, 0x03, 0x5a, 0x04, 0x59, 0x09, 0x80, 0x83, 0x18, 0x1c,
|
|
||||||
0x0a, 0x16, 0x09, 0x4c, 0x04, 0x80, 0x8a, 0x06, 0xab, 0xa4, 0x0c, 0x17,
|
|
||||||
0x04, 0x31, 0xa1, 0x04, 0x81, 0xda, 0x26, 0x07, 0x0c, 0x05, 0x05, 0x80,
|
|
||||||
0xa5, 0x11, 0x81, 0x6d, 0x10, 0x78, 0x28, 0x2a, 0x06, 0x4c, 0x04, 0x80,
|
|
||||||
0x8d, 0x04, 0x80, 0xbe, 0x03, 0x1b, 0x03, 0x0f, 0x0d,
|
|
||||||
};
|
|
||||||
static constexpr unsigned char normal1[] = {
|
|
||||||
0x5e, 0x22, 0x7b, 0x05, 0x03, 0x04, 0x2d, 0x03, 0x66, 0x03, 0x01, 0x2f,
|
|
||||||
0x2e, 0x80, 0x82, 0x1d, 0x03, 0x31, 0x0f, 0x1c, 0x04, 0x24, 0x09, 0x1e,
|
|
||||||
0x05, 0x2b, 0x05, 0x44, 0x04, 0x0e, 0x2a, 0x80, 0xaa, 0x06, 0x24, 0x04,
|
|
||||||
0x24, 0x04, 0x28, 0x08, 0x34, 0x0b, 0x01, 0x80, 0x90, 0x81, 0x37, 0x09,
|
|
||||||
0x16, 0x0a, 0x08, 0x80, 0x98, 0x39, 0x03, 0x63, 0x08, 0x09, 0x30, 0x16,
|
|
||||||
0x05, 0x21, 0x03, 0x1b, 0x05, 0x01, 0x40, 0x38, 0x04, 0x4b, 0x05, 0x2f,
|
|
||||||
0x04, 0x0a, 0x07, 0x09, 0x07, 0x40, 0x20, 0x27, 0x04, 0x0c, 0x09, 0x36,
|
|
||||||
0x03, 0x3a, 0x05, 0x1a, 0x07, 0x04, 0x0c, 0x07, 0x50, 0x49, 0x37, 0x33,
|
|
||||||
0x0d, 0x33, 0x07, 0x2e, 0x08, 0x0a, 0x81, 0x26, 0x52, 0x4e, 0x28, 0x08,
|
|
||||||
0x2a, 0x56, 0x1c, 0x14, 0x17, 0x09, 0x4e, 0x04, 0x1e, 0x0f, 0x43, 0x0e,
|
|
||||||
0x19, 0x07, 0x0a, 0x06, 0x48, 0x08, 0x27, 0x09, 0x75, 0x0b, 0x3f, 0x41,
|
|
||||||
0x2a, 0x06, 0x3b, 0x05, 0x0a, 0x06, 0x51, 0x06, 0x01, 0x05, 0x10, 0x03,
|
|
||||||
0x05, 0x80, 0x8b, 0x62, 0x1e, 0x48, 0x08, 0x0a, 0x80, 0xa6, 0x5e, 0x22,
|
|
||||||
0x45, 0x0b, 0x0a, 0x06, 0x0d, 0x13, 0x39, 0x07, 0x0a, 0x36, 0x2c, 0x04,
|
|
||||||
0x10, 0x80, 0xc0, 0x3c, 0x64, 0x53, 0x0c, 0x48, 0x09, 0x0a, 0x46, 0x45,
|
|
||||||
0x1b, 0x48, 0x08, 0x53, 0x1d, 0x39, 0x81, 0x07, 0x46, 0x0a, 0x1d, 0x03,
|
|
||||||
0x47, 0x49, 0x37, 0x03, 0x0e, 0x08, 0x0a, 0x06, 0x39, 0x07, 0x0a, 0x81,
|
|
||||||
0x36, 0x19, 0x80, 0xb7, 0x01, 0x0f, 0x32, 0x0d, 0x83, 0x9b, 0x66, 0x75,
|
|
||||||
0x0b, 0x80, 0xc4, 0x8a, 0xbc, 0x84, 0x2f, 0x8f, 0xd1, 0x82, 0x47, 0xa1,
|
|
||||||
0xb9, 0x82, 0x39, 0x07, 0x2a, 0x04, 0x02, 0x60, 0x26, 0x0a, 0x46, 0x0a,
|
|
||||||
0x28, 0x05, 0x13, 0x82, 0xb0, 0x5b, 0x65, 0x4b, 0x04, 0x39, 0x07, 0x11,
|
|
||||||
0x40, 0x05, 0x0b, 0x02, 0x0e, 0x97, 0xf8, 0x08, 0x84, 0xd6, 0x2a, 0x09,
|
|
||||||
0xa2, 0xf7, 0x81, 0x1f, 0x31, 0x03, 0x11, 0x04, 0x08, 0x81, 0x8c, 0x89,
|
|
||||||
0x04, 0x6b, 0x05, 0x0d, 0x03, 0x09, 0x07, 0x10, 0x93, 0x60, 0x80, 0xf6,
|
|
||||||
0x0a, 0x73, 0x08, 0x6e, 0x17, 0x46, 0x80, 0x9a, 0x14, 0x0c, 0x57, 0x09,
|
|
||||||
0x19, 0x80, 0x87, 0x81, 0x47, 0x03, 0x85, 0x42, 0x0f, 0x15, 0x85, 0x50,
|
|
||||||
0x2b, 0x80, 0xd5, 0x2d, 0x03, 0x1a, 0x04, 0x02, 0x81, 0x70, 0x3a, 0x05,
|
|
||||||
0x01, 0x85, 0x00, 0x80, 0xd7, 0x29, 0x4c, 0x04, 0x0a, 0x04, 0x02, 0x83,
|
|
||||||
0x11, 0x44, 0x4c, 0x3d, 0x80, 0xc2, 0x3c, 0x06, 0x01, 0x04, 0x55, 0x05,
|
|
||||||
0x1b, 0x34, 0x02, 0x81, 0x0e, 0x2c, 0x04, 0x64, 0x0c, 0x56, 0x0a, 0x80,
|
|
||||||
0xae, 0x38, 0x1d, 0x0d, 0x2c, 0x04, 0x09, 0x07, 0x02, 0x0e, 0x06, 0x80,
|
|
||||||
0x9a, 0x83, 0xd8, 0x08, 0x0d, 0x03, 0x0d, 0x03, 0x74, 0x0c, 0x59, 0x07,
|
|
||||||
0x0c, 0x14, 0x0c, 0x04, 0x38, 0x08, 0x0a, 0x06, 0x28, 0x08, 0x22, 0x4e,
|
|
||||||
0x81, 0x54, 0x0c, 0x15, 0x03, 0x03, 0x05, 0x07, 0x09, 0x19, 0x07, 0x07,
|
|
||||||
0x09, 0x03, 0x0d, 0x07, 0x29, 0x80, 0xcb, 0x25, 0x0a, 0x84, 0x06,
|
|
||||||
};
|
|
||||||
auto lower = static_cast<uint16_t>(cp);
|
|
||||||
if (cp < 0x10000) {
|
|
||||||
return is_printable(lower, singletons0,
|
|
||||||
sizeof(singletons0) / sizeof(*singletons0),
|
|
||||||
singletons0_lower, normal0, sizeof(normal0));
|
|
||||||
}
|
|
||||||
if (cp < 0x20000) {
|
|
||||||
return is_printable(lower, singletons1,
|
|
||||||
sizeof(singletons1) / sizeof(*singletons1),
|
|
||||||
singletons1_lower, normal1, sizeof(normal1));
|
|
||||||
}
|
|
||||||
if (0x2a6de <= cp && cp < 0x2a700) return false;
|
|
||||||
if (0x2b735 <= cp && cp < 0x2b740) return false;
|
|
||||||
if (0x2b81e <= cp && cp < 0x2b820) return false;
|
|
||||||
if (0x2cea2 <= cp && cp < 0x2ceb0) return false;
|
|
||||||
if (0x2ebe1 <= cp && cp < 0x2f800) return false;
|
|
||||||
if (0x2fa1e <= cp && cp < 0x30000) return false;
|
|
||||||
if (0x3134b <= cp && cp < 0xe0100) return false;
|
|
||||||
if (0xe01f0 <= cp && cp < 0x110000) return false;
|
|
||||||
return cp < 0x110000;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline auto needs_escape(uint32_t cp) -> bool {
|
|
||||||
return cp < 0x20 || cp == 0x7f || cp == '"' || cp == '\\' ||
|
|
||||||
!is_printable(cp);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename Char> struct find_escape_result {
|
|
||||||
const Char* begin;
|
|
||||||
const Char* end;
|
|
||||||
uint32_t cp;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename Char>
|
|
||||||
auto find_escape(const Char* begin, const Char* end)
|
|
||||||
-> find_escape_result<Char> {
|
|
||||||
for (; begin != end; ++begin) {
|
|
||||||
auto cp = static_cast<typename std::make_unsigned<Char>::type>(*begin);
|
|
||||||
if (sizeof(Char) == 1 && cp >= 0x80) continue;
|
|
||||||
if (needs_escape(cp)) return {begin, begin + 1, cp};
|
|
||||||
}
|
|
||||||
return {begin, nullptr, 0};
|
|
||||||
}
|
|
||||||
|
|
||||||
inline auto find_escape(const char* begin, const char* end)
|
|
||||||
-> find_escape_result<char> {
|
|
||||||
if (!is_utf8()) return find_escape<char>(begin, end);
|
|
||||||
auto result = find_escape_result<char>{end, nullptr, 0};
|
|
||||||
for_each_codepoint(string_view(begin, to_unsigned(end - begin)),
|
|
||||||
[&](uint32_t cp, string_view sv) {
|
|
||||||
if (needs_escape(cp)) {
|
|
||||||
result = {sv.begin(), sv.end(), cp};
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename Char, typename OutputIt>
|
|
||||||
auto write_range_entry(OutputIt out, basic_string_view<Char> str) -> OutputIt {
|
|
||||||
*out++ = '"';
|
|
||||||
auto begin = str.begin(), end = str.end();
|
|
||||||
do {
|
|
||||||
auto escape = find_escape(begin, end);
|
|
||||||
out = copy_str<Char>(begin, escape.begin, out);
|
|
||||||
begin = escape.end;
|
|
||||||
if (!begin) break;
|
|
||||||
auto c = static_cast<Char>(escape.cp);
|
|
||||||
switch (escape.cp) {
|
|
||||||
case '\n':
|
|
||||||
*out++ = '\\';
|
|
||||||
c = 'n';
|
|
||||||
break;
|
|
||||||
case '\r':
|
|
||||||
*out++ = '\\';
|
|
||||||
c = 'r';
|
|
||||||
break;
|
|
||||||
case '\t':
|
|
||||||
*out++ = '\\';
|
|
||||||
c = 't';
|
|
||||||
break;
|
|
||||||
case '"':
|
|
||||||
FMT_FALLTHROUGH;
|
|
||||||
case '\\':
|
|
||||||
*out++ = '\\';
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
if (is_utf8()) {
|
|
||||||
if (escape.cp < 0x100) {
|
|
||||||
out = format_to(out, "\\x{:02x}", escape.cp);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (escape.cp < 0x10000) {
|
|
||||||
out = format_to(out, "\\u{:04x}", escape.cp);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (escape.cp < 0x110000) {
|
|
||||||
out = format_to(out, "\\U{:08x}", escape.cp);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (Char escape_char : basic_string_view<Char>(
|
|
||||||
escape.begin, to_unsigned(escape.end - escape.begin))) {
|
|
||||||
out = format_to(
|
|
||||||
out, "\\x{:02x}",
|
|
||||||
static_cast<typename std::make_unsigned<Char>::type>(escape_char));
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
*out++ = c;
|
|
||||||
} while (begin != end);
|
|
||||||
*out++ = '"';
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename Char, typename OutputIt, typename T,
|
|
||||||
FMT_ENABLE_IF(std::is_convertible<T, std_string_view<char>>::value)>
|
|
||||||
inline auto write_range_entry(OutputIt out, const T& str) -> OutputIt {
|
|
||||||
auto sv = std_string_view<Char>(str);
|
|
||||||
return write_range_entry<Char>(out, basic_string_view<Char>(sv));
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename Char, typename OutputIt, typename Arg,
|
|
||||||
FMT_ENABLE_IF(std::is_same<Arg, Char>::value)>
|
|
||||||
OutputIt write_range_entry(OutputIt out, const Arg v) {
|
|
||||||
*out++ = '\'';
|
|
||||||
*out++ = v;
|
|
||||||
*out++ = '\'';
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <
|
|
||||||
typename Char, typename OutputIt, typename Arg,
|
|
||||||
FMT_ENABLE_IF(!is_std_string_like<typename std::decay<Arg>::type>::value &&
|
|
||||||
!std::is_same<Arg, Char>::value)>
|
|
||||||
OutputIt write_range_entry(OutputIt out, const Arg& v) {
|
|
||||||
return write<Char>(out, v);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
|
|
||||||
template <typename T> struct is_tuple_like {
|
template <typename T> struct is_tuple_like {
|
||||||
static FMT_CONSTEXPR_DECL const bool value =
|
static constexpr const bool value =
|
||||||
detail::is_tuple_like_<T>::value && !detail::is_range_<T>::value;
|
detail::is_tuple_like_<T>::value && !detail::is_range_<T>::value;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename TupleT, typename Char>
|
template <typename T, typename C> struct is_tuple_formattable {
|
||||||
struct formatter<TupleT, Char, enable_if_t<fmt::is_tuple_like<TupleT>::value>> {
|
static constexpr const bool value =
|
||||||
|
detail::is_tuple_formattable_<T, C>::value;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Tuple, typename Char>
|
||||||
|
struct formatter<Tuple, Char,
|
||||||
|
enable_if_t<fmt::is_tuple_like<Tuple>::value &&
|
||||||
|
fmt::is_tuple_formattable<Tuple, Char>::value>> {
|
||||||
private:
|
private:
|
||||||
// C++11 generic lambda for format().
|
decltype(detail::tuple::get_formatters<Tuple, Char>(
|
||||||
template <typename FormatContext> struct format_each {
|
detail::tuple_index_sequence<Tuple>())) formatters_;
|
||||||
template <typename T> void operator()(const T& v) {
|
|
||||||
if (i > 0) out = detail::write_delimiter(out);
|
basic_string_view<Char> separator_ = detail::string_literal<Char, ',', ' '>{};
|
||||||
out = detail::write_range_entry<Char>(out, v);
|
basic_string_view<Char> opening_bracket_ =
|
||||||
++i;
|
detail::string_literal<Char, '('>{};
|
||||||
}
|
basic_string_view<Char> closing_bracket_ =
|
||||||
int i;
|
detail::string_literal<Char, ')'>{};
|
||||||
typename FormatContext::iterator& out;
|
|
||||||
};
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
template <typename ParseContext>
|
FMT_CONSTEXPR formatter() {}
|
||||||
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
|
|
||||||
return ctx.begin();
|
FMT_CONSTEXPR void set_separator(basic_string_view<Char> sep) {
|
||||||
|
separator_ = sep;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename FormatContext = format_context>
|
FMT_CONSTEXPR void set_brackets(basic_string_view<Char> open,
|
||||||
auto format(const TupleT& values, FormatContext& ctx) -> decltype(ctx.out()) {
|
basic_string_view<Char> close) {
|
||||||
auto out = ctx.out();
|
opening_bracket_ = open;
|
||||||
*out++ = '(';
|
closing_bracket_ = close;
|
||||||
detail::for_each(values, format_each<FormatContext>{0, out});
|
}
|
||||||
*out++ = ')';
|
|
||||||
return out;
|
template <typename ParseContext>
|
||||||
|
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
|
||||||
|
auto it = ctx.begin();
|
||||||
|
if (it != ctx.end() && *it != '}')
|
||||||
|
FMT_THROW(format_error("invalid format specifier"));
|
||||||
|
detail::for_each(formatters_, detail::parse_empty_specs<ParseContext>{ctx});
|
||||||
|
return it;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename FormatContext>
|
||||||
|
auto format(const Tuple& value, FormatContext& ctx) const
|
||||||
|
-> decltype(ctx.out()) {
|
||||||
|
ctx.advance_to(detail::copy_str<Char>(opening_bracket_, ctx.out()));
|
||||||
|
detail::for_each2(
|
||||||
|
formatters_, value,
|
||||||
|
detail::format_tuple_element<FormatContext>{0, ctx, separator_});
|
||||||
|
return detail::copy_str<Char>(closing_bracket_, ctx.out());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T, typename Char> struct is_range {
|
template <typename T, typename Char> struct is_range {
|
||||||
static FMT_CONSTEXPR_DECL const bool value =
|
static constexpr const bool value =
|
||||||
detail::is_range_<T>::value && !detail::is_std_string_like<T>::value &&
|
detail::is_range_<T>::value && !detail::is_std_string_like<T>::value &&
|
||||||
!detail::is_map<T>::value &&
|
|
||||||
!std::is_convertible<T, std::basic_string<Char>>::value &&
|
!std::is_convertible<T, std::basic_string<Char>>::value &&
|
||||||
!std::is_constructible<detail::std_string_view<Char>, T>::value;
|
!std::is_convertible<T, detail::std_string_view<Char>>::value;
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
template <typename Context, typename Element> struct range_mapper {
|
template <typename Context> struct range_mapper {
|
||||||
using mapper = arg_mapper<Context>;
|
using mapper = arg_mapper<Context>;
|
||||||
|
|
||||||
template <typename T,
|
template <typename T,
|
||||||
@@ -620,116 +405,170 @@ template <typename Context, typename Element> struct range_mapper {
|
|||||||
|
|
||||||
template <typename Char, typename Element>
|
template <typename Char, typename Element>
|
||||||
using range_formatter_type =
|
using range_formatter_type =
|
||||||
conditional_t<is_formattable<Element, Char>::value,
|
formatter<remove_cvref_t<decltype(range_mapper<buffer_context<Char>>{}.map(
|
||||||
formatter<remove_cvref_t<decltype(
|
std::declval<Element>()))>,
|
||||||
range_mapper<buffer_context<Char>, Element>{}
|
Char>;
|
||||||
.map(std::declval<Element>()))>,
|
|
||||||
Char>,
|
template <typename R>
|
||||||
fallback_formatter<Element, Char>>;
|
using maybe_const_range =
|
||||||
|
conditional_t<has_const_begin_end<R>::value, const R, R>;
|
||||||
|
|
||||||
|
// Workaround a bug in MSVC 2015 and earlier.
|
||||||
|
#if !FMT_MSC_VERSION || FMT_MSC_VERSION >= 1910
|
||||||
|
template <typename R, typename Char>
|
||||||
|
struct is_formattable_delayed
|
||||||
|
: is_formattable<uncvref_type<maybe_const_range<R>>, Char> {};
|
||||||
|
#endif
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
|
|
||||||
template <typename R, typename Char>
|
template <typename T, typename Char, typename Enable = void>
|
||||||
struct formatter<
|
struct range_formatter;
|
||||||
R, Char,
|
|
||||||
enable_if_t<fmt::is_range<R, Char>::value
|
|
||||||
// Workaround a bug in MSVC 2019 and earlier.
|
|
||||||
#if !FMT_MSC_VER
|
|
||||||
&& (is_formattable<detail::uncvref_type<R>, Char>::value ||
|
|
||||||
detail::has_fallback_formatter<detail::uncvref_type<R>,
|
|
||||||
Char>::value)
|
|
||||||
#endif
|
|
||||||
>> {
|
|
||||||
|
|
||||||
using formatter_type =
|
template <typename T, typename Char>
|
||||||
detail::range_formatter_type<Char, detail::uncvref_type<R>>;
|
struct range_formatter<
|
||||||
formatter_type underlying_;
|
T, Char,
|
||||||
bool custom_specs_ = false;
|
enable_if_t<conjunction<std::is_same<T, remove_cvref_t<T>>,
|
||||||
|
is_formattable<T, Char>>::value>> {
|
||||||
|
private:
|
||||||
|
detail::range_formatter_type<Char, T> underlying_;
|
||||||
|
basic_string_view<Char> separator_ = detail::string_literal<Char, ',', ' '>{};
|
||||||
|
basic_string_view<Char> opening_bracket_ =
|
||||||
|
detail::string_literal<Char, '['>{};
|
||||||
|
basic_string_view<Char> closing_bracket_ =
|
||||||
|
detail::string_literal<Char, ']'>{};
|
||||||
|
|
||||||
|
public:
|
||||||
|
FMT_CONSTEXPR range_formatter() {}
|
||||||
|
|
||||||
|
FMT_CONSTEXPR auto underlying() -> detail::range_formatter_type<Char, T>& {
|
||||||
|
return underlying_;
|
||||||
|
}
|
||||||
|
|
||||||
|
FMT_CONSTEXPR void set_separator(basic_string_view<Char> sep) {
|
||||||
|
separator_ = sep;
|
||||||
|
}
|
||||||
|
|
||||||
|
FMT_CONSTEXPR void set_brackets(basic_string_view<Char> open,
|
||||||
|
basic_string_view<Char> close) {
|
||||||
|
opening_bracket_ = open;
|
||||||
|
closing_bracket_ = close;
|
||||||
|
}
|
||||||
|
|
||||||
template <typename ParseContext>
|
template <typename ParseContext>
|
||||||
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
|
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
|
||||||
auto it = ctx.begin();
|
auto it = ctx.begin();
|
||||||
auto end = ctx.end();
|
auto end = ctx.end();
|
||||||
if (it == end || *it == '}') return it;
|
|
||||||
|
|
||||||
if (*it != ':')
|
if (it != end && *it == 'n') {
|
||||||
FMT_THROW(format_error("no top-level range formatters supported"));
|
set_brackets({}, {});
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (it != end && *it != '}') {
|
||||||
|
if (*it != ':') FMT_THROW(format_error("invalid format specifier"));
|
||||||
|
++it;
|
||||||
|
} else {
|
||||||
|
detail::maybe_set_debug_format(underlying_, true);
|
||||||
|
}
|
||||||
|
|
||||||
custom_specs_ = true;
|
|
||||||
++it;
|
|
||||||
ctx.advance_to(it);
|
ctx.advance_to(it);
|
||||||
return underlying_.parse(ctx);
|
return underlying_.parse(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <
|
template <typename R, typename FormatContext>
|
||||||
typename FormatContext, typename U,
|
auto format(R&& range, FormatContext& ctx) const -> decltype(ctx.out()) {
|
||||||
FMT_ENABLE_IF(
|
detail::range_mapper<buffer_context<Char>> mapper;
|
||||||
std::is_same<U, conditional_t<detail::has_const_begin_end<R>::value,
|
|
||||||
const R, R>>::value)>
|
|
||||||
auto format(U& range, FormatContext& ctx) -> decltype(ctx.out()) {
|
|
||||||
#ifdef FMT_DEPRECATED_BRACED_RANGES
|
|
||||||
Char prefix = '{';
|
|
||||||
Char postfix = '}';
|
|
||||||
#else
|
|
||||||
Char prefix = detail::is_set<R>::value ? '{' : '[';
|
|
||||||
Char postfix = detail::is_set<R>::value ? '}' : ']';
|
|
||||||
#endif
|
|
||||||
detail::range_mapper<buffer_context<Char>, detail::uncvref_type<R>> mapper;
|
|
||||||
auto out = ctx.out();
|
auto out = ctx.out();
|
||||||
*out++ = prefix;
|
out = detail::copy_str<Char>(opening_bracket_, out);
|
||||||
int i = 0;
|
int i = 0;
|
||||||
auto it = std::begin(range);
|
auto it = detail::range_begin(range);
|
||||||
auto end = std::end(range);
|
auto end = detail::range_end(range);
|
||||||
for (; it != end; ++it) {
|
for (; it != end; ++it) {
|
||||||
if (i > 0) out = detail::write_delimiter(out);
|
if (i > 0) out = detail::copy_str<Char>(separator_, out);
|
||||||
if (custom_specs_) {
|
ctx.advance_to(out);
|
||||||
ctx.advance_to(out);
|
out = underlying_.format(mapper.map(*it), ctx);
|
||||||
out = underlying_.format(mapper.map(*it), ctx);
|
|
||||||
} else {
|
|
||||||
out = detail::write_range_entry<Char>(out, *it);
|
|
||||||
}
|
|
||||||
++i;
|
++i;
|
||||||
}
|
}
|
||||||
*out++ = postfix;
|
out = detail::copy_str<Char>(closing_bracket_, out);
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T, typename Char>
|
enum class range_format { disabled, map, set, sequence, string, debug_string };
|
||||||
struct formatter<
|
|
||||||
T, Char,
|
namespace detail {
|
||||||
enable_if_t<detail::is_map<T>::value
|
template <typename T>
|
||||||
// Workaround a bug in MSVC 2019 and earlier.
|
struct range_format_kind_
|
||||||
#if !FMT_MSC_VER
|
: std::integral_constant<range_format,
|
||||||
&& (is_formattable<detail::uncvref_type<T>, Char>::value ||
|
std::is_same<uncvref_type<T>, T>::value
|
||||||
detail::has_fallback_formatter<detail::uncvref_type<T>,
|
? range_format::disabled
|
||||||
Char>::value)
|
: is_map<T>::value ? range_format::map
|
||||||
#endif
|
: is_set<T>::value ? range_format::set
|
||||||
>> {
|
: range_format::sequence> {};
|
||||||
template <typename ParseContext>
|
|
||||||
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
|
template <range_format K, typename R, typename Char, typename Enable = void>
|
||||||
return ctx.begin();
|
struct range_default_formatter;
|
||||||
|
|
||||||
|
template <range_format K>
|
||||||
|
using range_format_constant = std::integral_constant<range_format, K>;
|
||||||
|
|
||||||
|
template <range_format K, typename R, typename Char>
|
||||||
|
struct range_default_formatter<
|
||||||
|
K, R, Char,
|
||||||
|
enable_if_t<(K == range_format::sequence || K == range_format::map ||
|
||||||
|
K == range_format::set)>> {
|
||||||
|
using range_type = detail::maybe_const_range<R>;
|
||||||
|
range_formatter<detail::uncvref_type<range_type>, Char> underlying_;
|
||||||
|
|
||||||
|
FMT_CONSTEXPR range_default_formatter() { init(range_format_constant<K>()); }
|
||||||
|
|
||||||
|
FMT_CONSTEXPR void init(range_format_constant<range_format::set>) {
|
||||||
|
underlying_.set_brackets(detail::string_literal<Char, '{'>{},
|
||||||
|
detail::string_literal<Char, '}'>{});
|
||||||
}
|
}
|
||||||
|
|
||||||
template <
|
FMT_CONSTEXPR void init(range_format_constant<range_format::map>) {
|
||||||
typename FormatContext, typename U,
|
underlying_.set_brackets(detail::string_literal<Char, '{'>{},
|
||||||
FMT_ENABLE_IF(
|
detail::string_literal<Char, '}'>{});
|
||||||
std::is_same<U, conditional_t<detail::has_const_begin_end<T>::value,
|
underlying_.underlying().set_brackets({}, {});
|
||||||
const T, T>>::value)>
|
underlying_.underlying().set_separator(
|
||||||
auto format(U& map, FormatContext& ctx) -> decltype(ctx.out()) {
|
detail::string_literal<Char, ':', ' '>{});
|
||||||
auto out = ctx.out();
|
|
||||||
*out++ = '{';
|
|
||||||
int i = 0;
|
|
||||||
for (const auto& item : map) {
|
|
||||||
if (i > 0) out = detail::write_delimiter(out);
|
|
||||||
out = detail::write_range_entry<Char>(out, item.first);
|
|
||||||
*out++ = ':';
|
|
||||||
*out++ = ' ';
|
|
||||||
out = detail::write_range_entry<Char>(out, item.second);
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
*out++ = '}';
|
|
||||||
return out;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FMT_CONSTEXPR void init(range_format_constant<range_format::sequence>) {}
|
||||||
|
|
||||||
|
template <typename ParseContext>
|
||||||
|
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
|
||||||
|
return underlying_.parse(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename FormatContext>
|
||||||
|
auto format(range_type& range, FormatContext& ctx) const
|
||||||
|
-> decltype(ctx.out()) {
|
||||||
|
return underlying_.format(range, ctx);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
template <typename T, typename Char, typename Enable = void>
|
||||||
|
struct range_format_kind
|
||||||
|
: conditional_t<
|
||||||
|
is_range<T, Char>::value, detail::range_format_kind_<T>,
|
||||||
|
std::integral_constant<range_format, range_format::disabled>> {};
|
||||||
|
|
||||||
|
template <typename R, typename Char>
|
||||||
|
struct formatter<
|
||||||
|
R, Char,
|
||||||
|
enable_if_t<conjunction<bool_constant<range_format_kind<R, Char>::value !=
|
||||||
|
range_format::disabled>
|
||||||
|
// Workaround a bug in MSVC 2015 and earlier.
|
||||||
|
#if !FMT_MSC_VERSION || FMT_MSC_VERSION >= 1910
|
||||||
|
,
|
||||||
|
detail::is_formattable_delayed<R, Char>
|
||||||
|
#endif
|
||||||
|
>::value>>
|
||||||
|
: detail::range_default_formatter<range_format_kind<R, Char>::value, R,
|
||||||
|
Char> {
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename Char, typename... T> struct tuple_join_view : detail::view {
|
template <typename Char, typename... T> struct tuple_join_view : detail::view {
|
||||||
@@ -740,9 +579,6 @@ template <typename Char, typename... T> struct tuple_join_view : detail::view {
|
|||||||
: tuple(t), sep{s} {}
|
: tuple(t), sep{s} {}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename Char, typename... T>
|
|
||||||
using tuple_arg_join = tuple_join_view<Char, T...>;
|
|
||||||
|
|
||||||
// Define FMT_TUPLE_JOIN_SPECIFIERS to enable experimental format specifiers
|
// Define FMT_TUPLE_JOIN_SPECIFIERS to enable experimental format specifiers
|
||||||
// support in tuple_join. It is disabled by default because of issues with
|
// support in tuple_join. It is disabled by default because of issues with
|
||||||
// the dynamic width and precision.
|
// the dynamic width and precision.
|
||||||
@@ -812,7 +648,45 @@ struct formatter<tuple_join_view<Char, T...>, Char> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
FMT_MODULE_EXPORT_BEGIN
|
namespace detail {
|
||||||
|
// Check if T has an interface like a container adaptor (e.g. std::stack,
|
||||||
|
// std::queue, std::priority_queue).
|
||||||
|
template <typename T> class is_container_adaptor_like {
|
||||||
|
template <typename U> static auto check(U* p) -> typename U::container_type;
|
||||||
|
template <typename> static void check(...);
|
||||||
|
|
||||||
|
public:
|
||||||
|
static constexpr const bool value =
|
||||||
|
!std::is_void<decltype(check<T>(nullptr))>::value;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Container> struct all {
|
||||||
|
const Container& c;
|
||||||
|
auto begin() const -> typename Container::const_iterator { return c.begin(); }
|
||||||
|
auto end() const -> typename Container::const_iterator { return c.end(); }
|
||||||
|
};
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
template <typename T, typename Char>
|
||||||
|
struct formatter<
|
||||||
|
T, Char,
|
||||||
|
enable_if_t<conjunction<detail::is_container_adaptor_like<T>,
|
||||||
|
bool_constant<range_format_kind<T, Char>::value ==
|
||||||
|
range_format::disabled>>::value>>
|
||||||
|
: formatter<detail::all<typename T::container_type>, Char> {
|
||||||
|
using all = detail::all<typename T::container_type>;
|
||||||
|
template <typename FormatContext>
|
||||||
|
auto format(const T& t, FormatContext& ctx) const -> decltype(ctx.out()) {
|
||||||
|
struct getter : T {
|
||||||
|
static auto get(const T& t) -> all {
|
||||||
|
return {t.*(&getter::c)}; // Access c through the derived class.
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return formatter<all>::format(getter::get(t), ctx);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
FMT_BEGIN_EXPORT
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\rst
|
\rst
|
||||||
@@ -855,7 +729,7 @@ auto join(std::initializer_list<T> list, string_view sep)
|
|||||||
return join(std::begin(list), std::end(list), sep);
|
return join(std::begin(list), std::end(list), sep);
|
||||||
}
|
}
|
||||||
|
|
||||||
FMT_MODULE_EXPORT_END
|
FMT_END_EXPORT
|
||||||
FMT_END_NAMESPACE
|
FMT_END_NAMESPACE
|
||||||
|
|
||||||
#endif // FMT_RANGES_H_
|
#endif // FMT_RANGES_H_
|
||||||
|
|||||||
465
deps/fmt/include/fmt/std.h
vendored
Normal file
465
deps/fmt/include/fmt/std.h
vendored
Normal file
@@ -0,0 +1,465 @@
|
|||||||
|
// Formatting library for C++ - formatters for standard library types
|
||||||
|
//
|
||||||
|
// Copyright (c) 2012 - present, Victor Zverovich
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// For the license information refer to format.h.
|
||||||
|
|
||||||
|
#ifndef FMT_STD_H_
|
||||||
|
#define FMT_STD_H_
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
|
#include <bitset>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <exception>
|
||||||
|
#include <memory>
|
||||||
|
#include <thread>
|
||||||
|
#include <type_traits>
|
||||||
|
#include <typeinfo>
|
||||||
|
#include <utility>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "format.h"
|
||||||
|
#include "ostream.h"
|
||||||
|
|
||||||
|
#if FMT_HAS_INCLUDE(<version>)
|
||||||
|
# include <version>
|
||||||
|
#endif
|
||||||
|
// Checking FMT_CPLUSPLUS for warning suppression in MSVC.
|
||||||
|
#if FMT_CPLUSPLUS >= 201703L
|
||||||
|
# if FMT_HAS_INCLUDE(<filesystem>)
|
||||||
|
# include <filesystem>
|
||||||
|
# endif
|
||||||
|
# if FMT_HAS_INCLUDE(<variant>)
|
||||||
|
# include <variant>
|
||||||
|
# endif
|
||||||
|
# if FMT_HAS_INCLUDE(<optional>)
|
||||||
|
# include <optional>
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// GCC 4 does not support FMT_HAS_INCLUDE.
|
||||||
|
#if FMT_HAS_INCLUDE(<cxxabi.h>) || defined(__GLIBCXX__)
|
||||||
|
# include <cxxabi.h>
|
||||||
|
// Android NDK with gabi++ library on some architectures does not implement
|
||||||
|
// abi::__cxa_demangle().
|
||||||
|
# ifndef __GABIXX_CXXABI_H__
|
||||||
|
# define FMT_HAS_ABI_CXA_DEMANGLE
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Check if typeid is available.
|
||||||
|
#ifndef FMT_USE_TYPEID
|
||||||
|
// __RTTI is for EDG compilers. In MSVC typeid is available without RTTI.
|
||||||
|
# if defined(__GXX_RTTI) || FMT_HAS_FEATURE(cxx_rtti) || FMT_MSC_VERSION || \
|
||||||
|
defined(__INTEL_RTTI__) || defined(__RTTI)
|
||||||
|
# define FMT_USE_TYPEID 1
|
||||||
|
# else
|
||||||
|
# define FMT_USE_TYPEID 0
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cpp_lib_filesystem
|
||||||
|
FMT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
template <typename Char> auto get_path_string(const std::filesystem::path& p) {
|
||||||
|
return p.string<Char>();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Char>
|
||||||
|
void write_escaped_path(basic_memory_buffer<Char>& quoted,
|
||||||
|
const std::filesystem::path& p) {
|
||||||
|
write_escaped_string<Char>(std::back_inserter(quoted), p.string<Char>());
|
||||||
|
}
|
||||||
|
|
||||||
|
# ifdef _WIN32
|
||||||
|
template <>
|
||||||
|
inline auto get_path_string<char>(const std::filesystem::path& p) {
|
||||||
|
return to_utf8<wchar_t>(p.native(), to_utf8_error_policy::replace);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
inline void write_escaped_path<char>(memory_buffer& quoted,
|
||||||
|
const std::filesystem::path& p) {
|
||||||
|
auto buf = basic_memory_buffer<wchar_t>();
|
||||||
|
write_escaped_string<wchar_t>(std::back_inserter(buf), p.native());
|
||||||
|
bool valid = to_utf8<wchar_t>::convert(quoted, {buf.data(), buf.size()});
|
||||||
|
FMT_ASSERT(valid, "invalid utf16");
|
||||||
|
}
|
||||||
|
# endif // _WIN32
|
||||||
|
|
||||||
|
template <>
|
||||||
|
inline void write_escaped_path<std::filesystem::path::value_type>(
|
||||||
|
basic_memory_buffer<std::filesystem::path::value_type>& quoted,
|
||||||
|
const std::filesystem::path& p) {
|
||||||
|
write_escaped_string<std::filesystem::path::value_type>(
|
||||||
|
std::back_inserter(quoted), p.native());
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
FMT_EXPORT
|
||||||
|
template <typename Char> struct formatter<std::filesystem::path, Char> {
|
||||||
|
private:
|
||||||
|
format_specs<Char> specs_;
|
||||||
|
detail::arg_ref<Char> width_ref_;
|
||||||
|
bool debug_ = false;
|
||||||
|
|
||||||
|
public:
|
||||||
|
FMT_CONSTEXPR void set_debug_format(bool set = true) { debug_ = set; }
|
||||||
|
|
||||||
|
template <typename ParseContext> FMT_CONSTEXPR auto parse(ParseContext& ctx) {
|
||||||
|
auto it = ctx.begin(), end = ctx.end();
|
||||||
|
if (it == end) return it;
|
||||||
|
|
||||||
|
it = detail::parse_align(it, end, specs_);
|
||||||
|
if (it == end) return it;
|
||||||
|
|
||||||
|
it = detail::parse_dynamic_spec(it, end, specs_.width, width_ref_, ctx);
|
||||||
|
if (it != end && *it == '?') {
|
||||||
|
debug_ = true;
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
return it;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename FormatContext>
|
||||||
|
auto format(const std::filesystem::path& p, FormatContext& ctx) const {
|
||||||
|
auto specs = specs_;
|
||||||
|
detail::handle_dynamic_spec<detail::width_checker>(specs.width, width_ref_,
|
||||||
|
ctx);
|
||||||
|
if (!debug_) {
|
||||||
|
auto s = detail::get_path_string<Char>(p);
|
||||||
|
return detail::write(ctx.out(), basic_string_view<Char>(s), specs);
|
||||||
|
}
|
||||||
|
auto quoted = basic_memory_buffer<Char>();
|
||||||
|
detail::write_escaped_path(quoted, p);
|
||||||
|
return detail::write(ctx.out(),
|
||||||
|
basic_string_view<Char>(quoted.data(), quoted.size()),
|
||||||
|
specs);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
FMT_END_NAMESPACE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
FMT_BEGIN_NAMESPACE
|
||||||
|
FMT_EXPORT
|
||||||
|
template <typename Char>
|
||||||
|
struct formatter<std::thread::id, Char> : basic_ostream_formatter<Char> {};
|
||||||
|
FMT_END_NAMESPACE
|
||||||
|
|
||||||
|
#ifdef __cpp_lib_optional
|
||||||
|
FMT_BEGIN_NAMESPACE
|
||||||
|
FMT_EXPORT
|
||||||
|
template <typename T, typename Char>
|
||||||
|
struct formatter<std::optional<T>, Char,
|
||||||
|
std::enable_if_t<is_formattable<T, Char>::value>> {
|
||||||
|
private:
|
||||||
|
formatter<T, Char> underlying_;
|
||||||
|
static constexpr basic_string_view<Char> optional =
|
||||||
|
detail::string_literal<Char, 'o', 'p', 't', 'i', 'o', 'n', 'a', 'l',
|
||||||
|
'('>{};
|
||||||
|
static constexpr basic_string_view<Char> none =
|
||||||
|
detail::string_literal<Char, 'n', 'o', 'n', 'e'>{};
|
||||||
|
|
||||||
|
template <class U>
|
||||||
|
FMT_CONSTEXPR static auto maybe_set_debug_format(U& u, bool set)
|
||||||
|
-> decltype(u.set_debug_format(set)) {
|
||||||
|
u.set_debug_format(set);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class U>
|
||||||
|
FMT_CONSTEXPR static void maybe_set_debug_format(U&, ...) {}
|
||||||
|
|
||||||
|
public:
|
||||||
|
template <typename ParseContext> FMT_CONSTEXPR auto parse(ParseContext& ctx) {
|
||||||
|
maybe_set_debug_format(underlying_, true);
|
||||||
|
return underlying_.parse(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename FormatContext>
|
||||||
|
auto format(std::optional<T> const& opt, FormatContext& ctx) const
|
||||||
|
-> decltype(ctx.out()) {
|
||||||
|
if (!opt) return detail::write<Char>(ctx.out(), none);
|
||||||
|
|
||||||
|
auto out = ctx.out();
|
||||||
|
out = detail::write<Char>(out, optional);
|
||||||
|
ctx.advance_to(out);
|
||||||
|
out = underlying_.format(*opt, ctx);
|
||||||
|
return detail::write(out, ')');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
FMT_END_NAMESPACE
|
||||||
|
#endif // __cpp_lib_optional
|
||||||
|
|
||||||
|
#ifdef __cpp_lib_variant
|
||||||
|
FMT_BEGIN_NAMESPACE
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
using variant_index_sequence =
|
||||||
|
std::make_index_sequence<std::variant_size<T>::value>;
|
||||||
|
|
||||||
|
template <typename> struct is_variant_like_ : std::false_type {};
|
||||||
|
template <typename... Types>
|
||||||
|
struct is_variant_like_<std::variant<Types...>> : std::true_type {};
|
||||||
|
|
||||||
|
// formattable element check.
|
||||||
|
template <typename T, typename C> class is_variant_formattable_ {
|
||||||
|
template <std::size_t... Is>
|
||||||
|
static std::conjunction<
|
||||||
|
is_formattable<std::variant_alternative_t<Is, T>, C>...>
|
||||||
|
check(std::index_sequence<Is...>);
|
||||||
|
|
||||||
|
public:
|
||||||
|
static constexpr const bool value =
|
||||||
|
decltype(check(variant_index_sequence<T>{}))::value;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Char, typename OutputIt, typename T>
|
||||||
|
auto write_variant_alternative(OutputIt out, const T& v) -> OutputIt {
|
||||||
|
if constexpr (is_string<T>::value)
|
||||||
|
return write_escaped_string<Char>(out, detail::to_string_view(v));
|
||||||
|
else if constexpr (std::is_same_v<T, Char>)
|
||||||
|
return write_escaped_char(out, v);
|
||||||
|
else
|
||||||
|
return write<Char>(out, v);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
template <typename T> struct is_variant_like {
|
||||||
|
static constexpr const bool value = detail::is_variant_like_<T>::value;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T, typename C> struct is_variant_formattable {
|
||||||
|
static constexpr const bool value =
|
||||||
|
detail::is_variant_formattable_<T, C>::value;
|
||||||
|
};
|
||||||
|
|
||||||
|
FMT_EXPORT
|
||||||
|
template <typename Char> struct formatter<std::monostate, Char> {
|
||||||
|
template <typename ParseContext>
|
||||||
|
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
|
||||||
|
return ctx.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename FormatContext>
|
||||||
|
auto format(const std::monostate&, FormatContext& ctx) const
|
||||||
|
-> decltype(ctx.out()) {
|
||||||
|
return detail::write<Char>(ctx.out(), "monostate");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
FMT_EXPORT
|
||||||
|
template <typename Variant, typename Char>
|
||||||
|
struct formatter<
|
||||||
|
Variant, Char,
|
||||||
|
std::enable_if_t<std::conjunction_v<
|
||||||
|
is_variant_like<Variant>, is_variant_formattable<Variant, Char>>>> {
|
||||||
|
template <typename ParseContext>
|
||||||
|
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
|
||||||
|
return ctx.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename FormatContext>
|
||||||
|
auto format(const Variant& value, FormatContext& ctx) const
|
||||||
|
-> decltype(ctx.out()) {
|
||||||
|
auto out = ctx.out();
|
||||||
|
|
||||||
|
out = detail::write<Char>(out, "variant(");
|
||||||
|
FMT_TRY {
|
||||||
|
std::visit(
|
||||||
|
[&](const auto& v) {
|
||||||
|
out = detail::write_variant_alternative<Char>(out, v);
|
||||||
|
},
|
||||||
|
value);
|
||||||
|
}
|
||||||
|
FMT_CATCH(const std::bad_variant_access&) {
|
||||||
|
detail::write<Char>(out, "valueless by exception");
|
||||||
|
}
|
||||||
|
*out++ = ')';
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
FMT_END_NAMESPACE
|
||||||
|
#endif // __cpp_lib_variant
|
||||||
|
|
||||||
|
FMT_BEGIN_NAMESPACE
|
||||||
|
FMT_EXPORT
|
||||||
|
template <typename Char> struct formatter<std::error_code, Char> {
|
||||||
|
template <typename ParseContext>
|
||||||
|
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
|
||||||
|
return ctx.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename FormatContext>
|
||||||
|
FMT_CONSTEXPR auto format(const std::error_code& ec, FormatContext& ctx) const
|
||||||
|
-> decltype(ctx.out()) {
|
||||||
|
auto out = ctx.out();
|
||||||
|
out = detail::write_bytes(out, ec.category().name(), format_specs<Char>());
|
||||||
|
out = detail::write<Char>(out, Char(':'));
|
||||||
|
out = detail::write<Char>(out, ec.value());
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
FMT_EXPORT
|
||||||
|
template <typename T, typename Char>
|
||||||
|
struct formatter<
|
||||||
|
T, Char,
|
||||||
|
typename std::enable_if<std::is_base_of<std::exception, T>::value>::type> {
|
||||||
|
private:
|
||||||
|
bool with_typename_ = false;
|
||||||
|
|
||||||
|
public:
|
||||||
|
FMT_CONSTEXPR auto parse(basic_format_parse_context<Char>& ctx)
|
||||||
|
-> decltype(ctx.begin()) {
|
||||||
|
auto it = ctx.begin();
|
||||||
|
auto end = ctx.end();
|
||||||
|
if (it == end || *it == '}') return it;
|
||||||
|
if (*it == 't') {
|
||||||
|
++it;
|
||||||
|
with_typename_ = FMT_USE_TYPEID != 0;
|
||||||
|
}
|
||||||
|
return it;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename OutputIt>
|
||||||
|
auto format(const std::exception& ex,
|
||||||
|
basic_format_context<OutputIt, Char>& ctx) const -> OutputIt {
|
||||||
|
format_specs<Char> spec;
|
||||||
|
auto out = ctx.out();
|
||||||
|
if (!with_typename_)
|
||||||
|
return detail::write_bytes(out, string_view(ex.what()), spec);
|
||||||
|
|
||||||
|
#if FMT_USE_TYPEID
|
||||||
|
const std::type_info& ti = typeid(ex);
|
||||||
|
# ifdef FMT_HAS_ABI_CXA_DEMANGLE
|
||||||
|
int status = 0;
|
||||||
|
std::size_t size = 0;
|
||||||
|
std::unique_ptr<char, decltype(&std::free)> demangled_name_ptr(
|
||||||
|
abi::__cxa_demangle(ti.name(), nullptr, &size, &status), &std::free);
|
||||||
|
|
||||||
|
string_view demangled_name_view;
|
||||||
|
if (demangled_name_ptr) {
|
||||||
|
demangled_name_view = demangled_name_ptr.get();
|
||||||
|
|
||||||
|
// Normalization of stdlib inline namespace names.
|
||||||
|
// libc++ inline namespaces.
|
||||||
|
// std::__1::* -> std::*
|
||||||
|
// std::__1::__fs::* -> std::*
|
||||||
|
// libstdc++ inline namespaces.
|
||||||
|
// std::__cxx11::* -> std::*
|
||||||
|
// std::filesystem::__cxx11::* -> std::filesystem::*
|
||||||
|
if (demangled_name_view.starts_with("std::")) {
|
||||||
|
char* begin = demangled_name_ptr.get();
|
||||||
|
char* to = begin + 5; // std::
|
||||||
|
for (char *from = to, *end = begin + demangled_name_view.size();
|
||||||
|
from < end;) {
|
||||||
|
// This is safe, because demangled_name is NUL-terminated.
|
||||||
|
if (from[0] == '_' && from[1] == '_') {
|
||||||
|
char* next = from + 1;
|
||||||
|
while (next < end && *next != ':') next++;
|
||||||
|
if (next[0] == ':' && next[1] == ':') {
|
||||||
|
from = next + 2;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*to++ = *from++;
|
||||||
|
}
|
||||||
|
demangled_name_view = {begin, detail::to_unsigned(to - begin)};
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
demangled_name_view = string_view(ti.name());
|
||||||
|
}
|
||||||
|
out = detail::write_bytes(out, demangled_name_view, spec);
|
||||||
|
# elif FMT_MSC_VERSION
|
||||||
|
string_view demangled_name_view(ti.name());
|
||||||
|
if (demangled_name_view.starts_with("class "))
|
||||||
|
demangled_name_view.remove_prefix(6);
|
||||||
|
else if (demangled_name_view.starts_with("struct "))
|
||||||
|
demangled_name_view.remove_prefix(7);
|
||||||
|
out = detail::write_bytes(out, demangled_name_view, spec);
|
||||||
|
# else
|
||||||
|
out = detail::write_bytes(out, string_view(ti.name()), spec);
|
||||||
|
# endif
|
||||||
|
*out++ = ':';
|
||||||
|
*out++ = ' ';
|
||||||
|
return detail::write_bytes(out, string_view(ex.what()), spec);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
template <typename T, typename Enable = void>
|
||||||
|
struct has_flip : std::false_type {};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct has_flip<T, void_t<decltype(std::declval<T>().flip())>>
|
||||||
|
: std::true_type {};
|
||||||
|
|
||||||
|
template <typename T> struct is_bit_reference_like {
|
||||||
|
static constexpr const bool value =
|
||||||
|
std::is_convertible<T, bool>::value &&
|
||||||
|
std::is_nothrow_assignable<T, bool>::value && has_flip<T>::value;
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef _LIBCPP_VERSION
|
||||||
|
|
||||||
|
// Workaround for libc++ incompatibility with C++ standard.
|
||||||
|
// According to the Standard, `bitset::operator[] const` returns bool.
|
||||||
|
template <typename C>
|
||||||
|
struct is_bit_reference_like<std::__bit_const_reference<C>> {
|
||||||
|
static constexpr const bool value = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
// We can't use std::vector<bool, Allocator>::reference and
|
||||||
|
// std::bitset<N>::reference because the compiler can't deduce Allocator and N
|
||||||
|
// in partial specialization.
|
||||||
|
FMT_EXPORT
|
||||||
|
template <typename BitRef, typename Char>
|
||||||
|
struct formatter<BitRef, Char,
|
||||||
|
enable_if_t<detail::is_bit_reference_like<BitRef>::value>>
|
||||||
|
: formatter<bool, Char> {
|
||||||
|
template <typename FormatContext>
|
||||||
|
FMT_CONSTEXPR auto format(const BitRef& v, FormatContext& ctx) const
|
||||||
|
-> decltype(ctx.out()) {
|
||||||
|
return formatter<bool, Char>::format(v, ctx);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
FMT_EXPORT
|
||||||
|
template <typename T, typename Char>
|
||||||
|
struct formatter<std::atomic<T>, Char,
|
||||||
|
enable_if_t<is_formattable<T, Char>::value>>
|
||||||
|
: formatter<T, Char> {
|
||||||
|
template <typename FormatContext>
|
||||||
|
auto format(const std::atomic<T>& v, FormatContext& ctx) const
|
||||||
|
-> decltype(ctx.out()) {
|
||||||
|
return formatter<T, Char>::format(v.load(), ctx);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef __cpp_lib_atomic_flag_test
|
||||||
|
FMT_EXPORT
|
||||||
|
template <typename Char>
|
||||||
|
struct formatter<std::atomic_flag, Char>
|
||||||
|
: formatter<bool, Char> {
|
||||||
|
template <typename FormatContext>
|
||||||
|
auto format(const std::atomic_flag& v, FormatContext& ctx) const
|
||||||
|
-> decltype(ctx.out()) {
|
||||||
|
return formatter<bool, Char>::format(v.test(), ctx);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#endif // __cpp_lib_atomic_flag_test
|
||||||
|
|
||||||
|
FMT_END_NAMESPACE
|
||||||
|
#endif // FMT_STD_H_
|
||||||
152
deps/fmt/include/fmt/xchar.h
vendored
152
deps/fmt/include/fmt/xchar.h
vendored
@@ -9,17 +9,35 @@
|
|||||||
#define FMT_XCHAR_H_
|
#define FMT_XCHAR_H_
|
||||||
|
|
||||||
#include <cwchar>
|
#include <cwchar>
|
||||||
#include <tuple>
|
|
||||||
|
|
||||||
#include "format.h"
|
#include "format.h"
|
||||||
|
|
||||||
|
#ifndef FMT_STATIC_THOUSANDS_SEPARATOR
|
||||||
|
# include <locale>
|
||||||
|
#endif
|
||||||
|
|
||||||
FMT_BEGIN_NAMESPACE
|
FMT_BEGIN_NAMESPACE
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
using is_exotic_char = bool_constant<!std::is_same<T, char>::value>;
|
using is_exotic_char = bool_constant<!std::is_same<T, char>::value>;
|
||||||
}
|
|
||||||
|
|
||||||
FMT_MODULE_EXPORT_BEGIN
|
inline auto write_loc(std::back_insert_iterator<detail::buffer<wchar_t>> out,
|
||||||
|
loc_value value, const format_specs<wchar_t>& specs,
|
||||||
|
locale_ref loc) -> bool {
|
||||||
|
#ifndef FMT_STATIC_THOUSANDS_SEPARATOR
|
||||||
|
auto& numpunct =
|
||||||
|
std::use_facet<std::numpunct<wchar_t>>(loc.get<std::locale>());
|
||||||
|
auto separator = std::wstring();
|
||||||
|
auto grouping = numpunct.grouping();
|
||||||
|
if (!grouping.empty()) separator = std::wstring(1, numpunct.thousands_sep());
|
||||||
|
return value.visit(loc_writer<wchar_t>{out, specs, separator, grouping, {}});
|
||||||
|
#endif
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
FMT_BEGIN_EXPORT
|
||||||
|
|
||||||
using wstring_view = basic_string_view<wchar_t>;
|
using wstring_view = basic_string_view<wchar_t>;
|
||||||
using wformat_parse_context = basic_format_parse_context<wchar_t>;
|
using wformat_parse_context = basic_format_parse_context<wchar_t>;
|
||||||
@@ -30,9 +48,13 @@ using wmemory_buffer = basic_memory_buffer<wchar_t>;
|
|||||||
#if FMT_GCC_VERSION && FMT_GCC_VERSION < 409
|
#if FMT_GCC_VERSION && FMT_GCC_VERSION < 409
|
||||||
// Workaround broken conversion on older gcc.
|
// Workaround broken conversion on older gcc.
|
||||||
template <typename... Args> using wformat_string = wstring_view;
|
template <typename... Args> using wformat_string = wstring_view;
|
||||||
|
inline auto runtime(wstring_view s) -> wstring_view { return s; }
|
||||||
#else
|
#else
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
using wformat_string = basic_format_string<wchar_t, type_identity_t<Args>...>;
|
using wformat_string = basic_format_string<wchar_t, type_identity_t<Args>...>;
|
||||||
|
inline auto runtime(wstring_view s) -> runtime_format_string<wchar_t> {
|
||||||
|
return {{s}};
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
template <> struct is_char<wchar_t> : std::true_type {};
|
template <> struct is_char<wchar_t> : std::true_type {};
|
||||||
@@ -40,19 +62,14 @@ template <> struct is_char<detail::char8_type> : std::true_type {};
|
|||||||
template <> struct is_char<char16_t> : std::true_type {};
|
template <> struct is_char<char16_t> : std::true_type {};
|
||||||
template <> struct is_char<char32_t> : std::true_type {};
|
template <> struct is_char<char32_t> : std::true_type {};
|
||||||
|
|
||||||
template <typename... Args>
|
template <typename... T>
|
||||||
constexpr format_arg_store<wformat_context, Args...> make_wformat_args(
|
constexpr format_arg_store<wformat_context, T...> make_wformat_args(
|
||||||
const Args&... args) {
|
const T&... args) {
|
||||||
return {args...};
|
return {args...};
|
||||||
}
|
}
|
||||||
|
|
||||||
inline namespace literals {
|
inline namespace literals {
|
||||||
constexpr auto operator"" _format(const wchar_t* s, size_t n)
|
#if FMT_USE_USER_DEFINED_LITERALS && !FMT_USE_NONTYPE_TEMPLATE_ARGS
|
||||||
-> 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) {
|
constexpr detail::udl_arg<wchar_t> operator"" _a(const wchar_t* s, size_t) {
|
||||||
return {s};
|
return {s};
|
||||||
}
|
}
|
||||||
@@ -82,18 +99,24 @@ template <typename Char, FMT_ENABLE_IF(!std::is_same<Char, char>::value)>
|
|||||||
auto vformat(basic_string_view<Char> format_str,
|
auto vformat(basic_string_view<Char> format_str,
|
||||||
basic_format_args<buffer_context<type_identity_t<Char>>> args)
|
basic_format_args<buffer_context<type_identity_t<Char>>> args)
|
||||||
-> std::basic_string<Char> {
|
-> std::basic_string<Char> {
|
||||||
basic_memory_buffer<Char> buffer;
|
auto buf = basic_memory_buffer<Char>();
|
||||||
detail::vformat_to(buffer, format_str, args);
|
detail::vformat_to(buf, format_str, args);
|
||||||
return to_string(buffer);
|
return to_string(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename... T>
|
||||||
|
auto format(wformat_string<T...> fmt, T&&... args) -> std::wstring {
|
||||||
|
return vformat(fmt::wstring_view(fmt), fmt::make_wformat_args(args...));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pass char_t as a default template parameter instead of using
|
// Pass char_t as a default template parameter instead of using
|
||||||
// std::basic_string<char_t<S>> to reduce the symbol size.
|
// std::basic_string<char_t<S>> to reduce the symbol size.
|
||||||
template <typename S, typename... Args, typename Char = char_t<S>,
|
template <typename S, typename... T, typename Char = char_t<S>,
|
||||||
FMT_ENABLE_IF(!std::is_same<Char, char>::value)>
|
FMT_ENABLE_IF(!std::is_same<Char, char>::value &&
|
||||||
auto format(const S& format_str, Args&&... args) -> std::basic_string<Char> {
|
!std::is_same<Char, wchar_t>::value)>
|
||||||
const auto& vargs = fmt::make_args_checked<Args...>(format_str, args...);
|
auto format(const S& format_str, T&&... args) -> std::basic_string<Char> {
|
||||||
return vformat(to_string_view(format_str), vargs);
|
return vformat(detail::to_string_view(format_str),
|
||||||
|
fmt::make_format_args<buffer_context<Char>>(args...));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Locale, typename S, typename Char = char_t<S>,
|
template <typename Locale, typename S, typename Char = char_t<S>,
|
||||||
@@ -103,17 +126,16 @@ inline auto vformat(
|
|||||||
const Locale& loc, const S& format_str,
|
const Locale& loc, const S& format_str,
|
||||||
basic_format_args<buffer_context<type_identity_t<Char>>> args)
|
basic_format_args<buffer_context<type_identity_t<Char>>> args)
|
||||||
-> std::basic_string<Char> {
|
-> std::basic_string<Char> {
|
||||||
return detail::vformat(loc, to_string_view(format_str), args);
|
return detail::vformat(loc, detail::to_string_view(format_str), args);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Locale, typename S, typename... Args,
|
template <typename Locale, typename S, typename... T, typename Char = char_t<S>,
|
||||||
typename Char = char_t<S>,
|
|
||||||
FMT_ENABLE_IF(detail::is_locale<Locale>::value&&
|
FMT_ENABLE_IF(detail::is_locale<Locale>::value&&
|
||||||
detail::is_exotic_char<Char>::value)>
|
detail::is_exotic_char<Char>::value)>
|
||||||
inline auto format(const Locale& loc, const S& format_str, Args&&... args)
|
inline auto format(const Locale& loc, const S& format_str, T&&... args)
|
||||||
-> std::basic_string<Char> {
|
-> std::basic_string<Char> {
|
||||||
return detail::vformat(loc, to_string_view(format_str),
|
return detail::vformat(loc, detail::to_string_view(format_str),
|
||||||
fmt::make_args_checked<Args...>(format_str, args...));
|
fmt::make_format_args<buffer_context<Char>>(args...));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename OutputIt, typename S, typename Char = char_t<S>,
|
template <typename OutputIt, typename S, typename Char = char_t<S>,
|
||||||
@@ -123,27 +145,17 @@ auto vformat_to(OutputIt out, const S& format_str,
|
|||||||
basic_format_args<buffer_context<type_identity_t<Char>>> args)
|
basic_format_args<buffer_context<type_identity_t<Char>>> args)
|
||||||
-> OutputIt {
|
-> OutputIt {
|
||||||
auto&& buf = detail::get_buffer<Char>(out);
|
auto&& buf = detail::get_buffer<Char>(out);
|
||||||
detail::vformat_to(buf, to_string_view(format_str), args);
|
detail::vformat_to(buf, detail::to_string_view(format_str), args);
|
||||||
return detail::get_iterator(buf);
|
return detail::get_iterator(buf, out);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename OutputIt, typename S, typename... Args,
|
template <typename OutputIt, typename S, typename... T,
|
||||||
typename Char = char_t<S>,
|
typename Char = char_t<S>,
|
||||||
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value&&
|
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value&&
|
||||||
detail::is_exotic_char<Char>::value)>
|
detail::is_exotic_char<Char>::value)>
|
||||||
inline auto format_to(OutputIt out, const S& fmt, Args&&... args) -> OutputIt {
|
inline auto format_to(OutputIt out, const S& fmt, T&&... args) -> OutputIt {
|
||||||
const auto& vargs = fmt::make_args_checked<Args...>(fmt, args...);
|
return vformat_to(out, detail::to_string_view(fmt),
|
||||||
return vformat_to(out, to_string_view(fmt), vargs);
|
fmt::make_format_args<buffer_context<Char>>(args...));
|
||||||
}
|
|
||||||
|
|
||||||
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,
|
template <typename Locale, typename S, typename OutputIt, typename... Args,
|
||||||
@@ -155,20 +167,21 @@ inline auto vformat_to(
|
|||||||
OutputIt out, const Locale& loc, const S& format_str,
|
OutputIt out, const Locale& loc, const S& format_str,
|
||||||
basic_format_args<buffer_context<type_identity_t<Char>>> args) -> OutputIt {
|
basic_format_args<buffer_context<type_identity_t<Char>>> args) -> OutputIt {
|
||||||
auto&& buf = detail::get_buffer<Char>(out);
|
auto&& buf = detail::get_buffer<Char>(out);
|
||||||
vformat_to(buf, to_string_view(format_str), args, detail::locale_ref(loc));
|
vformat_to(buf, detail::to_string_view(format_str), args,
|
||||||
return detail::get_iterator(buf);
|
detail::locale_ref(loc));
|
||||||
|
return detail::get_iterator(buf, out);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <
|
template <
|
||||||
typename OutputIt, typename Locale, typename S, typename... Args,
|
typename OutputIt, typename Locale, typename S, typename... T,
|
||||||
typename Char = char_t<S>,
|
typename Char = char_t<S>,
|
||||||
bool enable = detail::is_output_iterator<OutputIt, Char>::value&&
|
bool enable = detail::is_output_iterator<OutputIt, Char>::value&&
|
||||||
detail::is_locale<Locale>::value&& detail::is_exotic_char<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,
|
inline auto format_to(OutputIt out, const Locale& loc, const S& format_str,
|
||||||
Args&&... args) ->
|
T&&... args) ->
|
||||||
typename std::enable_if<enable, OutputIt>::type {
|
typename std::enable_if<enable, OutputIt>::type {
|
||||||
const auto& vargs = fmt::make_args_checked<Args...>(format_str, args...);
|
return vformat_to(out, loc, detail::to_string_view(format_str),
|
||||||
return vformat_to(out, loc, to_string_view(format_str), vargs);
|
fmt::make_format_args<buffer_context<Char>>(args...));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename OutputIt, typename Char, typename... Args,
|
template <typename OutputIt, typename Char, typename... Args,
|
||||||
@@ -178,36 +191,36 @@ inline auto vformat_to_n(
|
|||||||
OutputIt out, size_t n, basic_string_view<Char> format_str,
|
OutputIt out, size_t n, basic_string_view<Char> format_str,
|
||||||
basic_format_args<buffer_context<type_identity_t<Char>>> args)
|
basic_format_args<buffer_context<type_identity_t<Char>>> args)
|
||||||
-> format_to_n_result<OutputIt> {
|
-> format_to_n_result<OutputIt> {
|
||||||
detail::iterator_buffer<OutputIt, Char, detail::fixed_buffer_traits> buf(out,
|
using traits = detail::fixed_buffer_traits;
|
||||||
n);
|
auto buf = detail::iterator_buffer<OutputIt, Char, traits>(out, n);
|
||||||
detail::vformat_to(buf, format_str, args);
|
detail::vformat_to(buf, format_str, args);
|
||||||
return {buf.out(), buf.count()};
|
return {buf.out(), buf.count()};
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename OutputIt, typename S, typename... Args,
|
template <typename OutputIt, typename S, typename... T,
|
||||||
typename Char = char_t<S>,
|
typename Char = char_t<S>,
|
||||||
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value&&
|
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value&&
|
||||||
detail::is_exotic_char<Char>::value)>
|
detail::is_exotic_char<Char>::value)>
|
||||||
inline auto format_to_n(OutputIt out, size_t n, const S& fmt,
|
inline auto format_to_n(OutputIt out, size_t n, const S& fmt, T&&... args)
|
||||||
const Args&... args) -> format_to_n_result<OutputIt> {
|
-> format_to_n_result<OutputIt> {
|
||||||
const auto& vargs = fmt::make_args_checked<Args...>(fmt, args...);
|
return vformat_to_n(out, n, detail::to_string_view(fmt),
|
||||||
return vformat_to_n(out, n, to_string_view(fmt), vargs);
|
fmt::make_format_args<buffer_context<Char>>(args...));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename S, typename... Args, typename Char = char_t<S>,
|
template <typename S, typename... T, typename Char = char_t<S>,
|
||||||
FMT_ENABLE_IF(detail::is_exotic_char<Char>::value)>
|
FMT_ENABLE_IF(detail::is_exotic_char<Char>::value)>
|
||||||
inline auto formatted_size(const S& fmt, Args&&... args) -> size_t {
|
inline auto formatted_size(const S& fmt, T&&... args) -> size_t {
|
||||||
detail::counting_buffer<Char> buf;
|
auto buf = detail::counting_buffer<Char>();
|
||||||
const auto& vargs = fmt::make_args_checked<Args...>(fmt, args...);
|
detail::vformat_to(buf, detail::to_string_view(fmt),
|
||||||
detail::vformat_to(buf, to_string_view(fmt), vargs);
|
fmt::make_format_args<buffer_context<Char>>(args...));
|
||||||
return buf.count();
|
return buf.count();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void vprint(std::FILE* f, wstring_view fmt, wformat_args args) {
|
inline void vprint(std::FILE* f, wstring_view fmt, wformat_args args) {
|
||||||
wmemory_buffer buffer;
|
auto buf = wmemory_buffer();
|
||||||
detail::vformat_to(buffer, fmt, args);
|
detail::vformat_to(buf, fmt, args);
|
||||||
buffer.push_back(L'\0');
|
buf.push_back(L'\0');
|
||||||
if (std::fputws(buffer.data(), f) == -1)
|
if (std::fputws(buf.data(), f) == -1)
|
||||||
FMT_THROW(system_error(errno, FMT_STRING("cannot write to file")));
|
FMT_THROW(system_error(errno, FMT_STRING("cannot write to file")));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -224,13 +237,22 @@ template <typename... T> void print(wformat_string<T...> fmt, T&&... args) {
|
|||||||
return vprint(wstring_view(fmt), fmt::make_wformat_args(args...));
|
return vprint(wstring_view(fmt), fmt::make_wformat_args(args...));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename... T>
|
||||||
|
void println(std::FILE* f, wformat_string<T...> fmt, T&&... args) {
|
||||||
|
return print(f, L"{}\n", fmt::format(fmt, std::forward<T>(args)...));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename... T> void println(wformat_string<T...> fmt, T&&... args) {
|
||||||
|
return print(L"{}\n", fmt::format(fmt, std::forward<T>(args)...));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Converts *value* to ``std::wstring`` using the default format for type *T*.
|
Converts *value* to ``std::wstring`` using the default format for type *T*.
|
||||||
*/
|
*/
|
||||||
template <typename T> inline auto to_wstring(const T& value) -> std::wstring {
|
template <typename T> inline auto to_wstring(const T& value) -> std::wstring {
|
||||||
return format(FMT_STRING(L"{}"), value);
|
return format(FMT_STRING(L"{}"), value);
|
||||||
}
|
}
|
||||||
FMT_MODULE_EXPORT_END
|
FMT_END_EXPORT
|
||||||
FMT_END_NAMESPACE
|
FMT_END_NAMESPACE
|
||||||
|
|
||||||
#endif // FMT_XCHAR_H_
|
#endif // FMT_XCHAR_H_
|
||||||
|
|||||||
69
deps/fmt/src/fmt.cc
vendored
69
deps/fmt/src/fmt.cc
vendored
@@ -1,49 +1,44 @@
|
|||||||
module;
|
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)
|
|
||||||
# define _CRT_SECURE_NO_WARNINGS
|
|
||||||
#endif
|
|
||||||
#if !defined(WIN32_LEAN_AND_MEAN) && defined(_WIN32)
|
|
||||||
# define WIN32_LEAN_AND_MEAN
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
// Put all implementation-provided headers into the global module fragment
|
||||||
|
// to prevent attachment to this module.
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cctype>
|
|
||||||
#include <cerrno>
|
#include <cerrno>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <climits>
|
#include <climits>
|
||||||
#include <clocale>
|
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <cstdarg>
|
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <ctime>
|
#include <ctime>
|
||||||
#include <cwchar>
|
|
||||||
#include <exception>
|
#include <exception>
|
||||||
|
#include <filesystem>
|
||||||
|
#include <fstream>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
#include <locale>
|
#include <locale>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <optional>
|
||||||
#include <ostream>
|
#include <ostream>
|
||||||
#include <sstream>
|
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
#include <system_error>
|
#include <system_error>
|
||||||
|
#include <thread>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
#include <typeinfo>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
#include <variant>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <version>
|
||||||
|
|
||||||
#if _MSC_VER
|
#if __has_include(<cxxabi.h>)
|
||||||
|
# include <cxxabi.h>
|
||||||
|
#endif
|
||||||
|
#if defined(_MSC_VER) || defined(__MINGW32__)
|
||||||
# include <intrin.h>
|
# include <intrin.h>
|
||||||
#endif
|
#endif
|
||||||
#if defined __APPLE__ || defined(__FreeBSD__)
|
#if defined __APPLE__ || defined(__FreeBSD__)
|
||||||
@@ -65,22 +60,33 @@ module;
|
|||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
|
# if defined(__GLIBCXX__)
|
||||||
|
# include <ext/stdio_filebuf.h>
|
||||||
|
# include <ext/stdio_sync_filebuf.h>
|
||||||
|
# elif defined(_LIBCPP_VERSION)
|
||||||
|
# include <__std_stream>
|
||||||
|
# endif
|
||||||
|
# define WIN32_LEAN_AND_MEAN
|
||||||
# include <windows.h>
|
# include <windows.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
export module fmt;
|
export module fmt;
|
||||||
|
|
||||||
#define FMT_MODULE_EXPORT export
|
#define FMT_EXPORT export
|
||||||
#define FMT_MODULE_EXPORT_BEGIN export {
|
#define FMT_BEGIN_EXPORT export {
|
||||||
#define FMT_MODULE_EXPORT_END }
|
#define FMT_END_EXPORT }
|
||||||
#define FMT_BEGIN_DETAIL_NAMESPACE \
|
|
||||||
} \
|
// If you define FMT_ATTACH_TO_GLOBAL_MODULE
|
||||||
namespace detail {
|
// - all declarations are detached from module 'fmt'
|
||||||
#define FMT_END_DETAIL_NAMESPACE \
|
// - the module behaves like a traditional static library, too
|
||||||
} \
|
// - all library symbols are mangled traditionally
|
||||||
export {
|
// - you can mix TUs with either importing or #including the {fmt} API
|
||||||
// all library-provided declarations and definitions
|
#ifdef FMT_ATTACH_TO_GLOBAL_MODULE
|
||||||
// must be in the module purview to be exported
|
extern "C++" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// All library-provided declarations and definitions must be in the module
|
||||||
|
// purview to be exported.
|
||||||
#include "fmt/args.h"
|
#include "fmt/args.h"
|
||||||
#include "fmt/chrono.h"
|
#include "fmt/chrono.h"
|
||||||
#include "fmt/color.h"
|
#include "fmt/color.h"
|
||||||
@@ -88,8 +94,13 @@ export module fmt;
|
|||||||
#include "fmt/format.h"
|
#include "fmt/format.h"
|
||||||
#include "fmt/os.h"
|
#include "fmt/os.h"
|
||||||
#include "fmt/printf.h"
|
#include "fmt/printf.h"
|
||||||
|
#include "fmt/std.h"
|
||||||
#include "fmt/xchar.h"
|
#include "fmt/xchar.h"
|
||||||
|
|
||||||
|
#ifdef FMT_ATTACH_TO_GLOBAL_MODULE
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// gcc doesn't yet implement private module fragments
|
// gcc doesn't yet implement private module fragments
|
||||||
#if !FMT_GCC_VERSION
|
#if !FMT_GCC_VERSION
|
||||||
module : private;
|
module : private;
|
||||||
|
|||||||
111
deps/fmt/src/format.cc
vendored
111
deps/fmt/src/format.cc
vendored
@@ -10,115 +10,34 @@
|
|||||||
FMT_BEGIN_NAMESPACE
|
FMT_BEGIN_NAMESPACE
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
|
||||||
// DEPRECATED!
|
template FMT_API auto dragonbox::to_decimal(float x) noexcept
|
||||||
template <typename T = void> struct basic_data {
|
-> dragonbox::decimal_fp<float>;
|
||||||
FMT_API static constexpr const char digits[100][2] = {
|
template FMT_API auto dragonbox::to_decimal(double x) noexcept
|
||||||
{'0', '0'}, {'0', '1'}, {'0', '2'}, {'0', '3'}, {'0', '4'}, {'0', '5'},
|
-> dragonbox::decimal_fp<double>;
|
||||||
{'0', '6'}, {'0', '7'}, {'0', '8'}, {'0', '9'}, {'1', '0'}, {'1', '1'},
|
|
||||||
{'1', '2'}, {'1', '3'}, {'1', '4'}, {'1', '5'}, {'1', '6'}, {'1', '7'},
|
|
||||||
{'1', '8'}, {'1', '9'}, {'2', '0'}, {'2', '1'}, {'2', '2'}, {'2', '3'},
|
|
||||||
{'2', '4'}, {'2', '5'}, {'2', '6'}, {'2', '7'}, {'2', '8'}, {'2', '9'},
|
|
||||||
{'3', '0'}, {'3', '1'}, {'3', '2'}, {'3', '3'}, {'3', '4'}, {'3', '5'},
|
|
||||||
{'3', '6'}, {'3', '7'}, {'3', '8'}, {'3', '9'}, {'4', '0'}, {'4', '1'},
|
|
||||||
{'4', '2'}, {'4', '3'}, {'4', '4'}, {'4', '5'}, {'4', '6'}, {'4', '7'},
|
|
||||||
{'4', '8'}, {'4', '9'}, {'5', '0'}, {'5', '1'}, {'5', '2'}, {'5', '3'},
|
|
||||||
{'5', '4'}, {'5', '5'}, {'5', '6'}, {'5', '7'}, {'5', '8'}, {'5', '9'},
|
|
||||||
{'6', '0'}, {'6', '1'}, {'6', '2'}, {'6', '3'}, {'6', '4'}, {'6', '5'},
|
|
||||||
{'6', '6'}, {'6', '7'}, {'6', '8'}, {'6', '9'}, {'7', '0'}, {'7', '1'},
|
|
||||||
{'7', '2'}, {'7', '3'}, {'7', '4'}, {'7', '5'}, {'7', '6'}, {'7', '7'},
|
|
||||||
{'7', '8'}, {'7', '9'}, {'8', '0'}, {'8', '1'}, {'8', '2'}, {'8', '3'},
|
|
||||||
{'8', '4'}, {'8', '5'}, {'8', '6'}, {'8', '7'}, {'8', '8'}, {'8', '9'},
|
|
||||||
{'9', '0'}, {'9', '1'}, {'9', '2'}, {'9', '3'}, {'9', '4'}, {'9', '5'},
|
|
||||||
{'9', '6'}, {'9', '7'}, {'9', '8'}, {'9', '9'}};
|
|
||||||
FMT_API static constexpr const char hex_digits[] = "0123456789abcdef";
|
|
||||||
FMT_API static constexpr const char signs[4] = {0, '-', '+', ' '};
|
|
||||||
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};
|
|
||||||
FMT_API static constexpr const unsigned prefixes[4] = {0, 0, 0x1000000u | '+',
|
|
||||||
0x1000000u | ' '};
|
|
||||||
};
|
|
||||||
|
|
||||||
#ifdef FMT_SHARED
|
|
||||||
// Required for -flto, -fivisibility=hidden and -shared to work
|
|
||||||
extern template struct basic_data<void>;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if __cplusplus < 201703L
|
|
||||||
// DEPRECATED! These are here only for ABI compatiblity.
|
|
||||||
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 char basic_data<T>::left_padding_shifts[];
|
|
||||||
template <typename T>
|
|
||||||
constexpr const char basic_data<T>::right_padding_shifts[];
|
|
||||||
template <typename T> constexpr const unsigned basic_data<T>::prefixes[];
|
|
||||||
#endif
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
int format_float(char* buf, std::size_t size, const char* format, int precision,
|
|
||||||
T value) {
|
|
||||||
#ifdef FMT_FUZZ
|
|
||||||
if (precision > 100000)
|
|
||||||
throw std::runtime_error(
|
|
||||||
"fuzz mode - avoid large allocation inside snprintf");
|
|
||||||
#endif
|
|
||||||
// Suppress the warning about nonliteral format string.
|
|
||||||
int (*snprintf_ptr)(char*, size_t, const char*, ...) = FMT_SNPRINTF;
|
|
||||||
return precision < 0 ? snprintf_ptr(buf, size, format, value)
|
|
||||||
: snprintf_ptr(buf, size, format, precision, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
} // namespace detail
|
|
||||||
|
|
||||||
// Workaround a bug in MSVC2013 that prevents instantiation of format_float.
|
|
||||||
int (*instantiate_format_float)(double, int, detail::float_specs,
|
|
||||||
detail::buffer<char>&) = detail::format_float;
|
|
||||||
|
|
||||||
#ifndef FMT_STATIC_THOUSANDS_SEPARATOR
|
#ifndef FMT_STATIC_THOUSANDS_SEPARATOR
|
||||||
template FMT_API detail::locale_ref::locale_ref(const std::locale& loc);
|
template FMT_API locale_ref::locale_ref(const std::locale& loc);
|
||||||
template FMT_API std::locale detail::locale_ref::get<std::locale>() const;
|
template FMT_API auto locale_ref::get<std::locale>() const -> std::locale;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Explicit instantiations for char.
|
// Explicit instantiations for char.
|
||||||
|
|
||||||
template FMT_API auto detail::thousands_sep_impl(locale_ref)
|
template FMT_API auto thousands_sep_impl(locale_ref)
|
||||||
-> thousands_sep_result<char>;
|
-> thousands_sep_result<char>;
|
||||||
template FMT_API char detail::decimal_point_impl(locale_ref);
|
template FMT_API auto decimal_point_impl(locale_ref) -> char;
|
||||||
|
|
||||||
template FMT_API void detail::buffer<char>::append(const char*, const char*);
|
template FMT_API void buffer<char>::append(const char*, const char*);
|
||||||
|
|
||||||
// DEPRECATED!
|
template FMT_API void vformat_to(buffer<char>&, string_view,
|
||||||
// There is no correspondent extern template in format.h because of
|
typename vformat_args<>::type, locale_ref);
|
||||||
// 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);
|
|
||||||
|
|
||||||
template FMT_API int detail::snprintf_float(double, int, detail::float_specs,
|
|
||||||
detail::buffer<char>&);
|
|
||||||
template FMT_API int detail::snprintf_float(long double, int,
|
|
||||||
detail::float_specs,
|
|
||||||
detail::buffer<char>&);
|
|
||||||
template FMT_API int detail::format_float(double, int, detail::float_specs,
|
|
||||||
detail::buffer<char>&);
|
|
||||||
template FMT_API int detail::format_float(long double, int, detail::float_specs,
|
|
||||||
detail::buffer<char>&);
|
|
||||||
|
|
||||||
// Explicit instantiations for wchar_t.
|
// Explicit instantiations for wchar_t.
|
||||||
|
|
||||||
template FMT_API auto detail::thousands_sep_impl(locale_ref)
|
template FMT_API auto thousands_sep_impl(locale_ref)
|
||||||
-> thousands_sep_result<wchar_t>;
|
-> thousands_sep_result<wchar_t>;
|
||||||
template FMT_API wchar_t detail::decimal_point_impl(locale_ref);
|
template FMT_API auto decimal_point_impl(locale_ref) -> wchar_t;
|
||||||
|
|
||||||
template FMT_API void detail::buffer<wchar_t>::append(const wchar_t*,
|
template FMT_API void buffer<wchar_t>::append(const wchar_t*, const wchar_t*);
|
||||||
const wchar_t*);
|
|
||||||
|
|
||||||
template struct detail::basic_data<void>;
|
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
FMT_END_NAMESPACE
|
FMT_END_NAMESPACE
|
||||||
|
|||||||
201
deps/fmt/src/os.cc
vendored
201
deps/fmt/src/os.cc
vendored
@@ -18,6 +18,10 @@
|
|||||||
# include <sys/stat.h>
|
# include <sys/stat.h>
|
||||||
# include <sys/types.h>
|
# include <sys/types.h>
|
||||||
|
|
||||||
|
# ifdef _WRS_KERNEL // VxWorks7 kernel
|
||||||
|
# include <ioLib.h> // getpagesize
|
||||||
|
# endif
|
||||||
|
|
||||||
# ifndef _WIN32
|
# ifndef _WIN32
|
||||||
# include <unistd.h>
|
# include <unistd.h>
|
||||||
# else
|
# else
|
||||||
@@ -35,9 +39,15 @@
|
|||||||
# ifndef S_IRGRP
|
# ifndef S_IRGRP
|
||||||
# define S_IRGRP 0
|
# define S_IRGRP 0
|
||||||
# endif
|
# endif
|
||||||
|
# ifndef S_IWGRP
|
||||||
|
# define S_IWGRP 0
|
||||||
|
# endif
|
||||||
# ifndef S_IROTH
|
# ifndef S_IROTH
|
||||||
# define S_IROTH 0
|
# define S_IROTH 0
|
||||||
# endif
|
# endif
|
||||||
|
# ifndef S_IWOTH
|
||||||
|
# define S_IWOTH 0
|
||||||
|
# endif
|
||||||
# endif // _WIN32
|
# endif // _WIN32
|
||||||
#endif // FMT_USE_FCNTL
|
#endif // FMT_USE_FCNTL
|
||||||
|
|
||||||
@@ -45,10 +55,6 @@
|
|||||||
# include <windows.h>
|
# include <windows.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef fileno
|
|
||||||
# undef fileno
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
// Return type of read and write functions.
|
// Return type of read and write functions.
|
||||||
@@ -70,34 +76,6 @@ inline std::size_t convert_rwcount(std::size_t count) { return count; }
|
|||||||
FMT_BEGIN_NAMESPACE
|
FMT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
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(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) {
|
|
||||||
// WideCharToMultiByte does not support zero length, handle separately.
|
|
||||||
buffer_.resize(1);
|
|
||||||
buffer_[0] = 0;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int length = WideCharToMultiByte(CP_UTF8, 0, s.data(), s_size, nullptr, 0,
|
|
||||||
nullptr, nullptr);
|
|
||||||
if (length == 0) return GetLastError();
|
|
||||||
buffer_.resize(length + 1);
|
|
||||||
length = WideCharToMultiByte(CP_UTF8, 0, s.data(), s_size, &buffer_[0],
|
|
||||||
length, nullptr, nullptr);
|
|
||||||
if (length == 0) return GetLastError();
|
|
||||||
buffer_[length] = 0;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
|
||||||
class system_message {
|
class system_message {
|
||||||
@@ -107,7 +85,7 @@ class system_message {
|
|||||||
unsigned long result_;
|
unsigned long result_;
|
||||||
wchar_t* message_;
|
wchar_t* message_;
|
||||||
|
|
||||||
static bool is_whitespace(wchar_t c) FMT_NOEXCEPT {
|
static bool is_whitespace(wchar_t c) noexcept {
|
||||||
return c == L' ' || c == L'\n' || c == L'\r' || c == L'\t' || c == L'\0';
|
return c == L' ' || c == L'\n' || c == L'\r' || c == L'\t' || c == L'\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -126,20 +104,20 @@ class system_message {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
~system_message() { LocalFree(message_); }
|
~system_message() { LocalFree(message_); }
|
||||||
explicit operator bool() const FMT_NOEXCEPT { return result_ != 0; }
|
explicit operator bool() const noexcept { return result_ != 0; }
|
||||||
operator basic_string_view<wchar_t>() const FMT_NOEXCEPT {
|
operator basic_string_view<wchar_t>() const noexcept {
|
||||||
return basic_string_view<wchar_t>(message_, result_);
|
return basic_string_view<wchar_t>(message_, result_);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class utf8_system_category final : public std::error_category {
|
class utf8_system_category final : public std::error_category {
|
||||||
public:
|
public:
|
||||||
const char* name() const FMT_NOEXCEPT override { return "system"; }
|
const char* name() const noexcept override { return "system"; }
|
||||||
std::string message(int error_code) const override {
|
std::string message(int error_code) const override {
|
||||||
system_message msg(error_code);
|
auto&& msg = system_message(error_code);
|
||||||
if (msg) {
|
if (msg) {
|
||||||
utf16_to_utf8 utf8_message;
|
auto utf8_message = to_utf8<wchar_t>();
|
||||||
if (utf8_message.convert(msg) == ERROR_SUCCESS) {
|
if (utf8_message.convert(msg)) {
|
||||||
return utf8_message.str();
|
return utf8_message.str();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -149,7 +127,7 @@ class utf8_system_category final : public std::error_category {
|
|||||||
|
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
|
|
||||||
FMT_API const std::error_category& system_category() FMT_NOEXCEPT {
|
FMT_API const std::error_category& system_category() noexcept {
|
||||||
static const detail::utf8_system_category category;
|
static const detail::utf8_system_category category;
|
||||||
return category;
|
return category;
|
||||||
}
|
}
|
||||||
@@ -161,13 +139,14 @@ std::system_error vwindows_error(int err_code, string_view format_str,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void detail::format_windows_error(detail::buffer<char>& out, int error_code,
|
void detail::format_windows_error(detail::buffer<char>& out, int error_code,
|
||||||
const char* message) FMT_NOEXCEPT {
|
const char* message) noexcept {
|
||||||
FMT_TRY {
|
FMT_TRY {
|
||||||
system_message msg(error_code);
|
auto&& msg = system_message(error_code);
|
||||||
if (msg) {
|
if (msg) {
|
||||||
utf16_to_utf8 utf8_message;
|
auto utf8_message = to_utf8<wchar_t>();
|
||||||
if (utf8_message.convert(msg) == ERROR_SUCCESS) {
|
if (utf8_message.convert(msg)) {
|
||||||
format_to(buffer_appender<char>(out), "{}: {}", message, utf8_message);
|
fmt::format_to(appender(out), FMT_STRING("{}: {}"), message,
|
||||||
|
string_view(utf8_message));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -176,12 +155,12 @@ void detail::format_windows_error(detail::buffer<char>& out, int error_code,
|
|||||||
format_error_code(out, error_code, message);
|
format_error_code(out, error_code, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
void report_windows_error(int error_code, const char* message) FMT_NOEXCEPT {
|
void report_windows_error(int error_code, const char* message) noexcept {
|
||||||
report_error(detail::format_windows_error, error_code, message);
|
report_error(detail::format_windows_error, error_code, message);
|
||||||
}
|
}
|
||||||
#endif // _WIN32
|
#endif // _WIN32
|
||||||
|
|
||||||
buffered_file::~buffered_file() FMT_NOEXCEPT {
|
buffered_file::~buffered_file() noexcept {
|
||||||
if (file_ && FMT_SYSTEM(fclose(file_)) != 0)
|
if (file_ && FMT_SYSTEM(fclose(file_)) != 0)
|
||||||
report_system_error(errno, "cannot close file");
|
report_system_error(errno, "cannot close file");
|
||||||
}
|
}
|
||||||
@@ -190,42 +169,50 @@ buffered_file::buffered_file(cstring_view filename, cstring_view mode) {
|
|||||||
FMT_RETRY_VAL(file_, FMT_SYSTEM(fopen(filename.c_str(), mode.c_str())),
|
FMT_RETRY_VAL(file_, FMT_SYSTEM(fopen(filename.c_str(), mode.c_str())),
|
||||||
nullptr);
|
nullptr);
|
||||||
if (!file_)
|
if (!file_)
|
||||||
FMT_THROW(system_error(errno, "cannot open file {}", filename.c_str()));
|
FMT_THROW(system_error(errno, FMT_STRING("cannot open file {}"),
|
||||||
|
filename.c_str()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void buffered_file::close() {
|
void buffered_file::close() {
|
||||||
if (!file_) return;
|
if (!file_) return;
|
||||||
int result = FMT_SYSTEM(fclose(file_));
|
int result = FMT_SYSTEM(fclose(file_));
|
||||||
file_ = nullptr;
|
file_ = nullptr;
|
||||||
if (result != 0) FMT_THROW(system_error(errno, "cannot close file"));
|
if (result != 0)
|
||||||
|
FMT_THROW(system_error(errno, FMT_STRING("cannot close file")));
|
||||||
}
|
}
|
||||||
|
|
||||||
// A macro used to prevent expansion of fileno on broken versions of MinGW.
|
int buffered_file::descriptor() const {
|
||||||
#define FMT_ARGS
|
#ifdef fileno // fileno is a macro on OpenBSD so we cannot use FMT_POSIX_CALL.
|
||||||
|
int fd = fileno(file_);
|
||||||
int buffered_file::fileno() const {
|
#else
|
||||||
int fd = FMT_POSIX_CALL(fileno FMT_ARGS(file_));
|
int fd = FMT_POSIX_CALL(fileno(file_));
|
||||||
if (fd == -1) FMT_THROW(system_error(errno, "cannot get file descriptor"));
|
#endif
|
||||||
|
if (fd == -1)
|
||||||
|
FMT_THROW(system_error(errno, FMT_STRING("cannot get file descriptor")));
|
||||||
return fd;
|
return fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if FMT_USE_FCNTL
|
#if FMT_USE_FCNTL
|
||||||
file::file(cstring_view path, int oflag) {
|
|
||||||
# ifdef _WIN32
|
# ifdef _WIN32
|
||||||
using mode_t = int;
|
using mode_t = int;
|
||||||
# endif
|
# endif
|
||||||
mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
|
constexpr mode_t default_open_mode =
|
||||||
|
S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
|
||||||
|
|
||||||
|
file::file(cstring_view path, int oflag) {
|
||||||
# if defined(_WIN32) && !defined(__MINGW32__)
|
# if defined(_WIN32) && !defined(__MINGW32__)
|
||||||
fd_ = -1;
|
fd_ = -1;
|
||||||
FMT_POSIX_CALL(sopen_s(&fd_, path.c_str(), oflag, _SH_DENYNO, mode));
|
auto converted = detail::utf8_to_utf16(string_view(path.c_str()));
|
||||||
|
*this = file::open_windows_file(converted.c_str(), oflag);
|
||||||
# else
|
# else
|
||||||
FMT_RETRY(fd_, FMT_POSIX_CALL(open(path.c_str(), oflag, mode)));
|
FMT_RETRY(fd_, FMT_POSIX_CALL(open(path.c_str(), oflag, default_open_mode)));
|
||||||
# endif
|
|
||||||
if (fd_ == -1)
|
if (fd_ == -1)
|
||||||
FMT_THROW(system_error(errno, "cannot open file {}", path.c_str()));
|
FMT_THROW(
|
||||||
|
system_error(errno, FMT_STRING("cannot open file {}"), path.c_str()));
|
||||||
|
# endif
|
||||||
}
|
}
|
||||||
|
|
||||||
file::~file() FMT_NOEXCEPT {
|
file::~file() noexcept {
|
||||||
// Don't retry close in case of EINTR!
|
// Don't retry close in case of EINTR!
|
||||||
// See http://linux.derkeiler.com/Mailing-Lists/Kernel/2005-09/3000.html
|
// See http://linux.derkeiler.com/Mailing-Lists/Kernel/2005-09/3000.html
|
||||||
if (fd_ != -1 && FMT_POSIX_CALL(close(fd_)) != 0)
|
if (fd_ != -1 && FMT_POSIX_CALL(close(fd_)) != 0)
|
||||||
@@ -238,7 +225,8 @@ void file::close() {
|
|||||||
// See http://linux.derkeiler.com/Mailing-Lists/Kernel/2005-09/3000.html
|
// See http://linux.derkeiler.com/Mailing-Lists/Kernel/2005-09/3000.html
|
||||||
int result = FMT_POSIX_CALL(close(fd_));
|
int result = FMT_POSIX_CALL(close(fd_));
|
||||||
fd_ = -1;
|
fd_ = -1;
|
||||||
if (result != 0) FMT_THROW(system_error(errno, "cannot close file"));
|
if (result != 0)
|
||||||
|
FMT_THROW(system_error(errno, FMT_STRING("cannot close file")));
|
||||||
}
|
}
|
||||||
|
|
||||||
long long file::size() const {
|
long long file::size() const {
|
||||||
@@ -260,7 +248,7 @@ long long file::size() const {
|
|||||||
using Stat = struct stat;
|
using Stat = struct stat;
|
||||||
Stat file_stat = Stat();
|
Stat file_stat = Stat();
|
||||||
if (FMT_POSIX_CALL(fstat(fd_, &file_stat)) == -1)
|
if (FMT_POSIX_CALL(fstat(fd_, &file_stat)) == -1)
|
||||||
FMT_THROW(system_error(errno, "cannot get file attributes"));
|
FMT_THROW(system_error(errno, FMT_STRING("cannot get file attributes")));
|
||||||
static_assert(sizeof(long long) >= sizeof(file_stat.st_size),
|
static_assert(sizeof(long long) >= sizeof(file_stat.st_size),
|
||||||
"return type of file::size is not large enough");
|
"return type of file::size is not large enough");
|
||||||
return file_stat.st_size;
|
return file_stat.st_size;
|
||||||
@@ -270,14 +258,16 @@ long long file::size() const {
|
|||||||
std::size_t file::read(void* buffer, std::size_t count) {
|
std::size_t file::read(void* buffer, std::size_t count) {
|
||||||
rwresult result = 0;
|
rwresult result = 0;
|
||||||
FMT_RETRY(result, FMT_POSIX_CALL(read(fd_, buffer, convert_rwcount(count))));
|
FMT_RETRY(result, FMT_POSIX_CALL(read(fd_, buffer, convert_rwcount(count))));
|
||||||
if (result < 0) FMT_THROW(system_error(errno, "cannot read from file"));
|
if (result < 0)
|
||||||
|
FMT_THROW(system_error(errno, FMT_STRING("cannot read from file")));
|
||||||
return detail::to_unsigned(result);
|
return detail::to_unsigned(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::size_t file::write(const void* buffer, std::size_t count) {
|
std::size_t file::write(const void* buffer, std::size_t count) {
|
||||||
rwresult result = 0;
|
rwresult result = 0;
|
||||||
FMT_RETRY(result, FMT_POSIX_CALL(write(fd_, buffer, convert_rwcount(count))));
|
FMT_RETRY(result, FMT_POSIX_CALL(write(fd_, buffer, convert_rwcount(count))));
|
||||||
if (result < 0) FMT_THROW(system_error(errno, "cannot write to file"));
|
if (result < 0)
|
||||||
|
FMT_THROW(system_error(errno, FMT_STRING("cannot write to file")));
|
||||||
return detail::to_unsigned(result);
|
return detail::to_unsigned(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -286,7 +276,8 @@ file file::dup(int fd) {
|
|||||||
// http://pubs.opengroup.org/onlinepubs/009695399/functions/dup.html
|
// http://pubs.opengroup.org/onlinepubs/009695399/functions/dup.html
|
||||||
int new_fd = FMT_POSIX_CALL(dup(fd));
|
int new_fd = FMT_POSIX_CALL(dup(fd));
|
||||||
if (new_fd == -1)
|
if (new_fd == -1)
|
||||||
FMT_THROW(system_error(errno, "cannot duplicate file descriptor {}", fd));
|
FMT_THROW(system_error(
|
||||||
|
errno, FMT_STRING("cannot duplicate file descriptor {}"), fd));
|
||||||
return file(new_fd);
|
return file(new_fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -294,12 +285,13 @@ void file::dup2(int fd) {
|
|||||||
int result = 0;
|
int result = 0;
|
||||||
FMT_RETRY(result, FMT_POSIX_CALL(dup2(fd_, fd)));
|
FMT_RETRY(result, FMT_POSIX_CALL(dup2(fd_, fd)));
|
||||||
if (result == -1) {
|
if (result == -1) {
|
||||||
FMT_THROW(system_error(errno, "cannot duplicate file descriptor {} to {}",
|
FMT_THROW(system_error(
|
||||||
fd_, fd));
|
errno, FMT_STRING("cannot duplicate file descriptor {} to {}"), fd_,
|
||||||
|
fd));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void file::dup2(int fd, std::error_code& ec) FMT_NOEXCEPT {
|
void file::dup2(int fd, std::error_code& ec) noexcept {
|
||||||
int result = 0;
|
int result = 0;
|
||||||
FMT_RETRY(result, FMT_POSIX_CALL(dup2(fd_, fd)));
|
FMT_RETRY(result, FMT_POSIX_CALL(dup2(fd_, fd)));
|
||||||
if (result == -1) ec = std::error_code(errno, std::generic_category());
|
if (result == -1) ec = std::error_code(errno, std::generic_category());
|
||||||
@@ -320,7 +312,8 @@ void file::pipe(file& read_end, file& write_end) {
|
|||||||
// http://pubs.opengroup.org/onlinepubs/009696799/functions/pipe.html
|
// http://pubs.opengroup.org/onlinepubs/009696799/functions/pipe.html
|
||||||
int result = FMT_POSIX_CALL(pipe(fds));
|
int result = FMT_POSIX_CALL(pipe(fds));
|
||||||
# endif
|
# endif
|
||||||
if (result != 0) FMT_THROW(system_error(errno, "cannot create pipe"));
|
if (result != 0)
|
||||||
|
FMT_THROW(system_error(errno, FMT_STRING("cannot create pipe")));
|
||||||
// The following assignments don't throw because read_fd and write_fd
|
// The following assignments don't throw because read_fd and write_fd
|
||||||
// are closed.
|
// are closed.
|
||||||
read_end = file(fds[0]);
|
read_end = file(fds[0]);
|
||||||
@@ -334,28 +327,72 @@ buffered_file file::fdopen(const char* mode) {
|
|||||||
# else
|
# else
|
||||||
FILE* f = FMT_POSIX_CALL(fdopen(fd_, mode));
|
FILE* f = FMT_POSIX_CALL(fdopen(fd_, mode));
|
||||||
# endif
|
# endif
|
||||||
if (!f)
|
if (!f) {
|
||||||
FMT_THROW(
|
FMT_THROW(system_error(
|
||||||
system_error(errno, "cannot associate stream with file descriptor"));
|
errno, FMT_STRING("cannot associate stream with file descriptor")));
|
||||||
|
}
|
||||||
buffered_file bf(f);
|
buffered_file bf(f);
|
||||||
fd_ = -1;
|
fd_ = -1;
|
||||||
return bf;
|
return bf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# if defined(_WIN32) && !defined(__MINGW32__)
|
||||||
|
file file::open_windows_file(wcstring_view path, int oflag) {
|
||||||
|
int fd = -1;
|
||||||
|
auto err = _wsopen_s(&fd, path.c_str(), oflag, _SH_DENYNO, default_open_mode);
|
||||||
|
if (fd == -1) {
|
||||||
|
FMT_THROW(system_error(err, FMT_STRING("cannot open file {}"),
|
||||||
|
detail::to_utf8<wchar_t>(path.c_str()).c_str()));
|
||||||
|
}
|
||||||
|
return file(fd);
|
||||||
|
}
|
||||||
|
# endif
|
||||||
|
|
||||||
|
# if !defined(__MSDOS__)
|
||||||
long getpagesize() {
|
long getpagesize() {
|
||||||
# ifdef _WIN32
|
# ifdef _WIN32
|
||||||
SYSTEM_INFO si;
|
SYSTEM_INFO si;
|
||||||
GetSystemInfo(&si);
|
GetSystemInfo(&si);
|
||||||
return si.dwPageSize;
|
return si.dwPageSize;
|
||||||
# else
|
# else
|
||||||
|
# ifdef _WRS_KERNEL
|
||||||
|
long size = FMT_POSIX_CALL(getpagesize());
|
||||||
|
# else
|
||||||
long size = FMT_POSIX_CALL(sysconf(_SC_PAGESIZE));
|
long size = FMT_POSIX_CALL(sysconf(_SC_PAGESIZE));
|
||||||
if (size < 0) FMT_THROW(system_error(errno, "cannot get memory page size"));
|
# endif
|
||||||
return size;
|
|
||||||
# endif
|
|
||||||
}
|
|
||||||
|
|
||||||
FMT_API void ostream::grow(size_t) {
|
if (size < 0)
|
||||||
|
FMT_THROW(system_error(errno, FMT_STRING("cannot get memory page size")));
|
||||||
|
return size;
|
||||||
|
# endif
|
||||||
|
}
|
||||||
|
# endif
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
void file_buffer::grow(size_t) {
|
||||||
if (this->size() == this->capacity()) flush();
|
if (this->size() == this->capacity()) flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
file_buffer::file_buffer(cstring_view path,
|
||||||
|
const detail::ostream_params& params)
|
||||||
|
: file_(path, params.oflag) {
|
||||||
|
set(new char[params.buffer_size], params.buffer_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
file_buffer::file_buffer(file_buffer&& other)
|
||||||
|
: detail::buffer<char>(other.data(), other.size(), other.capacity()),
|
||||||
|
file_(std::move(other.file_)) {
|
||||||
|
other.clear();
|
||||||
|
other.set(nullptr, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
file_buffer::~file_buffer() {
|
||||||
|
flush();
|
||||||
|
delete[] data();
|
||||||
|
}
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
ostream::~ostream() = default;
|
||||||
#endif // FMT_USE_FCNTL
|
#endif // FMT_USE_FCNTL
|
||||||
FMT_END_NAMESPACE
|
FMT_END_NAMESPACE
|
||||||
|
|||||||
@@ -68,13 +68,13 @@ public:
|
|||||||
bool SetLogLevel(std::string const& name, int32 level, bool isLogger = true);
|
bool SetLogLevel(std::string const& name, int32 level, bool isLogger = true);
|
||||||
|
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
inline void outMessage(std::string const& filter, LogLevel const level, std::string_view fmt, Args&&... args)
|
inline void outMessage(std::string const& filter, LogLevel const level, Acore::FormatString<Args...> fmt, Args&&... args)
|
||||||
{
|
{
|
||||||
_outMessage(filter, level, Acore::StringFormatFmt(fmt, std::forward<Args>(args)...));
|
_outMessage(filter, level, Acore::StringFormatFmt(fmt, std::forward<Args>(args)...));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
void outCommand(uint32 account, std::string_view fmt, Args&&... args)
|
void outCommand(uint32 account, Acore::FormatString<Args...> fmt, Args&&... args)
|
||||||
{
|
{
|
||||||
if (!ShouldLog("commands.gm", LOG_LEVEL_INFO))
|
if (!ShouldLog("commands.gm", LOG_LEVEL_INFO))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -39,17 +39,20 @@ namespace Acore
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename... Args>
|
||||||
|
using FormatString = fmt::format_string<Args...>;
|
||||||
|
|
||||||
// Default string format function.
|
// Default string format function.
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
inline std::string StringFormatFmt(std::string_view fmt, Args&&... args)
|
inline std::string StringFormatFmt(FormatString<Args...> fmt, Args&&... args)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return fmt::format(fmt, std::forward<Args>(args)...);
|
return fmt::format(fmt, std::forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
catch (const fmt::format_error& formatError)
|
catch (std::exception const& e)
|
||||||
{
|
{
|
||||||
return fmt::format("An error occurred formatting string \"{}\": {}", fmt, formatError.what());
|
return fmt::format("Wrong format occurred ({}). Fmt string: '{}'", e.what(), fmt.get());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -76,4 +79,9 @@ namespace Acore::String
|
|||||||
AC_COMMON_API std::string AddSuffixIfNotExists(std::string str, const char suffix);
|
AC_COMMON_API std::string AddSuffixIfNotExists(std::string str, const char suffix);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add support enum for fmt
|
||||||
|
//template <typename T, std::enable_if_t<std::is_enum_v<T>, int> = 0>
|
||||||
|
template <typename T, FMT_ENABLE_IF(std::is_enum_v<T>)>
|
||||||
|
auto format_as(T f) { return fmt::underlying(f); }
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -633,6 +633,9 @@ namespace lfg
|
|||||||
bool m_Testing;
|
bool m_Testing;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <typename T, FMT_ENABLE_IF(std::is_enum_v<T>)>
|
||||||
|
auto format_as(T f) { return fmt::underlying(f); }
|
||||||
|
|
||||||
} // namespace lfg
|
} // namespace lfg
|
||||||
|
|
||||||
#define sLFGMgr lfg::LFGMgr::instance()
|
#define sLFGMgr lfg::LFGMgr::instance()
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
#define PacketUtilities_h__
|
#define PacketUtilities_h__
|
||||||
|
|
||||||
#include "ByteBuffer.h"
|
#include "ByteBuffer.h"
|
||||||
|
#include "StringFormat.h"
|
||||||
#include "Tuples.h"
|
#include "Tuples.h"
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
|
|
||||||
@@ -295,4 +296,13 @@ namespace WorldPackets
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<std::size_t MaxBytesWithoutNullTerminator, typename... Validators>
|
||||||
|
struct fmt::formatter<WorldPackets::String<MaxBytesWithoutNullTerminator, Validators...>> : fmt::formatter<std::string_view>
|
||||||
|
{
|
||||||
|
auto format(WorldPackets::String<MaxBytesWithoutNullTerminator, Validators...> const& str, format_context& ctx) const
|
||||||
|
{
|
||||||
|
return fmt::formatter<std::string_view>::format(std::string_view(str), ctx);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
#endif // PacketUtilities_h__
|
#endif // PacketUtilities_h__
|
||||||
Reference in New Issue
Block a user