externals/fmt: Update fmt to 5.3.0
Merge commit '0066ad2d3879f4604b3a2644128cf5d447e54eef' into HEAD
This commit is contained in:
commit
51fe05a443
41 changed files with 3817 additions and 2059 deletions
1
externals/fmt/.gitignore
vendored
1
externals/fmt/.gitignore
vendored
|
@ -31,3 +31,4 @@ CMakeFiles
|
||||||
FMT.build
|
FMT.build
|
||||||
Makefile
|
Makefile
|
||||||
run-msbuild.bat
|
run-msbuild.bat
|
||||||
|
fmt.pc
|
||||||
|
|
71
externals/fmt/.travis.yml
vendored
71
externals/fmt/.travis.yml
vendored
|
@ -84,42 +84,41 @@ matrix:
|
||||||
sources:
|
sources:
|
||||||
- ubuntu-toolchain-r-test
|
- ubuntu-toolchain-r-test
|
||||||
# Android
|
# Android
|
||||||
# - language: android
|
- language: android
|
||||||
# android:
|
addons:
|
||||||
# addons:
|
apt:
|
||||||
# apt:
|
update: true
|
||||||
# update: true
|
sources:
|
||||||
# components:
|
- ubuntu-toolchain-r-test
|
||||||
# - tools
|
packages:
|
||||||
# - platform-tools
|
- wget
|
||||||
# - android-21
|
- unzip
|
||||||
# - sys-img-armeabi-v7a-android-21
|
- tree
|
||||||
# env:
|
android:
|
||||||
# - ANDROID=true
|
components:
|
||||||
# before_install:
|
- tools
|
||||||
# - git submodule update --init --recursive
|
- platform-tools
|
||||||
# - sudo apt-get install wget unzip tree
|
- android-21
|
||||||
# install:
|
env:
|
||||||
# # Accept SDK Licenses + Install NDK
|
- ANDROID=true
|
||||||
# - yes | sdkmanager --update > /dev/null 2>&1
|
before_install:
|
||||||
# - sdkmanager ndk-bundle > /dev/null 2>&1
|
# Download/Install Gradle
|
||||||
# # Download Gradle 4.3.1
|
- wget https://services.gradle.org/distributions/gradle-4.10.2-bin.zip
|
||||||
# - wget https://services.gradle.org/distributions/gradle-4.3.1-bin.zip
|
- mkdir -p gradle
|
||||||
# - mkdir -p gradle
|
- unzip -q -d ./gradle gradle-4.10.2-bin.zip
|
||||||
# - unzip -q -d ./gradle gradle-4.3.1-bin.zip
|
- export GRADLE=gradle/gradle-4.10.2/bin/gradle
|
||||||
# - export GRADLE=${TRAVIS_BUILD_DIR}/gradle/gradle-4.3.1/bin/gradle
|
- bash $GRADLE --version
|
||||||
# before_script:
|
install:
|
||||||
# - bash $GRADLE --version
|
# Accept SDK Licenses + Install NDK
|
||||||
# - cd ./support
|
- yes | sdkmanager --update > /dev/null 2>&1
|
||||||
# script:
|
- sdkmanager ndk-bundle > /dev/null 2>&1
|
||||||
# - bash $GRADLE clean assemble
|
before_script:
|
||||||
# after_success:
|
- pushd ./support
|
||||||
# - cd ${TRAVIS_BUILD_DIR}
|
script:
|
||||||
# - tree ./libs
|
- bash ../$GRADLE clean assemble
|
||||||
allow_failures:
|
after_success:
|
||||||
# Errors
|
- popd;
|
||||||
- env: COMPILER=g++-4.4 BUILD=Debug STANDARD=11
|
- tree ./libs
|
||||||
compiler: gcc
|
|
||||||
|
|
||||||
before_script:
|
before_script:
|
||||||
- if [[ "${TRAVIS_OS_NAME}" == "linux" ]]; then export CXX=${COMPILER}; fi
|
- if [[ "${TRAVIS_OS_NAME}" == "linux" ]]; then export CXX=${COMPILER}; fi
|
||||||
|
|
46
externals/fmt/CMakeLists.txt
vendored
46
externals/fmt/CMakeLists.txt
vendored
|
@ -68,16 +68,17 @@ include(CheckCXXCompilerFlag)
|
||||||
|
|
||||||
if (CMAKE_CXX_COMPILER_ID MATCHES "GNU")
|
if (CMAKE_CXX_COMPILER_ID MATCHES "GNU")
|
||||||
set(PEDANTIC_COMPILE_FLAGS -pedantic-errors -Wall -Wextra -pedantic
|
set(PEDANTIC_COMPILE_FLAGS -pedantic-errors -Wall -Wextra -pedantic
|
||||||
-Wold-style-cast -Wfloat-equal -Wlogical-op -Wundef
|
-Wold-style-cast -Wundef
|
||||||
-Wredundant-decls -Wshadow -Wwrite-strings -Wpointer-arith
|
-Wredundant-decls -Wwrite-strings -Wpointer-arith
|
||||||
-Wcast-qual -Wformat=2 -Wmissing-include-dirs
|
-Wcast-qual -Wformat=2 -Wmissing-include-dirs
|
||||||
-Wcast-align -Wnon-virtual-dtor
|
-Wcast-align -Wnon-virtual-dtor
|
||||||
-Wctor-dtor-privacy -Wdisabled-optimization
|
-Wctor-dtor-privacy -Wdisabled-optimization
|
||||||
-Winvalid-pch -Woverloaded-virtual
|
-Winvalid-pch -Woverloaded-virtual
|
||||||
-Wno-ctor-dtor-privacy -Wno-dangling-else -Wno-float-equal
|
-Wconversion
|
||||||
-Wno-format-nonliteral -Wno-sign-conversion -Wno-shadow)
|
-Wno-ctor-dtor-privacy -Wno-format-nonliteral -Wno-shadow)
|
||||||
if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.6)
|
if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.6)
|
||||||
set(PEDANTIC_COMPILE_FLAGS ${PEDANTIC_COMPILE_FLAGS} -Wnoexcept)
|
set(PEDANTIC_COMPILE_FLAGS ${PEDANTIC_COMPILE_FLAGS} -Wnoexcept
|
||||||
|
-Wno-dangling-else -Wno-unused-local-typedefs)
|
||||||
endif ()
|
endif ()
|
||||||
if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.0)
|
if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.0)
|
||||||
set(PEDANTIC_COMPILE_FLAGS ${PEDANTIC_COMPILE_FLAGS} -Wdouble-promotion
|
set(PEDANTIC_COMPILE_FLAGS ${PEDANTIC_COMPILE_FLAGS} -Wdouble-promotion
|
||||||
|
@ -88,29 +89,17 @@ if (CMAKE_CXX_COMPILER_ID MATCHES "GNU")
|
||||||
set(PEDANTIC_COMPILE_FLAGS ${PEDANTIC_COMPILE_FLAGS} -Wshift-overflow=2
|
set(PEDANTIC_COMPILE_FLAGS ${PEDANTIC_COMPILE_FLAGS} -Wshift-overflow=2
|
||||||
-Wnull-dereference -Wduplicated-cond)
|
-Wnull-dereference -Wduplicated-cond)
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
set(WERROR_FLAG -Werror)
|
set(WERROR_FLAG -Werror)
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||||
set(PEDANTIC_COMPILE_FLAGS -Weverything -Wpedantic
|
set(PEDANTIC_COMPILE_FLAGS -Wall -Wextra -pedantic -Wconversion -Wno-sign-conversion)
|
||||||
-Wno-weak-vtables -Wno-padded -Wno-gnu-statement-expression
|
check_cxx_compiler_flag(-Wzero-as-null-pointer-constant HAS_NULLPTR_WARNING)
|
||||||
-Wno-c++98-compat -Wno-c++98-compat-pedantic -Wno-reserved-id-macro
|
|
||||||
-Wno-global-constructors -Wno-disabled-macro-expansion
|
|
||||||
-Wno-switch-enum -Wno-documentation-unknown-command
|
|
||||||
-Wno-unused-member-function
|
|
||||||
-Wno-format-nonliteral -Wno-missing-noreturn -Wno-undefined-func-template
|
|
||||||
-Wno-shadow -Wno-sign-conversion -Wno-used-but-marked-unused
|
|
||||||
-Wno-covered-switch-default -Wno-missing-prototypes
|
|
||||||
-Wno-missing-variable-declarations -Wno-double-promotion)
|
|
||||||
|
|
||||||
set(WERROR_FLAG -Werror)
|
|
||||||
|
|
||||||
check_cxx_compiler_flag(-Wno-zero-as-null-pointer-constant HAS_NULLPTR_WARNING)
|
|
||||||
if (HAS_NULLPTR_WARNING)
|
if (HAS_NULLPTR_WARNING)
|
||||||
set(PEDANTIC_COMPILE_FLAGS ${PEDANTIC_COMPILE_FLAGS}
|
set(PEDANTIC_COMPILE_FLAGS ${PEDANTIC_COMPILE_FLAGS}
|
||||||
-Wno-zero-as-null-pointer-constant)
|
-Wzero-as-null-pointer-constant)
|
||||||
endif ()
|
endif ()
|
||||||
|
set(WERROR_FLAG -Werror)
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
if (MSVC)
|
if (MSVC)
|
||||||
|
@ -150,8 +139,8 @@ function(add_headers VAR)
|
||||||
endfunction()
|
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 color.h core.h format.h format-inl.h ostream.h printf.h
|
add_headers(FMT_HEADERS chrono.h color.h core.h format.h format-inl.h locale.h
|
||||||
time.h ranges.h)
|
ostream.h printf.h time.h ranges.h)
|
||||||
set(FMT_SOURCES src/format.cc)
|
set(FMT_SOURCES src/format.cc)
|
||||||
if (HAVE_OPEN)
|
if (HAVE_OPEN)
|
||||||
add_headers(FMT_HEADERS posix.h)
|
add_headers(FMT_HEADERS posix.h)
|
||||||
|
@ -202,6 +191,7 @@ if (FMT_INSTALL)
|
||||||
"Installation directory for cmake files, relative to ${CMAKE_INSTALL_PREFIX}.")
|
"Installation directory for cmake files, relative to ${CMAKE_INSTALL_PREFIX}.")
|
||||||
set(version_config ${PROJECT_BINARY_DIR}/fmt-config-version.cmake)
|
set(version_config ${PROJECT_BINARY_DIR}/fmt-config-version.cmake)
|
||||||
set(project_config ${PROJECT_BINARY_DIR}/fmt-config.cmake)
|
set(project_config ${PROJECT_BINARY_DIR}/fmt-config.cmake)
|
||||||
|
set(pkgconfig ${PROJECT_BINARY_DIR}/fmt.pc)
|
||||||
set(targets_export_name fmt-targets)
|
set(targets_export_name fmt-targets)
|
||||||
|
|
||||||
set (INSTALL_TARGETS fmt)
|
set (INSTALL_TARGETS fmt)
|
||||||
|
@ -215,11 +205,18 @@ if (FMT_INSTALL)
|
||||||
set(FMT_INC_DIR ${CMAKE_INSTALL_INCLUDEDIR}/fmt CACHE STRING
|
set(FMT_INC_DIR ${CMAKE_INSTALL_INCLUDEDIR}/fmt CACHE STRING
|
||||||
"Installation directory for include files, relative to ${CMAKE_INSTALL_PREFIX}.")
|
"Installation directory for include files, relative to ${CMAKE_INSTALL_PREFIX}.")
|
||||||
|
|
||||||
|
set(FMT_PKGCONFIG_DIR "${CMAKE_INSTALL_PREFIX}/share/pkgconfig" CACHE PATH
|
||||||
|
"Installation directory for pkgconfig (.pc) files, relative to ${CMAKE_INSTALL_PREFIX}.")
|
||||||
|
|
||||||
# Generate the version, config and target files into the build directory.
|
# Generate the version, config and target files into the build directory.
|
||||||
write_basic_package_version_file(
|
write_basic_package_version_file(
|
||||||
${version_config}
|
${version_config}
|
||||||
VERSION ${FMT_VERSION}
|
VERSION ${FMT_VERSION}
|
||||||
COMPATIBILITY AnyNewerVersion)
|
COMPATIBILITY AnyNewerVersion)
|
||||||
|
configure_file(
|
||||||
|
"${PROJECT_SOURCE_DIR}/support/cmake/fmt.pc.in"
|
||||||
|
"${pkgconfig}"
|
||||||
|
@ONLY)
|
||||||
configure_package_config_file(
|
configure_package_config_file(
|
||||||
${PROJECT_SOURCE_DIR}/support/cmake/fmt-config.cmake.in
|
${PROJECT_SOURCE_DIR}/support/cmake/fmt-config.cmake.in
|
||||||
${project_config}
|
${project_config}
|
||||||
|
@ -239,7 +236,10 @@ if (FMT_INSTALL)
|
||||||
# Install the library and headers.
|
# Install the library and headers.
|
||||||
install(TARGETS ${INSTALL_TARGETS} EXPORT ${targets_export_name}
|
install(TARGETS ${INSTALL_TARGETS} EXPORT ${targets_export_name}
|
||||||
DESTINATION ${FMT_LIB_DIR})
|
DESTINATION ${FMT_LIB_DIR})
|
||||||
|
|
||||||
|
install(FILES $<TARGET_PDB_FILE:${INSTALL_TARGETS}> DESTINATION ${FMT_LIB_DIR} OPTIONAL)
|
||||||
install(FILES ${FMT_HEADERS} DESTINATION ${FMT_INC_DIR})
|
install(FILES ${FMT_HEADERS} DESTINATION ${FMT_INC_DIR})
|
||||||
|
install(FILES "${pkgconfig}" DESTINATION "${FMT_PKGCONFIG_DIR}")
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
if (FMT_DOC)
|
if (FMT_DOC)
|
||||||
|
|
236
externals/fmt/ChangeLog.rst
vendored
236
externals/fmt/ChangeLog.rst
vendored
|
@ -1,3 +1,239 @@
|
||||||
|
5.3.0 - 2018-12-28
|
||||||
|
------------------
|
||||||
|
|
||||||
|
* Introduced experimental chrono formatting support:
|
||||||
|
|
||||||
|
.. code:: c++
|
||||||
|
|
||||||
|
#include <fmt/chrono.h>
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
using namespace std::literals::chrono_literals;
|
||||||
|
fmt::print("Default format: {} {}\n", 42s, 100ms);
|
||||||
|
fmt::print("strftime-like format: {:%H:%M:%S}\n", 3h + 15min + 30s);
|
||||||
|
}
|
||||||
|
|
||||||
|
prints::
|
||||||
|
|
||||||
|
Default format: 42s 100ms
|
||||||
|
strftime-like format: 03:15:30
|
||||||
|
|
||||||
|
* Added experimental support for emphasis (bold, italic, underline,
|
||||||
|
strikethrough), colored output to a file stream, and improved colored
|
||||||
|
formatting API
|
||||||
|
(`#961 <https://github.com/fmtlib/fmt/pull/961>`_,
|
||||||
|
`#967 <https://github.com/fmtlib/fmt/pull/967>`_,
|
||||||
|
`#973 <https://github.com/fmtlib/fmt/pull/973>`_):
|
||||||
|
|
||||||
|
.. code:: c++
|
||||||
|
|
||||||
|
#include <fmt/color.h>
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
print(fg(fmt::color::crimson) | fmt::emphasis::bold,
|
||||||
|
"Hello, {}!\n", "world");
|
||||||
|
print(fg(fmt::color::floral_white) | bg(fmt::color::slate_gray) |
|
||||||
|
fmt::emphasis::underline, "Hello, {}!\n", "мир");
|
||||||
|
print(fg(fmt::color::steel_blue) | fmt::emphasis::italic,
|
||||||
|
"Hello, {}!\n", "世界");
|
||||||
|
}
|
||||||
|
|
||||||
|
prints the following on modern terminals with RGB color support:
|
||||||
|
|
||||||
|
.. image:: https://user-images.githubusercontent.com/576385/
|
||||||
|
50405788-b66e7500-076e-11e9-9592-7324d1f951d8.png
|
||||||
|
|
||||||
|
Thanks `@Rakete1111 (Nicolas) <https://github.com/Rakete1111>`_.
|
||||||
|
|
||||||
|
* Added support for 4-bit terminal colors
|
||||||
|
(`#968 <https://github.com/fmtlib/fmt/issues/968>`_,
|
||||||
|
`#974 <https://github.com/fmtlib/fmt/pull/974>`_)
|
||||||
|
|
||||||
|
.. code:: c++
|
||||||
|
|
||||||
|
#include <fmt/color.h>
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
print(fg(fmt::terminal_color::red), "stop\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
Note that these colors vary by terminal:
|
||||||
|
|
||||||
|
.. image:: https://user-images.githubusercontent.com/576385/
|
||||||
|
50405925-dbfc7e00-0770-11e9-9b85-333fab0af9ac.png
|
||||||
|
|
||||||
|
Thanks `@Rakete1111 (Nicolas) <https://github.com/Rakete1111>`_.
|
||||||
|
|
||||||
|
* Parameterized formatting functions on the type of the format string
|
||||||
|
(`#880 <https://github.com/fmtlib/fmt/issues/880>`_,
|
||||||
|
`#881 <https://github.com/fmtlib/fmt/pull/881>`_,
|
||||||
|
`#883 <https://github.com/fmtlib/fmt/pull/883>`_,
|
||||||
|
`#885 <https://github.com/fmtlib/fmt/pull/885>`_,
|
||||||
|
`#897 <https://github.com/fmtlib/fmt/pull/897>`_,
|
||||||
|
`#920 <https://github.com/fmtlib/fmt/issues/920>`_).
|
||||||
|
Any object of type ``S`` that has an overloaded ``to_string_view(const S&)``
|
||||||
|
returning ``fmt::string_view`` can be used as a format string:
|
||||||
|
|
||||||
|
.. code:: c++
|
||||||
|
|
||||||
|
namespace my_ns {
|
||||||
|
inline string_view to_string_view(const my_string& s) {
|
||||||
|
return {s.data(), s.length()};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string message = fmt::format(my_string("The answer is {}."), 42);
|
||||||
|
|
||||||
|
Thanks `@DanielaE (Daniela Engert) <https://github.com/DanielaE>`_.
|
||||||
|
|
||||||
|
* Made ``std::string_view`` work as a format string
|
||||||
|
(`#898 <https://github.com/fmtlib/fmt/pull/898>`_):
|
||||||
|
|
||||||
|
.. code:: c++
|
||||||
|
|
||||||
|
auto message = fmt::format(std::string_view("The answer is {}."), 42);
|
||||||
|
|
||||||
|
Thanks `@DanielaE (Daniela Engert) <https://github.com/DanielaE>`_.
|
||||||
|
|
||||||
|
* Added wide string support to compile-time format string checks
|
||||||
|
(`#924 <https://github.com/fmtlib/fmt/pull/924>`_):
|
||||||
|
|
||||||
|
.. code:: c++
|
||||||
|
|
||||||
|
print(fmt(L"{:f}"), 42); // compile-time error: invalid type specifier
|
||||||
|
|
||||||
|
Thanks `@XZiar <https://github.com/XZiar>`_.
|
||||||
|
|
||||||
|
* Made colored print functions work with wide strings
|
||||||
|
(`#867 <https://github.com/fmtlib/fmt/pull/867>`_):
|
||||||
|
|
||||||
|
.. code:: c++
|
||||||
|
|
||||||
|
#include <fmt/color.h>
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
print(fg(fmt::color::red), L"{}\n", 42);
|
||||||
|
}
|
||||||
|
|
||||||
|
Thanks `@DanielaE (Daniela Engert) <https://github.com/DanielaE>`_.
|
||||||
|
|
||||||
|
* Introduced experimental Unicode support
|
||||||
|
(`#628 <https://github.com/fmtlib/fmt/issues/628>`_,
|
||||||
|
`#891 <https://github.com/fmtlib/fmt/pull/891>`_):
|
||||||
|
|
||||||
|
.. code:: c++
|
||||||
|
|
||||||
|
using namespace fmt::literals;
|
||||||
|
auto s = fmt::format("{:*^5}"_u, "🤡"_u); // s == "**🤡**"_u
|
||||||
|
|
||||||
|
* Improved locale support:
|
||||||
|
|
||||||
|
.. code:: c++
|
||||||
|
|
||||||
|
#include <fmt/locale.h>
|
||||||
|
|
||||||
|
struct numpunct : std::numpunct<char> {
|
||||||
|
protected:
|
||||||
|
char do_thousands_sep() const override { return '~'; }
|
||||||
|
};
|
||||||
|
|
||||||
|
std::locale loc;
|
||||||
|
auto s = fmt::format(std::locale(loc, new numpunct()), "{:n}", 1234567);
|
||||||
|
// s == "1~234~567"
|
||||||
|
|
||||||
|
* Constrained formatting functions on proper iterator types
|
||||||
|
(`#921 <https://github.com/fmtlib/fmt/pull/921>`_):
|
||||||
|
Thanks `@DanielaE (Daniela Engert) <https://github.com/DanielaE>`_.
|
||||||
|
|
||||||
|
* Added ``make_printf_args`` and ``make_wprintf_args`` functions
|
||||||
|
(`#934 <https://github.com/fmtlib/fmt/pull/934>`_).
|
||||||
|
Thanks `@tnovotny <https://github.com/tnovotny>`_.
|
||||||
|
|
||||||
|
* Deprecated ``fmt::visit``, ``parse_context``, and ``wparse_context``.
|
||||||
|
Use ``fmt::visit_format_arg``, ``format_parse_context``, and
|
||||||
|
``wformat_parse_context`` instead.
|
||||||
|
|
||||||
|
* Removed undocumented ``basic_fixed_buffer`` which has been superseded by the
|
||||||
|
iterator-based API
|
||||||
|
(`#873 <https://github.com/fmtlib/fmt/issues/873>`_,
|
||||||
|
`#902 <https://github.com/fmtlib/fmt/pull/902>`_).
|
||||||
|
Thanks `@superfunc (hollywood programmer) <https://github.com/superfunc>`_.
|
||||||
|
|
||||||
|
* Disallowed repeated leading zeros in an argument ID:
|
||||||
|
|
||||||
|
.. code:: c++
|
||||||
|
|
||||||
|
fmt::print("{000}", 42); // error
|
||||||
|
|
||||||
|
* Reintroduced support for gcc 4.4.
|
||||||
|
|
||||||
|
* Fixed compilation on platforms with exotic ``double``
|
||||||
|
(`#878 <https://github.com/fmtlib/fmt/issues/878>`_).
|
||||||
|
|
||||||
|
* Improved documentation
|
||||||
|
(`#164 <https://github.com/fmtlib/fmt/issues/164>`_,
|
||||||
|
`#877 <https://github.com/fmtlib/fmt/issues/877>`_,
|
||||||
|
`#901 <https://github.com/fmtlib/fmt/pull/901>`_,
|
||||||
|
`#906 <https://github.com/fmtlib/fmt/pull/906>`_,
|
||||||
|
`#979 <https://github.com/fmtlib/fmt/pull/979>`_).
|
||||||
|
Thanks `@kookjr (Mathew Cucuzella) <https://github.com/kookjr>`_,
|
||||||
|
`@DarkDimius (Dmitry Petrashko) <https://github.com/DarkDimius>`_,
|
||||||
|
`@HecticSerenity <https://github.com/HecticSerenity>`_.
|
||||||
|
|
||||||
|
* Added pkgconfig support which makes it easier to consume the library from
|
||||||
|
meson and other build systems
|
||||||
|
(`#916 <https://github.com/fmtlib/fmt/pull/916>`_).
|
||||||
|
Thanks `@colemickens (Cole Mickens) <https://github.com/colemickens>`_.
|
||||||
|
|
||||||
|
* Various build improvements
|
||||||
|
(`#909 <https://github.com/fmtlib/fmt/pull/909>`_,
|
||||||
|
`#926 <https://github.com/fmtlib/fmt/pull/926>`_,
|
||||||
|
`#937 <https://github.com/fmtlib/fmt/pull/937>`_,
|
||||||
|
`#953 <https://github.com/fmtlib/fmt/pull/953>`_,
|
||||||
|
`#959 <https://github.com/fmtlib/fmt/pull/959>`_).
|
||||||
|
Thanks `@tchaikov (Kefu Chai) <https://github.com/tchaikov>`_,
|
||||||
|
`@luncliff (Park DongHa) <https://github.com/luncliff>`_,
|
||||||
|
`@AndreasSchoenle (Andreas Schönle) <https://github.com/AndreasSchoenle>`_,
|
||||||
|
`@hotwatermorning <https://github.com/hotwatermorning>`_,
|
||||||
|
`@Zefz (JohanJansen) <https://github.com/Zefz>`_.
|
||||||
|
|
||||||
|
* Improved ``string_view`` construction performance
|
||||||
|
(`#914 <https://github.com/fmtlib/fmt/pull/914>`_).
|
||||||
|
Thanks `@gabime (Gabi Melman) <https://github.com/gabime>`_.
|
||||||
|
|
||||||
|
* Fixed non-matching char types
|
||||||
|
(`#895 <https://github.com/fmtlib/fmt/pull/895>`_).
|
||||||
|
Thanks `@DanielaE (Daniela Engert) <https://github.com/DanielaE>`_.
|
||||||
|
|
||||||
|
* Fixed ``format_to_n`` with ``std::back_insert_iterator``
|
||||||
|
(`#913 <https://github.com/fmtlib/fmt/pull/913>`_).
|
||||||
|
Thanks `@DanielaE (Daniela Engert) <https://github.com/DanielaE>`_.
|
||||||
|
|
||||||
|
* Fixed locale-dependent formatting
|
||||||
|
(`#905 <https://github.com/fmtlib/fmt/issues/905>`_).
|
||||||
|
|
||||||
|
* Fixed various compiler warnings and errors
|
||||||
|
(`#882 <https://github.com/fmtlib/fmt/pull/882>`_,
|
||||||
|
`#886 <https://github.com/fmtlib/fmt/pull/886>`_,
|
||||||
|
`#933 <https://github.com/fmtlib/fmt/pull/933>`_,
|
||||||
|
`#941 <https://github.com/fmtlib/fmt/pull/941>`_,
|
||||||
|
`#931 <https://github.com/fmtlib/fmt/issues/931>`_,
|
||||||
|
`#943 <https://github.com/fmtlib/fmt/pull/943>`_,
|
||||||
|
`#954 <https://github.com/fmtlib/fmt/pull/954>`_,
|
||||||
|
`#956 <https://github.com/fmtlib/fmt/pull/956>`_,
|
||||||
|
`#962 <https://github.com/fmtlib/fmt/pull/962>`_,
|
||||||
|
`#965 <https://github.com/fmtlib/fmt/issues/965>`_,
|
||||||
|
`#977 <https://github.com/fmtlib/fmt/issues/977>`_,
|
||||||
|
`#983 <https://github.com/fmtlib/fmt/pull/983>`_,
|
||||||
|
`#989 <https://github.com/fmtlib/fmt/pull/989>`_).
|
||||||
|
Thanks `@Luthaf (Guillaume Fraux) <https://github.com/Luthaf>`_,
|
||||||
|
`@stevenhoving (Steven Hoving) <https://github.com/stevenhoving>`_,
|
||||||
|
`@christinaa (Kristina Brooks) <https://github.com/christinaa>`_,
|
||||||
|
`@lgritz (Larry Gritz) <https://github.com/lgritz>`_,
|
||||||
|
`@DanielaE (Daniela Engert) <https://github.com/DanielaE>`_,
|
||||||
|
`@0x8000-0000 (Sign Bit) <https://github.com/0x8000-0000>`_,
|
||||||
|
`@liuping1997 <https://github.com/liuping1997>`_.
|
||||||
|
|
||||||
5.2.1 - 2018-09-21
|
5.2.1 - 2018-09-21
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
|
|
37
externals/fmt/README.rst
vendored
37
externals/fmt/README.rst
vendored
|
@ -30,7 +30,7 @@ Features
|
||||||
of `str.format <https://docs.python.org/2/library/stdtypes.html#str.format>`_
|
of `str.format <https://docs.python.org/2/library/stdtypes.html#str.format>`_
|
||||||
in Python.
|
in Python.
|
||||||
* Safe `printf implementation
|
* Safe `printf implementation
|
||||||
<http://fmtlib.net/latest/api.html#printf-formatting-functions>`_ including
|
<http://fmtlib.net/latest/api.html#printf-formatting>`_ including
|
||||||
the POSIX extension for positional arguments.
|
the POSIX extension for positional arguments.
|
||||||
* Support for user-defined types.
|
* Support for user-defined types.
|
||||||
* High speed: performance of the format API is close to that of glibc's `printf
|
* High speed: performance of the format API is close to that of glibc's `printf
|
||||||
|
@ -126,7 +126,7 @@ Formatting of user-defined types is supported via a simple
|
||||||
|
|
||||||
template <typename FormatContext>
|
template <typename FormatContext>
|
||||||
auto format(const date &d, FormatContext &ctx) {
|
auto format(const date &d, FormatContext &ctx) {
|
||||||
return format_to(ctx.begin(), "{}-{}-{}", d.year, d.month, d.day);
|
return format_to(ctx.out(), "{}-{}-{}", d.year, d.month, d.day);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -153,19 +153,27 @@ which take arbitrary arguments (`godbolt <https://godbolt.org/g/MHjHVf>`_):
|
||||||
report_error("file not found: {}", path);
|
report_error("file not found: {}", path);
|
||||||
|
|
||||||
Note that ``vreport_error`` is not parameterized on argument types which can
|
Note that ``vreport_error`` is not parameterized on argument types which can
|
||||||
improve compile times and reduce code size compared to fully parameterized version.
|
improve compile times and reduce code size compared to fully parameterized
|
||||||
|
version.
|
||||||
|
|
||||||
Projects using this library
|
Projects using this library
|
||||||
---------------------------
|
---------------------------
|
||||||
|
|
||||||
* `0 A.D. <http://play0ad.com/>`_: A free, open-source, cross-platform real-time strategy game
|
* `0 A.D. <http://play0ad.com/>`_: A free, open-source, cross-platform real-time
|
||||||
|
strategy game
|
||||||
|
|
||||||
* `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
|
||||||
|
|
||||||
* `AvioBook <https://www.aviobook.aero/en>`_: A comprehensive aircraft operations suite
|
* `AvioBook <https://www.aviobook.aero/en>`_: A comprehensive aircraft
|
||||||
|
operations suite
|
||||||
|
|
||||||
* `CUAUV <http://cuauv.org/>`_: Cornell University's autonomous underwater vehicle
|
* `Celestia <https://celestia.space/>`_: Real-time 3D visualization of space
|
||||||
|
|
||||||
|
* `Ceph <https://ceph.com/>`_: A scalable distributed storage system
|
||||||
|
|
||||||
|
* `CUAUV <http://cuauv.org/>`_: Cornell University's autonomous underwater
|
||||||
|
vehicle
|
||||||
|
|
||||||
* `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
|
||||||
|
@ -200,7 +208,11 @@ Projects using this library
|
||||||
|
|
||||||
* `readpe <https://bitbucket.org/sys_dev/readpe>`_: Read Portable Executable
|
* `readpe <https://bitbucket.org/sys_dev/readpe>`_: Read Portable Executable
|
||||||
|
|
||||||
* `redis-cerberus <https://github.com/HunanTV/redis-cerberus>`_: A Redis cluster proxy
|
* `redis-cerberus <https://github.com/HunanTV/redis-cerberus>`_: A Redis cluster
|
||||||
|
proxy
|
||||||
|
|
||||||
|
* `rpclib <http://rpclib.net/>`_: A modern C++ msgpack-RPC server and client
|
||||||
|
library
|
||||||
|
|
||||||
* `Saddy <https://github.com/mamontov-cpp/saddy-graphics-engine-2d>`_:
|
* `Saddy <https://github.com/mamontov-cpp/saddy-graphics-engine-2d>`_:
|
||||||
Small crossplatform 2D graphic engine
|
Small crossplatform 2D graphic engine
|
||||||
|
@ -208,11 +220,11 @@ Projects using this library
|
||||||
* `Salesforce Analytics Cloud <http://www.salesforce.com/analytics-cloud/overview/>`_:
|
* `Salesforce Analytics Cloud <http://www.salesforce.com/analytics-cloud/overview/>`_:
|
||||||
Business intelligence software
|
Business intelligence software
|
||||||
|
|
||||||
* `Scylla <http://www.scylladb.com/>`_: A Cassandra-compatible NoSQL data store that can handle
|
* `Scylla <http://www.scylladb.com/>`_: A Cassandra-compatible NoSQL data store
|
||||||
1 million transactions per second on a single server
|
that can handle 1 million transactions per second on a single server
|
||||||
|
|
||||||
* `Seastar <http://www.seastar-project.org/>`_: An advanced, open-source C++ framework for
|
* `Seastar <http://www.seastar-project.org/>`_: An advanced, open-source C++
|
||||||
high-performance server applications on modern hardware
|
framework for high-performance server applications on modern hardware
|
||||||
|
|
||||||
* `spdlog <https://github.com/gabime/spdlog>`_: Super fast C++ logging library
|
* `spdlog <https://github.com/gabime/spdlog>`_: Super fast C++ logging library
|
||||||
|
|
||||||
|
@ -220,7 +232,8 @@ Projects using this library
|
||||||
|
|
||||||
* `Touch Surgery <https://www.touchsurgery.com/>`_: Surgery simulator
|
* `Touch Surgery <https://www.touchsurgery.com/>`_: Surgery simulator
|
||||||
|
|
||||||
* `TrinityCore <https://github.com/TrinityCore/TrinityCore>`_: Open-source MMORPG framework
|
* `TrinityCore <https://github.com/TrinityCore/TrinityCore>`_: Open-source
|
||||||
|
MMORPG framework
|
||||||
|
|
||||||
`More... <https://github.com/search?q=cppformat&type=Code>`_
|
`More... <https://github.com/search?q=cppformat&type=Code>`_
|
||||||
|
|
||||||
|
|
63
externals/fmt/doc/api.rst
vendored
63
externals/fmt/doc/api.rst
vendored
|
@ -26,30 +26,29 @@ Core API
|
||||||
and a lightweight subset of formatting functions.
|
and a lightweight subset of formatting functions.
|
||||||
|
|
||||||
The following functions use :ref:`format string syntax <syntax>`
|
The following functions use :ref:`format string syntax <syntax>`
|
||||||
imilar to that of Python's `str.format
|
similar to that of Python's `str.format
|
||||||
<http://docs.python.org/3/library/stdtypes.html#str.format>`_.
|
<http://docs.python.org/3/library/stdtypes.html#str.format>`_.
|
||||||
They take *format_str* and *args* as arguments.
|
They take *format_str* and *args* as arguments.
|
||||||
|
|
||||||
*format_str* is a format string that contains literal text and replacement
|
*format_str* is a format string that contains literal text and replacement
|
||||||
fields surrounded by braces ``{}``. The fields are replaced with formatted
|
fields surrounded by braces ``{}``. The fields are replaced with formatted
|
||||||
arguments in the resulting string.
|
arguments in the resulting string. A function taking *format_str* doesn't
|
||||||
|
participate in an overload resolution if the latter is not a string.
|
||||||
|
|
||||||
*args* is an argument list representing objects to be formatted.
|
*args* is an argument list representing objects to be formatted.
|
||||||
|
|
||||||
.. _format:
|
.. _format:
|
||||||
|
|
||||||
.. doxygenfunction:: format(const String&, const Args&...)
|
.. doxygenfunction:: format(const S&, const Args&...)
|
||||||
.. doxygenfunction:: vformat(const String&, basic_format_args<typename buffer_context<Char>::type>)
|
.. doxygenfunction:: vformat(const S&, basic_format_args<typename buffer_context<Char>::type>)
|
||||||
|
|
||||||
.. _print:
|
.. _print:
|
||||||
|
|
||||||
.. doxygenfunction:: print(string_view, const Args&...)
|
.. doxygenfunction:: print(const S&, const Args&...)
|
||||||
.. doxygenfunction:: vprint(string_view, format_args)
|
.. doxygenfunction:: vprint(string_view, format_args)
|
||||||
|
|
||||||
.. doxygenfunction:: print(std::FILE *, string_view, const Args&...)
|
.. doxygenfunction:: print(std::FILE *, const S&, const Args&...)
|
||||||
.. doxygenfunction:: vprint(std::FILE *, string_view, format_args)
|
.. doxygenfunction:: vprint(std::FILE *, string_view, format_args)
|
||||||
|
|
||||||
.. doxygenfunction:: print(std::FILE *, wstring_view, const Args&...)
|
|
||||||
.. doxygenfunction:: vprint(std::FILE *, wstring_view, wformat_args)
|
.. doxygenfunction:: vprint(std::FILE *, wstring_view, wformat_args)
|
||||||
|
|
||||||
Named arguments
|
Named arguments
|
||||||
|
@ -149,6 +148,35 @@ You can also reuse existing formatters, for example::
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
You can also write a formatter for a hierarchy of classes::
|
||||||
|
|
||||||
|
#include <type_traits>
|
||||||
|
#include <fmt/format.h>
|
||||||
|
|
||||||
|
struct A {
|
||||||
|
virtual ~A() {}
|
||||||
|
virtual std::string name() const { return "A"; }
|
||||||
|
};
|
||||||
|
|
||||||
|
struct B : A {
|
||||||
|
virtual std::string name() const { return "B"; }
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct fmt::formatter<T, std::enable_if_t<std::is_base_of<A, T>::value, char>> :
|
||||||
|
fmt::formatter<std::string> {
|
||||||
|
template <typename FormatCtx>
|
||||||
|
auto format(const A& a, FormatCtx& ctx) {
|
||||||
|
return fmt::formatter<std::string>::format(a.name(), ctx);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
B b;
|
||||||
|
A& a = b;
|
||||||
|
fmt::print("{}", a); // prints "B"
|
||||||
|
}
|
||||||
|
|
||||||
This section shows how to define a custom format function for a user-defined
|
This section shows how to define a custom format function for a user-defined
|
||||||
type. The next section describes how to get ``fmt`` to use a conventional stream
|
type. The next section describes how to get ``fmt`` to use a conventional stream
|
||||||
output ``operator<<`` when one is defined for a user-defined type.
|
output ``operator<<`` when one is defined for a user-defined type.
|
||||||
|
@ -156,7 +184,7 @@ output ``operator<<`` when one is defined for a user-defined type.
|
||||||
Output iterator support
|
Output iterator support
|
||||||
-----------------------
|
-----------------------
|
||||||
|
|
||||||
.. doxygenfunction:: fmt::format_to(OutputIt, string_view, const Args&...)
|
.. doxygenfunction:: fmt::format_to(OutputIt, const S&, const Args&...)
|
||||||
.. doxygenfunction:: fmt::format_to_n(OutputIt, std::size_t, string_view, const Args&...)
|
.. doxygenfunction:: fmt::format_to_n(OutputIt, std::size_t, string_view, const Args&...)
|
||||||
.. doxygenstruct:: fmt::format_to_n_result
|
.. doxygenstruct:: fmt::format_to_n_result
|
||||||
:members:
|
:members:
|
||||||
|
@ -173,12 +201,16 @@ The following user-defined literals are defined in ``fmt/format.h``.
|
||||||
Utilities
|
Utilities
|
||||||
---------
|
---------
|
||||||
|
|
||||||
|
.. doxygentypedef:: fmt::char_t
|
||||||
|
|
||||||
.. doxygenfunction:: fmt::formatted_size(string_view, const Args&...)
|
.. doxygenfunction:: fmt::formatted_size(string_view, const Args&...)
|
||||||
|
|
||||||
.. doxygenfunction:: fmt::to_string(const T&)
|
.. doxygenfunction:: fmt::to_string(const T&)
|
||||||
|
|
||||||
.. doxygenfunction:: fmt::to_wstring(const T&)
|
.. doxygenfunction:: fmt::to_wstring(const T&)
|
||||||
|
|
||||||
|
.. doxygenfunction:: fmt::to_string_view(basic_string_view<Char>)
|
||||||
|
|
||||||
.. doxygenclass:: fmt::basic_memory_buffer
|
.. doxygenclass:: fmt::basic_memory_buffer
|
||||||
:protected-members:
|
:protected-members:
|
||||||
:members:
|
:members:
|
||||||
|
@ -248,7 +280,8 @@ custom argument formatter class::
|
||||||
// with the ``x`` format specifier.
|
// with the ``x`` format specifier.
|
||||||
class custom_arg_formatter : public arg_formatter {
|
class custom_arg_formatter : public arg_formatter {
|
||||||
public:
|
public:
|
||||||
custom_arg_formatter(fmt::format_context &ctx, fmt::format_specs &spec)
|
custom_arg_formatter(fmt::format_context &ctx,
|
||||||
|
fmt::format_specs *spec = nullptr)
|
||||||
: arg_formatter(ctx, spec) {}
|
: arg_formatter(ctx, spec) {}
|
||||||
|
|
||||||
using arg_formatter::operator();
|
using arg_formatter::operator();
|
||||||
|
@ -319,7 +352,7 @@ user-defined types that have overloaded ``operator<<``::
|
||||||
std::string s = fmt::format("The date is {}", date(2012, 12, 9));
|
std::string s = fmt::format("The date is {}", date(2012, 12, 9));
|
||||||
// s == "The date is 2012-12-9"
|
// s == "The date is 2012-12-9"
|
||||||
|
|
||||||
.. doxygenfunction:: print(std::ostream&, string_view, const Args&...)
|
.. doxygenfunction:: print(std::basic_ostream<fmt::char_t<S>>&, const S&, const Args&...)
|
||||||
|
|
||||||
.. _printf-api:
|
.. _printf-api:
|
||||||
|
|
||||||
|
@ -333,10 +366,10 @@ the POSIX extension for positional arguments. Unlike their standard
|
||||||
counterparts, the ``fmt`` functions are type-safe and throw an exception if an
|
counterparts, the ``fmt`` functions are type-safe and throw an exception if an
|
||||||
argument type doesn't match its format specification.
|
argument type doesn't match its format specification.
|
||||||
|
|
||||||
.. doxygenfunction:: printf(string_view, const Args&...)
|
.. doxygenfunction:: printf(const S&, const Args&...)
|
||||||
|
|
||||||
.. doxygenfunction:: fprintf(std::FILE *, string_view, const Args&...)
|
.. doxygenfunction:: fprintf(std::FILE *, const S&, const Args&...)
|
||||||
|
|
||||||
.. doxygenfunction:: fprintf(std::ostream&, string_view, const Args&...)
|
.. doxygenfunction:: fprintf(std::basic_ostream<fmt::char_t<S>>&, const S&, const Args&...)
|
||||||
|
|
||||||
.. doxygenfunction:: sprintf(string_view, const Args&...)
|
.. doxygenfunction:: sprintf(const S&, const Args&...)
|
||||||
|
|
6
externals/fmt/doc/build.py
vendored
6
externals/fmt/doc/build.py
vendored
|
@ -6,7 +6,7 @@ import errno, os, shutil, sys, tempfile
|
||||||
from subprocess import check_call, check_output, CalledProcessError, Popen, PIPE
|
from subprocess import check_call, check_output, CalledProcessError, Popen, PIPE
|
||||||
from distutils.version import LooseVersion
|
from distutils.version import LooseVersion
|
||||||
|
|
||||||
versions = ['1.0.0', '1.1.0', '2.0.0', '3.0.2', '4.0.0', '4.1.0', '5.0.0', '5.1.0', '5.2.0', '5.2.1']
|
versions = ['1.0.0', '1.1.0', '2.0.0', '3.0.2', '4.0.0', '4.1.0', '5.0.0', '5.1.0', '5.2.0', '5.2.1', '5.3.0']
|
||||||
|
|
||||||
def pip_install(package, commit=None, **kwargs):
|
def pip_install(package, commit=None, **kwargs):
|
||||||
"Install package using pip."
|
"Install package using pip."
|
||||||
|
@ -89,10 +89,12 @@ def build_docs(version='dev', **kwargs):
|
||||||
FMT_USE_VARIADIC_TEMPLATES=1 \
|
FMT_USE_VARIADIC_TEMPLATES=1 \
|
||||||
FMT_USE_RVALUE_REFERENCES=1 \
|
FMT_USE_RVALUE_REFERENCES=1 \
|
||||||
FMT_USE_USER_DEFINED_LITERALS=1 \
|
FMT_USE_USER_DEFINED_LITERALS=1 \
|
||||||
|
FMT_USE_ALIAS_TEMPLATES=1 \
|
||||||
FMT_API= \
|
FMT_API= \
|
||||||
"FMT_BEGIN_NAMESPACE=namespace fmt {{" \
|
"FMT_BEGIN_NAMESPACE=namespace fmt {{" \
|
||||||
"FMT_END_NAMESPACE=}}" \
|
"FMT_END_NAMESPACE=}}" \
|
||||||
"FMT_STRING_ALIAS=1"
|
"FMT_STRING_ALIAS=1" \
|
||||||
|
"FMT_ENABLE_IF_T(B, T)=T"
|
||||||
EXCLUDE_SYMBOLS = fmt::internal::* StringValue write_str
|
EXCLUDE_SYMBOLS = fmt::internal::* StringValue write_str
|
||||||
'''.format(include_dir, doxyxml_dir).encode('UTF-8'))
|
'''.format(include_dir, doxyxml_dir).encode('UTF-8'))
|
||||||
if p.returncode != 0:
|
if p.returncode != 0:
|
||||||
|
|
4
externals/fmt/doc/index.rst
vendored
4
externals/fmt/doc/index.rst
vendored
|
@ -40,7 +40,7 @@ The ``fmt::format`` function returns a string "The answer is 42.". You can use
|
||||||
format_to(out, "For a moment, {} happened.", "nothing");
|
format_to(out, "For a moment, {} happened.", "nothing");
|
||||||
out.data(); // returns a pointer to the formatted data
|
out.data(); // returns a pointer to the formatted data
|
||||||
|
|
||||||
The ``fmt::print`` function performs formatting and writes the result to a file:
|
The ``fmt::print`` function performs formatting and writes the result to a stream:
|
||||||
|
|
||||||
.. code:: c++
|
.. code:: c++
|
||||||
|
|
||||||
|
@ -94,7 +94,7 @@ Safety
|
||||||
|
|
||||||
The library is fully type safe, automatic memory management prevents buffer
|
The library is fully type safe, automatic memory management prevents buffer
|
||||||
overflow, errors in format strings are reported using exceptions or at compile
|
overflow, errors in format strings are reported using exceptions or at compile
|
||||||
tim. For example, the code
|
time. For example, the code
|
||||||
|
|
||||||
.. code:: c++
|
.. code:: c++
|
||||||
|
|
||||||
|
|
9
externals/fmt/doc/usage.rst
vendored
9
externals/fmt/doc/usage.rst
vendored
|
@ -45,7 +45,7 @@ You can control generation of the make ``test`` target with the ``FMT_TEST``
|
||||||
CMake option. This can be useful if you include fmt as a subdirectory in
|
CMake option. This can be useful if you include fmt as a subdirectory in
|
||||||
your project but don't want to add fmt's tests to your ``test`` target.
|
your project but don't want to add fmt's tests to your ``test`` target.
|
||||||
|
|
||||||
If you use Windows and have Visual Studio installed, a :file:`FORMAT.sln`
|
If you use Windows and have Visual Studio installed, a :file:`FMT.sln`
|
||||||
file and several :file:`.vcproj` files will be created. You can then build them
|
file and several :file:`.vcproj` files will be created. You can then build them
|
||||||
using Visual Studio or msbuild.
|
using Visual Studio or msbuild.
|
||||||
|
|
||||||
|
@ -74,7 +74,12 @@ or
|
||||||
|
|
||||||
to exclude it from ``make``, ``make all``, or ``cmake --build .``.
|
to exclude it from ``make``, ``make all``, or ``cmake --build .``.
|
||||||
|
|
||||||
Settting up your target to use a header-only version of ``fmt`` is equaly easy::
|
You can detect and use an installed version of {fmt} as follows::
|
||||||
|
|
||||||
|
find_package(fmt)
|
||||||
|
target_link_libraries(<your-target> fmt::fmt)
|
||||||
|
|
||||||
|
Setting up your target to use a header-only version of ``fmt`` is equaly easy::
|
||||||
|
|
||||||
target_link_libraries(<your-target> PRIVATE fmt-header-only)
|
target_link_libraries(<your-target> PRIVATE fmt-header-only)
|
||||||
|
|
||||||
|
|
452
externals/fmt/include/fmt/chrono.h
vendored
Normal file
452
externals/fmt/include/fmt/chrono.h
vendored
Normal file
|
@ -0,0 +1,452 @@
|
||||||
|
// Formatting library for C++ - chrono support
|
||||||
|
//
|
||||||
|
// Copyright (c) 2012 - present, Victor Zverovich
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// For the license information refer to format.h.
|
||||||
|
|
||||||
|
#ifndef FMT_CHRONO_H_
|
||||||
|
#define FMT_CHRONO_H_
|
||||||
|
|
||||||
|
#include "format.h"
|
||||||
|
#include "locale.h"
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
#include <ctime>
|
||||||
|
#include <locale>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
FMT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
|
namespace internal{
|
||||||
|
|
||||||
|
enum class numeric_system {
|
||||||
|
standard,
|
||||||
|
// Alternative numeric system, e.g. 十二 instead of 12 in ja_JP locale.
|
||||||
|
alternative
|
||||||
|
};
|
||||||
|
|
||||||
|
// Parses a put_time-like format string and invokes handler actions.
|
||||||
|
template <typename Char, typename Handler>
|
||||||
|
FMT_CONSTEXPR const Char *parse_chrono_format(
|
||||||
|
const Char *begin, const Char *end, Handler &&handler) {
|
||||||
|
auto ptr = begin;
|
||||||
|
while (ptr != end) {
|
||||||
|
auto c = *ptr;
|
||||||
|
if (c == '}') break;
|
||||||
|
if (c != '%') {
|
||||||
|
++ptr;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (begin != ptr)
|
||||||
|
handler.on_text(begin, ptr);
|
||||||
|
++ptr; // consume '%'
|
||||||
|
if (ptr == end)
|
||||||
|
throw format_error("invalid format");
|
||||||
|
c = *ptr++;
|
||||||
|
switch (c) {
|
||||||
|
case '%':
|
||||||
|
handler.on_text(ptr - 1, ptr);
|
||||||
|
break;
|
||||||
|
case 'n': {
|
||||||
|
const char newline[] = "\n";
|
||||||
|
handler.on_text(newline, newline + 1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 't': {
|
||||||
|
const char tab[] = "\t";
|
||||||
|
handler.on_text(tab, tab + 1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// Day of the week:
|
||||||
|
case 'a':
|
||||||
|
handler.on_abbr_weekday();
|
||||||
|
break;
|
||||||
|
case 'A':
|
||||||
|
handler.on_full_weekday();
|
||||||
|
break;
|
||||||
|
case 'w':
|
||||||
|
handler.on_dec0_weekday(numeric_system::standard);
|
||||||
|
break;
|
||||||
|
case 'u':
|
||||||
|
handler.on_dec1_weekday(numeric_system::standard);
|
||||||
|
break;
|
||||||
|
// Month:
|
||||||
|
case 'b':
|
||||||
|
handler.on_abbr_month();
|
||||||
|
break;
|
||||||
|
case 'B':
|
||||||
|
handler.on_full_month();
|
||||||
|
break;
|
||||||
|
// Hour, minute, second:
|
||||||
|
case 'H':
|
||||||
|
handler.on_24_hour(numeric_system::standard);
|
||||||
|
break;
|
||||||
|
case 'I':
|
||||||
|
handler.on_12_hour(numeric_system::standard);
|
||||||
|
break;
|
||||||
|
case 'M':
|
||||||
|
handler.on_minute(numeric_system::standard);
|
||||||
|
break;
|
||||||
|
case 'S':
|
||||||
|
handler.on_second(numeric_system::standard);
|
||||||
|
break;
|
||||||
|
// Other:
|
||||||
|
case 'c':
|
||||||
|
handler.on_datetime(numeric_system::standard);
|
||||||
|
break;
|
||||||
|
case 'x':
|
||||||
|
handler.on_loc_date(numeric_system::standard);
|
||||||
|
break;
|
||||||
|
case 'X':
|
||||||
|
handler.on_loc_time(numeric_system::standard);
|
||||||
|
break;
|
||||||
|
case 'D':
|
||||||
|
handler.on_us_date();
|
||||||
|
break;
|
||||||
|
case 'F':
|
||||||
|
handler.on_iso_date();
|
||||||
|
break;
|
||||||
|
case 'r':
|
||||||
|
handler.on_12_hour_time();
|
||||||
|
break;
|
||||||
|
case 'R':
|
||||||
|
handler.on_24_hour_time();
|
||||||
|
break;
|
||||||
|
case 'T':
|
||||||
|
handler.on_iso_time();
|
||||||
|
break;
|
||||||
|
case 'p':
|
||||||
|
handler.on_am_pm();
|
||||||
|
break;
|
||||||
|
case 'z':
|
||||||
|
handler.on_utc_offset();
|
||||||
|
break;
|
||||||
|
case 'Z':
|
||||||
|
handler.on_tz_name();
|
||||||
|
break;
|
||||||
|
// Alternative representation:
|
||||||
|
case 'E': {
|
||||||
|
if (ptr == end)
|
||||||
|
throw format_error("invalid format");
|
||||||
|
c = *ptr++;
|
||||||
|
switch (c) {
|
||||||
|
case 'c':
|
||||||
|
handler.on_datetime(numeric_system::alternative);
|
||||||
|
break;
|
||||||
|
case 'x':
|
||||||
|
handler.on_loc_date(numeric_system::alternative);
|
||||||
|
break;
|
||||||
|
case 'X':
|
||||||
|
handler.on_loc_time(numeric_system::alternative);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw format_error("invalid format");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'O':
|
||||||
|
if (ptr == end)
|
||||||
|
throw format_error("invalid format");
|
||||||
|
c = *ptr++;
|
||||||
|
switch (c) {
|
||||||
|
case 'w':
|
||||||
|
handler.on_dec0_weekday(numeric_system::alternative);
|
||||||
|
break;
|
||||||
|
case 'u':
|
||||||
|
handler.on_dec1_weekday(numeric_system::alternative);
|
||||||
|
break;
|
||||||
|
case 'H':
|
||||||
|
handler.on_24_hour(numeric_system::alternative);
|
||||||
|
break;
|
||||||
|
case 'I':
|
||||||
|
handler.on_12_hour(numeric_system::alternative);
|
||||||
|
break;
|
||||||
|
case 'M':
|
||||||
|
handler.on_minute(numeric_system::alternative);
|
||||||
|
break;
|
||||||
|
case 'S':
|
||||||
|
handler.on_second(numeric_system::alternative);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw format_error("invalid format");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw format_error("invalid format");
|
||||||
|
}
|
||||||
|
begin = ptr;
|
||||||
|
}
|
||||||
|
if (begin != ptr)
|
||||||
|
handler.on_text(begin, ptr);
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct chrono_format_checker {
|
||||||
|
void report_no_date() { throw format_error("no date"); }
|
||||||
|
|
||||||
|
template <typename Char>
|
||||||
|
void on_text(const Char *, const Char *) {}
|
||||||
|
void on_abbr_weekday() { report_no_date(); }
|
||||||
|
void on_full_weekday() { report_no_date(); }
|
||||||
|
void on_dec0_weekday(numeric_system) { report_no_date(); }
|
||||||
|
void on_dec1_weekday(numeric_system) { report_no_date(); }
|
||||||
|
void on_abbr_month() { report_no_date(); }
|
||||||
|
void on_full_month() { report_no_date(); }
|
||||||
|
void on_24_hour(numeric_system) {}
|
||||||
|
void on_12_hour(numeric_system) {}
|
||||||
|
void on_minute(numeric_system) {}
|
||||||
|
void on_second(numeric_system) {}
|
||||||
|
void on_datetime(numeric_system) { report_no_date(); }
|
||||||
|
void on_loc_date(numeric_system) { report_no_date(); }
|
||||||
|
void on_loc_time(numeric_system) { report_no_date(); }
|
||||||
|
void on_us_date() { report_no_date(); }
|
||||||
|
void on_iso_date() { report_no_date(); }
|
||||||
|
void on_12_hour_time() {}
|
||||||
|
void on_24_hour_time() {}
|
||||||
|
void on_iso_time() {}
|
||||||
|
void on_am_pm() {}
|
||||||
|
void on_utc_offset() { report_no_date(); }
|
||||||
|
void on_tz_name() { report_no_date(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Int>
|
||||||
|
inline int to_int(Int value) {
|
||||||
|
FMT_ASSERT(value >= (std::numeric_limits<int>::min)() &&
|
||||||
|
value <= (std::numeric_limits<int>::max)(), "invalid value");
|
||||||
|
return static_cast<int>(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename FormatContext, typename OutputIt>
|
||||||
|
struct chrono_formatter {
|
||||||
|
FormatContext &context;
|
||||||
|
OutputIt out;
|
||||||
|
std::chrono::seconds s;
|
||||||
|
std::chrono::milliseconds ms;
|
||||||
|
|
||||||
|
typedef typename FormatContext::char_type char_type;
|
||||||
|
|
||||||
|
explicit chrono_formatter(FormatContext &ctx, OutputIt o)
|
||||||
|
: context(ctx), out(o) {}
|
||||||
|
|
||||||
|
int hour() const { return to_int((s.count() / 3600) % 24); }
|
||||||
|
|
||||||
|
int hour12() const {
|
||||||
|
auto hour = to_int((s.count() / 3600) % 12);
|
||||||
|
return hour > 0 ? hour : 12;
|
||||||
|
}
|
||||||
|
|
||||||
|
int minute() const { return to_int((s.count() / 60) % 60); }
|
||||||
|
int second() const { return to_int(s.count() % 60); }
|
||||||
|
|
||||||
|
std::tm time() const {
|
||||||
|
auto time = std::tm();
|
||||||
|
time.tm_hour = hour();
|
||||||
|
time.tm_min = minute();
|
||||||
|
time.tm_sec = second();
|
||||||
|
return time;
|
||||||
|
}
|
||||||
|
|
||||||
|
void write(int value, int width) {
|
||||||
|
typedef typename int_traits<int>::main_type main_type;
|
||||||
|
main_type n = to_unsigned(value);
|
||||||
|
int num_digits = internal::count_digits(n);
|
||||||
|
if (width > num_digits)
|
||||||
|
out = std::fill_n(out, width - num_digits, '0');
|
||||||
|
out = format_decimal<char_type>(out, n, num_digits);
|
||||||
|
}
|
||||||
|
|
||||||
|
void format_localized(const tm &time, const char *format) {
|
||||||
|
auto locale = context.locale().template get<std::locale>();
|
||||||
|
auto &facet = std::use_facet<std::time_put<char_type>>(locale);
|
||||||
|
std::basic_ostringstream<char_type> os;
|
||||||
|
os.imbue(locale);
|
||||||
|
facet.put(os, os, ' ', &time, format, format + std::strlen(format));
|
||||||
|
auto str = os.str();
|
||||||
|
std::copy(str.begin(), str.end(), out);
|
||||||
|
}
|
||||||
|
|
||||||
|
void on_text(const char_type *begin, const char_type *end) {
|
||||||
|
std::copy(begin, end, out);
|
||||||
|
}
|
||||||
|
|
||||||
|
// These are not implemented because durations don't have date information.
|
||||||
|
void on_abbr_weekday() {}
|
||||||
|
void on_full_weekday() {}
|
||||||
|
void on_dec0_weekday(numeric_system) {}
|
||||||
|
void on_dec1_weekday(numeric_system) {}
|
||||||
|
void on_abbr_month() {}
|
||||||
|
void on_full_month() {}
|
||||||
|
void on_datetime(numeric_system) {}
|
||||||
|
void on_loc_date(numeric_system) {}
|
||||||
|
void on_loc_time(numeric_system) {}
|
||||||
|
void on_us_date() {}
|
||||||
|
void on_iso_date() {}
|
||||||
|
void on_utc_offset() {}
|
||||||
|
void on_tz_name() {}
|
||||||
|
|
||||||
|
void on_24_hour(numeric_system ns) {
|
||||||
|
if (ns == numeric_system::standard)
|
||||||
|
return write(hour(), 2);
|
||||||
|
auto time = tm();
|
||||||
|
time.tm_hour = hour();
|
||||||
|
format_localized(time, "%OH");
|
||||||
|
}
|
||||||
|
|
||||||
|
void on_12_hour(numeric_system ns) {
|
||||||
|
if (ns == numeric_system::standard)
|
||||||
|
return write(hour12(), 2);
|
||||||
|
auto time = tm();
|
||||||
|
time.tm_hour = hour();
|
||||||
|
format_localized(time, "%OI");
|
||||||
|
}
|
||||||
|
|
||||||
|
void on_minute(numeric_system ns) {
|
||||||
|
if (ns == numeric_system::standard)
|
||||||
|
return write(minute(), 2);
|
||||||
|
auto time = tm();
|
||||||
|
time.tm_min = minute();
|
||||||
|
format_localized(time, "%OM");
|
||||||
|
}
|
||||||
|
|
||||||
|
void on_second(numeric_system ns) {
|
||||||
|
if (ns == numeric_system::standard) {
|
||||||
|
write(second(), 2);
|
||||||
|
if (ms != std::chrono::milliseconds(0)) {
|
||||||
|
*out++ = '.';
|
||||||
|
write(to_int(ms.count()), 3);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto time = tm();
|
||||||
|
time.tm_sec = second();
|
||||||
|
format_localized(time, "%OS");
|
||||||
|
}
|
||||||
|
|
||||||
|
void on_12_hour_time() { format_localized(time(), "%r"); }
|
||||||
|
|
||||||
|
void on_24_hour_time() {
|
||||||
|
write(hour(), 2);
|
||||||
|
*out++ = ':';
|
||||||
|
write(minute(), 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void on_iso_time() {
|
||||||
|
on_24_hour_time();
|
||||||
|
*out++ = ':';
|
||||||
|
write(second(), 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void on_am_pm() { format_localized(time(), "%p"); }
|
||||||
|
};
|
||||||
|
} // namespace internal
|
||||||
|
|
||||||
|
template <typename Period> FMT_CONSTEXPR const char *get_units() {
|
||||||
|
return FMT_NULL;
|
||||||
|
}
|
||||||
|
template <> FMT_CONSTEXPR const char *get_units<std::atto>() { return "as"; }
|
||||||
|
template <> FMT_CONSTEXPR const char *get_units<std::femto>() { return "fs"; }
|
||||||
|
template <> FMT_CONSTEXPR const char *get_units<std::pico>() { return "ps"; }
|
||||||
|
template <> FMT_CONSTEXPR const char *get_units<std::nano>() { return "ns"; }
|
||||||
|
template <> FMT_CONSTEXPR const char *get_units<std::micro>() { return "µs"; }
|
||||||
|
template <> FMT_CONSTEXPR const char *get_units<std::milli>() { return "ms"; }
|
||||||
|
template <> FMT_CONSTEXPR const char *get_units<std::centi>() { return "cs"; }
|
||||||
|
template <> FMT_CONSTEXPR const char *get_units<std::deci>() { return "ds"; }
|
||||||
|
template <> FMT_CONSTEXPR const char *get_units<std::ratio<1>>() { return "s"; }
|
||||||
|
template <> FMT_CONSTEXPR const char *get_units<std::deca>() { return "das"; }
|
||||||
|
template <> FMT_CONSTEXPR const char *get_units<std::hecto>() { return "hs"; }
|
||||||
|
template <> FMT_CONSTEXPR const char *get_units<std::kilo>() { return "ks"; }
|
||||||
|
template <> FMT_CONSTEXPR const char *get_units<std::mega>() { return "Ms"; }
|
||||||
|
template <> FMT_CONSTEXPR const char *get_units<std::giga>() { return "Gs"; }
|
||||||
|
template <> FMT_CONSTEXPR const char *get_units<std::tera>() { return "Ts"; }
|
||||||
|
template <> FMT_CONSTEXPR const char *get_units<std::peta>() { return "Ps"; }
|
||||||
|
template <> FMT_CONSTEXPR const char *get_units<std::exa>() { return "Es"; }
|
||||||
|
template <> FMT_CONSTEXPR const char *get_units<std::ratio<60>>() {
|
||||||
|
return "m";
|
||||||
|
}
|
||||||
|
template <> FMT_CONSTEXPR const char *get_units<std::ratio<3600>>() {
|
||||||
|
return "h";
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Rep, typename Period, typename Char>
|
||||||
|
struct formatter<std::chrono::duration<Rep, Period>, Char> {
|
||||||
|
private:
|
||||||
|
align_spec spec;
|
||||||
|
internal::arg_ref<Char> width_ref;
|
||||||
|
mutable basic_string_view<Char> format_str;
|
||||||
|
typedef std::chrono::duration<Rep, Period> duration;
|
||||||
|
|
||||||
|
struct spec_handler {
|
||||||
|
formatter &f;
|
||||||
|
basic_parse_context<Char> &context;
|
||||||
|
|
||||||
|
typedef internal::arg_ref<Char> arg_ref_type;
|
||||||
|
|
||||||
|
template <typename Id>
|
||||||
|
FMT_CONSTEXPR arg_ref_type make_arg_ref(Id arg_id) {
|
||||||
|
context.check_arg_id(arg_id);
|
||||||
|
return arg_ref_type(arg_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
FMT_CONSTEXPR arg_ref_type make_arg_ref(internal::auto_id) {
|
||||||
|
return arg_ref_type(context.next_arg_id());
|
||||||
|
}
|
||||||
|
|
||||||
|
void on_error(const char *msg) { throw format_error(msg); }
|
||||||
|
void on_fill(Char fill) { f.spec.fill_ = fill; }
|
||||||
|
void on_align(alignment align) { f.spec.align_ = align; }
|
||||||
|
void on_width(unsigned width) { f.spec.width_ = width; }
|
||||||
|
|
||||||
|
template <typename Id>
|
||||||
|
void on_dynamic_width(Id arg_id) {
|
||||||
|
f.width_ref = make_arg_ref(arg_id);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
formatter() : spec() {}
|
||||||
|
|
||||||
|
FMT_CONSTEXPR auto parse(basic_parse_context<Char> &ctx)
|
||||||
|
-> decltype(ctx.begin()) {
|
||||||
|
auto begin = ctx.begin(), end = ctx.end();
|
||||||
|
if (begin == end) return begin;
|
||||||
|
spec_handler handler{*this, ctx};
|
||||||
|
begin = internal::parse_align(begin, end, handler);
|
||||||
|
if (begin == end) return begin;
|
||||||
|
begin = internal::parse_width(begin, end, handler);
|
||||||
|
end = parse_chrono_format(begin, end, internal::chrono_format_checker());
|
||||||
|
format_str = basic_string_view<Char>(&*begin, internal::to_unsigned(end - begin));
|
||||||
|
return end;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename FormatContext>
|
||||||
|
auto format(const duration &d, FormatContext &ctx)
|
||||||
|
-> decltype(ctx.out()) {
|
||||||
|
auto begin = format_str.begin(), end = format_str.end();
|
||||||
|
memory_buffer buf;
|
||||||
|
typedef output_range<decltype(ctx.out()), Char> range;
|
||||||
|
basic_writer<range> w(range(ctx.out()));
|
||||||
|
if (begin == end || *begin == '}') {
|
||||||
|
if (const char *unit = get_units<Period>())
|
||||||
|
format_to(buf, "{}{}", d.count(), unit);
|
||||||
|
else if (Period::den == 1)
|
||||||
|
format_to(buf, "{}[{}]s", d.count(), Period::num);
|
||||||
|
else
|
||||||
|
format_to(buf, "{}[{}/{}]s", d.count(), Period::num, Period::den);
|
||||||
|
internal::handle_dynamic_spec<internal::width_checker>(
|
||||||
|
spec.width_, width_ref, ctx);
|
||||||
|
} else {
|
||||||
|
auto out = std::back_inserter(buf);
|
||||||
|
internal::chrono_formatter<FormatContext, decltype(out)> f(ctx, out);
|
||||||
|
f.s = std::chrono::duration_cast<std::chrono::seconds>(d);
|
||||||
|
f.ms = std::chrono::duration_cast<std::chrono::milliseconds>(d - f.s);
|
||||||
|
parse_chrono_format(begin, end, f);
|
||||||
|
}
|
||||||
|
w.write(buf.data(), buf.size(), spec);
|
||||||
|
return w.out();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
FMT_END_NAMESPACE
|
||||||
|
|
||||||
|
#endif // FMT_CHRONO_H_
|
407
externals/fmt/include/fmt/color.h
vendored
407
externals/fmt/include/fmt/color.h
vendored
|
@ -47,7 +47,6 @@ inline void vprint_colored(color c, wstring_view format, wformat_args args) {
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
// Experimental color support.
|
|
||||||
enum class color : uint32_t {
|
enum class color : uint32_t {
|
||||||
alice_blue = 0xF0F8FF, // rgb(240,248,255)
|
alice_blue = 0xF0F8FF, // rgb(240,248,255)
|
||||||
antique_white = 0xFAEBD7, // rgb(250,235,215)
|
antique_white = 0xFAEBD7, // rgb(250,235,215)
|
||||||
|
@ -189,9 +188,35 @@ enum class color : uint32_t {
|
||||||
white = 0xFFFFFF, // rgb(255,255,255)
|
white = 0xFFFFFF, // rgb(255,255,255)
|
||||||
white_smoke = 0xF5F5F5, // rgb(245,245,245)
|
white_smoke = 0xF5F5F5, // rgb(245,245,245)
|
||||||
yellow = 0xFFFF00, // rgb(255,255,0)
|
yellow = 0xFFFF00, // rgb(255,255,0)
|
||||||
yellow_green = 0x9ACD32, // rgb(154,205,50)
|
yellow_green = 0x9ACD32 // rgb(154,205,50)
|
||||||
}; // enum class color
|
}; // enum class color
|
||||||
|
|
||||||
|
enum class terminal_color : uint8_t {
|
||||||
|
black = 30,
|
||||||
|
red,
|
||||||
|
green,
|
||||||
|
yellow,
|
||||||
|
blue,
|
||||||
|
magenta,
|
||||||
|
cyan,
|
||||||
|
white,
|
||||||
|
bright_black = 90,
|
||||||
|
bright_red,
|
||||||
|
bright_green,
|
||||||
|
bright_yellow,
|
||||||
|
bright_blue,
|
||||||
|
bright_magenta,
|
||||||
|
bright_cyan,
|
||||||
|
bright_white
|
||||||
|
}; // enum class terminal_color
|
||||||
|
|
||||||
|
enum class emphasis : uint8_t {
|
||||||
|
bold = 1,
|
||||||
|
italic = 1 << 1,
|
||||||
|
underline = 1 << 2,
|
||||||
|
strikethrough = 1 << 3
|
||||||
|
}; // enum class emphasis
|
||||||
|
|
||||||
// rgb is a struct for red, green and blue colors.
|
// rgb is a struct for red, green and blue colors.
|
||||||
// We use rgb as name because some editors will show it as color direct in the
|
// We use rgb as name because some editors will show it as color direct in the
|
||||||
// editor.
|
// editor.
|
||||||
|
@ -209,66 +234,340 @@ struct rgb {
|
||||||
uint8_t b;
|
uint8_t b;
|
||||||
};
|
};
|
||||||
|
|
||||||
void vprint_rgb(rgb fd, string_view format, format_args args);
|
|
||||||
void vprint_rgb(rgb fd, rgb bg, string_view format, format_args args);
|
|
||||||
|
|
||||||
/**
|
|
||||||
Formats a string and prints it to stdout using ANSI escape sequences to
|
|
||||||
specify foreground color 'fd'.
|
|
||||||
Example:
|
|
||||||
fmt::print(fmt::color::red, "Elapsed time: {0:.2f} seconds", 1.23);
|
|
||||||
*/
|
|
||||||
template <typename... Args>
|
|
||||||
inline void print(rgb fd, string_view format_str, const Args & ... args) {
|
|
||||||
vprint_rgb(fd, format_str, make_format_args(args...));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Formats a string and prints it to stdout using ANSI escape sequences to
|
|
||||||
specify foreground color 'fd' and background color 'bg'.
|
|
||||||
Example:
|
|
||||||
fmt::print(fmt::color::red, fmt::color::black,
|
|
||||||
"Elapsed time: {0:.2f} seconds", 1.23);
|
|
||||||
*/
|
|
||||||
template <typename... Args>
|
|
||||||
inline void print(rgb fd, rgb bg, string_view format_str,
|
|
||||||
const Args & ... args) {
|
|
||||||
vprint_rgb(fd, bg, format_str, make_format_args(args...));
|
|
||||||
}
|
|
||||||
namespace internal {
|
namespace internal {
|
||||||
FMT_CONSTEXPR void to_esc(uint8_t c, char out[], int offset) {
|
|
||||||
out[offset + 0] = static_cast<char>('0' + c / 100);
|
// color is a struct of either a rgb color or a terminal color.
|
||||||
out[offset + 1] = static_cast<char>('0' + c / 10 % 10);
|
struct color_type {
|
||||||
out[offset + 2] = static_cast<char>('0' + c % 10);
|
FMT_CONSTEXPR color_type() FMT_NOEXCEPT
|
||||||
}
|
: is_rgb(), value{} {}
|
||||||
|
FMT_CONSTEXPR color_type(color rgb_color) FMT_NOEXCEPT
|
||||||
|
: is_rgb(true), value{} {
|
||||||
|
value.rgb_color = static_cast<uint32_t>(rgb_color);
|
||||||
|
}
|
||||||
|
FMT_CONSTEXPR color_type(rgb rgb_color) FMT_NOEXCEPT
|
||||||
|
: is_rgb(true), value{} {
|
||||||
|
value.rgb_color = (static_cast<uint32_t>(rgb_color.r) << 16)
|
||||||
|
| (static_cast<uint32_t>(rgb_color.g) << 8) | rgb_color.b;
|
||||||
|
}
|
||||||
|
FMT_CONSTEXPR color_type(terminal_color term_color) FMT_NOEXCEPT
|
||||||
|
: is_rgb(), value{} {
|
||||||
|
value.term_color = static_cast<uint8_t>(term_color);
|
||||||
|
}
|
||||||
|
bool is_rgb;
|
||||||
|
union color_union {
|
||||||
|
uint8_t term_color;
|
||||||
|
uint32_t rgb_color;
|
||||||
|
} value;
|
||||||
|
};
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
|
|
||||||
inline void vprint_rgb(rgb fd, string_view format, format_args args) {
|
// Experimental text formatting support.
|
||||||
char escape_fd[] = "\x1b[38;2;000;000;000m";
|
class text_style {
|
||||||
internal::to_esc(fd.r, escape_fd, 7);
|
public:
|
||||||
internal::to_esc(fd.g, escape_fd, 11);
|
FMT_CONSTEXPR text_style(emphasis em = emphasis()) FMT_NOEXCEPT
|
||||||
internal::to_esc(fd.b, escape_fd, 15);
|
: set_foreground_color(), set_background_color(), ems(em) {}
|
||||||
|
|
||||||
std::fputs(escape_fd, stdout);
|
FMT_CONSTEXPR text_style &operator|=(const text_style &rhs) {
|
||||||
vprint(format, args);
|
if (!set_foreground_color) {
|
||||||
std::fputs(internal::data::RESET_COLOR, stdout);
|
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)
|
||||||
|
throw format_error("can't OR a terminal color");
|
||||||
|
foreground_color.value.rgb_color |= rhs.foreground_color.value.rgb_color;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!set_background_color) {
|
||||||
|
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)
|
||||||
|
throw format_error("can't OR 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
|
||||||
|
text_style operator|(text_style lhs, const text_style &rhs) {
|
||||||
|
return lhs |= rhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
FMT_CONSTEXPR text_style &operator&=(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)
|
||||||
|
throw format_error("can't AND a terminal color");
|
||||||
|
foreground_color.value.rgb_color &= rhs.foreground_color.value.rgb_color;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!set_background_color) {
|
||||||
|
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)
|
||||||
|
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
|
||||||
|
text_style operator&(text_style lhs, const text_style &rhs) {
|
||||||
|
return lhs &= rhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
FMT_CONSTEXPR bool has_foreground() const FMT_NOEXCEPT {
|
||||||
|
return set_foreground_color;
|
||||||
|
}
|
||||||
|
FMT_CONSTEXPR bool has_background() const FMT_NOEXCEPT {
|
||||||
|
return set_background_color;
|
||||||
|
}
|
||||||
|
FMT_CONSTEXPR bool has_emphasis() const FMT_NOEXCEPT {
|
||||||
|
return static_cast<uint8_t>(ems) != 0;
|
||||||
|
}
|
||||||
|
FMT_CONSTEXPR internal::color_type get_foreground() const FMT_NOEXCEPT {
|
||||||
|
assert(has_foreground() && "no foreground specified for this style");
|
||||||
|
return foreground_color;
|
||||||
|
}
|
||||||
|
FMT_CONSTEXPR internal::color_type get_background() const FMT_NOEXCEPT {
|
||||||
|
assert(has_background() && "no background specified for this style");
|
||||||
|
return background_color;
|
||||||
|
}
|
||||||
|
FMT_CONSTEXPR emphasis get_emphasis() const FMT_NOEXCEPT {
|
||||||
|
assert(has_emphasis() && "no emphasis specified for this style");
|
||||||
|
return ems;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
FMT_CONSTEXPR text_style(bool is_foreground,
|
||||||
|
internal::color_type text_color) FMT_NOEXCEPT
|
||||||
|
: set_foreground_color(),
|
||||||
|
set_background_color(),
|
||||||
|
ems() {
|
||||||
|
if (is_foreground) {
|
||||||
|
foreground_color = text_color;
|
||||||
|
set_foreground_color = true;
|
||||||
|
} else {
|
||||||
|
background_color = text_color;
|
||||||
|
set_background_color = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
friend FMT_CONSTEXPR_DECL text_style fg(internal::color_type foreground)
|
||||||
|
FMT_NOEXCEPT;
|
||||||
|
friend FMT_CONSTEXPR_DECL text_style bg(internal::color_type background)
|
||||||
|
FMT_NOEXCEPT;
|
||||||
|
|
||||||
|
internal::color_type foreground_color;
|
||||||
|
internal::color_type background_color;
|
||||||
|
bool set_foreground_color;
|
||||||
|
bool set_background_color;
|
||||||
|
emphasis ems;
|
||||||
|
};
|
||||||
|
|
||||||
|
FMT_CONSTEXPR text_style fg(internal::color_type foreground) FMT_NOEXCEPT {
|
||||||
|
return text_style(/*is_foreground=*/true, foreground);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void vprint_rgb(rgb fd, rgb bg, string_view format, format_args args) {
|
FMT_CONSTEXPR text_style bg(internal::color_type background) FMT_NOEXCEPT {
|
||||||
char escape_fd[] = "\x1b[38;2;000;000;000m"; // foreground color
|
return text_style(/*is_foreground=*/false, background);
|
||||||
char escape_bg[] = "\x1b[48;2;000;000;000m"; // background color
|
}
|
||||||
internal::to_esc(fd.r, escape_fd, 7);
|
|
||||||
internal::to_esc(fd.g, escape_fd, 11);
|
|
||||||
internal::to_esc(fd.b, escape_fd, 15);
|
|
||||||
|
|
||||||
internal::to_esc(bg.r, escape_bg, 7);
|
FMT_CONSTEXPR text_style operator|(emphasis lhs, emphasis rhs) FMT_NOEXCEPT {
|
||||||
internal::to_esc(bg.g, escape_bg, 11);
|
return text_style(lhs) | rhs;
|
||||||
internal::to_esc(bg.b, escape_bg, 15);
|
}
|
||||||
|
|
||||||
std::fputs(escape_fd, stdout);
|
namespace internal {
|
||||||
std::fputs(escape_bg, stdout);
|
|
||||||
vprint(format, args);
|
template <typename Char>
|
||||||
std::fputs(internal::data::RESET_COLOR, stdout);
|
struct ansi_color_escape {
|
||||||
|
FMT_CONSTEXPR ansi_color_escape(internal::color_type text_color,
|
||||||
|
const char * esc) FMT_NOEXCEPT {
|
||||||
|
// If we have a terminal color, we need to output another escape code
|
||||||
|
// sequence.
|
||||||
|
if (!text_color.is_rgb) {
|
||||||
|
bool is_background = esc == internal::data::BACKGROUND_COLOR;
|
||||||
|
uint32_t value = text_color.value.term_color;
|
||||||
|
// Background ASCII codes are the same as the foreground ones but with
|
||||||
|
// 10 more.
|
||||||
|
if (is_background)
|
||||||
|
value += 10u;
|
||||||
|
|
||||||
|
std::size_t index = 0;
|
||||||
|
buffer[index++] = static_cast<Char>('\x1b');
|
||||||
|
buffer[index++] = static_cast<Char>('[');
|
||||||
|
|
||||||
|
if (value >= 100u) {
|
||||||
|
buffer[index++] = static_cast<Char>('1');
|
||||||
|
value %= 100u;
|
||||||
|
}
|
||||||
|
buffer[index++] = static_cast<Char>('0' + value / 10u);
|
||||||
|
buffer[index++] = static_cast<Char>('0' + value % 10u);
|
||||||
|
|
||||||
|
buffer[index++] = static_cast<Char>('m');
|
||||||
|
buffer[index++] = static_cast<Char>('\0');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < 7; i++) {
|
||||||
|
buffer[i] = static_cast<Char>(esc[i]);
|
||||||
|
}
|
||||||
|
rgb color(text_color.value.rgb_color);
|
||||||
|
to_esc(color.r, buffer + 7, ';');
|
||||||
|
to_esc(color.g, buffer + 11, ';');
|
||||||
|
to_esc(color.b, buffer + 15, 'm');
|
||||||
|
buffer[19] = static_cast<Char>(0);
|
||||||
|
}
|
||||||
|
FMT_CONSTEXPR ansi_color_escape(emphasis em) FMT_NOEXCEPT {
|
||||||
|
uint8_t em_codes[4] = {};
|
||||||
|
uint8_t em_bits = static_cast<uint8_t>(em);
|
||||||
|
if (em_bits & static_cast<uint8_t>(emphasis::bold))
|
||||||
|
em_codes[0] = 1;
|
||||||
|
if (em_bits & static_cast<uint8_t>(emphasis::italic))
|
||||||
|
em_codes[1] = 3;
|
||||||
|
if (em_bits & static_cast<uint8_t>(emphasis::underline))
|
||||||
|
em_codes[2] = 4;
|
||||||
|
if (em_bits & static_cast<uint8_t>(emphasis::strikethrough))
|
||||||
|
em_codes[3] = 9;
|
||||||
|
|
||||||
|
std::size_t index = 0;
|
||||||
|
for (int i = 0; i < 4; ++i) {
|
||||||
|
if (!em_codes[i])
|
||||||
|
continue;
|
||||||
|
buffer[index++] = static_cast<Char>('\x1b');
|
||||||
|
buffer[index++] = static_cast<Char>('[');
|
||||||
|
buffer[index++] = static_cast<Char>('0' + em_codes[i]);
|
||||||
|
buffer[index++] = static_cast<Char>('m');
|
||||||
|
}
|
||||||
|
buffer[index++] = static_cast<Char>(0);
|
||||||
|
}
|
||||||
|
FMT_CONSTEXPR operator const Char *() const FMT_NOEXCEPT { return buffer; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
Char buffer[7u + 3u * 4u + 1u];
|
||||||
|
|
||||||
|
static FMT_CONSTEXPR void to_esc(uint8_t c, Char *out,
|
||||||
|
char delimiter) FMT_NOEXCEPT {
|
||||||
|
out[0] = static_cast<Char>('0' + c / 100);
|
||||||
|
out[1] = static_cast<Char>('0' + c / 10 % 10);
|
||||||
|
out[2] = static_cast<Char>('0' + c % 10);
|
||||||
|
out[3] = static_cast<Char>(delimiter);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Char>
|
||||||
|
FMT_CONSTEXPR ansi_color_escape<Char>
|
||||||
|
make_foreground_color(internal::color_type foreground) FMT_NOEXCEPT {
|
||||||
|
return ansi_color_escape<Char>(foreground, internal::data::FOREGROUND_COLOR);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Char>
|
||||||
|
FMT_CONSTEXPR ansi_color_escape<Char>
|
||||||
|
make_background_color(internal::color_type background) FMT_NOEXCEPT {
|
||||||
|
return ansi_color_escape<Char>(background, internal::data::BACKGROUND_COLOR);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Char>
|
||||||
|
FMT_CONSTEXPR ansi_color_escape<Char>
|
||||||
|
make_emphasis(emphasis em) FMT_NOEXCEPT {
|
||||||
|
return ansi_color_escape<Char>(em);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Char>
|
||||||
|
inline void fputs(const Char *chars, FILE *stream) FMT_NOEXCEPT {
|
||||||
|
std::fputs(chars, stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
inline void fputs<wchar_t>(const wchar_t *chars, FILE *stream) FMT_NOEXCEPT {
|
||||||
|
std::fputws(chars, stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Char>
|
||||||
|
inline void reset_color(FILE *stream) FMT_NOEXCEPT {
|
||||||
|
fputs(internal::data::RESET_COLOR, stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
inline void reset_color<wchar_t>(FILE *stream) FMT_NOEXCEPT {
|
||||||
|
fputs(internal::data::WRESET_COLOR, stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
// The following specialiazation disables using std::FILE as a character type,
|
||||||
|
// which is needed because or else
|
||||||
|
// fmt::print(stderr, fmt::emphasis::bold, "");
|
||||||
|
// would take stderr (a std::FILE *) as the format string.
|
||||||
|
template <>
|
||||||
|
struct is_string<std::FILE *> : std::false_type {};
|
||||||
|
template <>
|
||||||
|
struct is_string<const std::FILE *> : std::false_type {};
|
||||||
|
} // namespace internal
|
||||||
|
|
||||||
|
template <
|
||||||
|
typename S, typename Char = typename internal::char_t<S>::type>
|
||||||
|
void vprint(std::FILE *f, const text_style &ts, const S &format,
|
||||||
|
basic_format_args<typename buffer_context<Char>::type> args) {
|
||||||
|
bool has_style = false;
|
||||||
|
if (ts.has_emphasis()) {
|
||||||
|
has_style = true;
|
||||||
|
internal::fputs<Char>(
|
||||||
|
internal::make_emphasis<Char>(ts.get_emphasis()), f);
|
||||||
|
}
|
||||||
|
if (ts.has_foreground()) {
|
||||||
|
has_style = true;
|
||||||
|
internal::fputs<Char>(
|
||||||
|
internal::make_foreground_color<Char>(ts.get_foreground()), f);
|
||||||
|
}
|
||||||
|
if (ts.has_background()) {
|
||||||
|
has_style = true;
|
||||||
|
internal::fputs<Char>(
|
||||||
|
internal::make_background_color<Char>(ts.get_background()), f);
|
||||||
|
}
|
||||||
|
vprint(f, format, args);
|
||||||
|
if (has_style) {
|
||||||
|
internal::reset_color<Char>(f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Formats a string and prints it to the specified file stream using ANSI
|
||||||
|
escape sequences to specify text formatting.
|
||||||
|
Example:
|
||||||
|
fmt::print(fmt::emphasis::bold | fg(fmt::color::red),
|
||||||
|
"Elapsed time: {0:.2f} seconds", 1.23);
|
||||||
|
*/
|
||||||
|
template <typename String, typename... Args>
|
||||||
|
typename std::enable_if<internal::is_string<String>::value>::type print(
|
||||||
|
std::FILE *f, const text_style &ts, const String &format_str,
|
||||||
|
const Args &... args) {
|
||||||
|
internal::check_format_string<Args...>(format_str);
|
||||||
|
typedef typename internal::char_t<String>::type char_t;
|
||||||
|
typedef typename buffer_context<char_t>::type context_t;
|
||||||
|
format_arg_store<context_t, Args...> as{args...};
|
||||||
|
vprint(f, ts, format_str, basic_format_args<context_t>(as));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Formats a string and prints it to stdout using ANSI escape sequences to
|
||||||
|
specify text formatting.
|
||||||
|
Example:
|
||||||
|
fmt::print(fmt::emphasis::bold | fg(fmt::color::red),
|
||||||
|
"Elapsed time: {0:.2f} seconds", 1.23);
|
||||||
|
*/
|
||||||
|
template <typename String, typename... Args>
|
||||||
|
typename std::enable_if<internal::is_string<String>::value>::type print(
|
||||||
|
const text_style &ts, const String &format_str,
|
||||||
|
const Args &... args) {
|
||||||
|
return print(stdout, ts, format_str, args...);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
900
externals/fmt/include/fmt/core.h
vendored
900
externals/fmt/include/fmt/core.h
vendored
File diff suppressed because it is too large
Load diff
548
externals/fmt/include/fmt/format-inl.h
vendored
548
externals/fmt/include/fmt/format-inl.h
vendored
|
@ -136,12 +136,14 @@ int safe_strerror(
|
||||||
ERANGE : result;
|
ERANGE : result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if !FMT_MSC_VER
|
||||||
// Fallback to strerror if strerror_r and strerror_s are not available.
|
// Fallback to strerror if strerror_r and strerror_s are not available.
|
||||||
int fallback(internal::null<>) {
|
int fallback(internal::null<>) {
|
||||||
errno = 0;
|
errno = 0;
|
||||||
buffer_ = strerror(error_code_);
|
buffer_ = strerror(error_code_);
|
||||||
return errno;
|
return errno;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
public:
|
public:
|
||||||
dispatcher(int err_code, char *&buf, std::size_t buf_size)
|
dispatcher(int err_code, char *&buf, std::size_t buf_size)
|
||||||
|
@ -170,7 +172,7 @@ void format_error_code(internal::buffer &out, int error_code,
|
||||||
abs_value = 0 - abs_value;
|
abs_value = 0 - abs_value;
|
||||||
++error_code_size;
|
++error_code_size;
|
||||||
}
|
}
|
||||||
error_code_size += internal::count_digits(abs_value);
|
error_code_size += internal::to_unsigned(internal::count_digits(abs_value));
|
||||||
writer w(out);
|
writer w(out);
|
||||||
if (message.size() <= inline_buffer_size - error_code_size) {
|
if (message.size() <= inline_buffer_size - error_code_size) {
|
||||||
w.write(message);
|
w.write(message);
|
||||||
|
@ -192,34 +194,39 @@ void report_error(FormatFunc func, int error_code,
|
||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
#if !defined(FMT_STATIC_THOUSANDS_SEPARATOR)
|
FMT_FUNC size_t internal::count_code_points(basic_string_view<char8_t> s) {
|
||||||
class locale {
|
|
||||||
private:
|
|
||||||
std::locale locale_;
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit locale(std::locale loc = std::locale()) : locale_(loc) {}
|
|
||||||
std::locale get() { return locale_; }
|
|
||||||
};
|
|
||||||
|
|
||||||
FMT_FUNC size_t internal::count_code_points(u8string_view s) {
|
|
||||||
const char8_t *data = s.data();
|
const char8_t *data = s.data();
|
||||||
int num_code_points = 0;
|
size_t num_code_points = 0;
|
||||||
for (size_t i = 0, size = s.size(); i != size; ++i) {
|
for (size_t i = 0, size = s.size(); i != size; ++i) {
|
||||||
if ((data[i].value & 0xc0) != 0x80)
|
if ((data[i] & 0xc0) != 0x80)
|
||||||
++num_code_points;
|
++num_code_points;
|
||||||
}
|
}
|
||||||
return num_code_points;
|
return num_code_points;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if !defined(FMT_STATIC_THOUSANDS_SEPARATOR)
|
||||||
|
namespace internal {
|
||||||
|
|
||||||
|
template <typename Locale>
|
||||||
|
locale_ref::locale_ref(const Locale &loc) : locale_(&loc) {
|
||||||
|
static_assert(std::is_same<Locale, std::locale>::value, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Locale>
|
||||||
|
Locale locale_ref::get() const {
|
||||||
|
static_assert(std::is_same<Locale, std::locale>::value, "");
|
||||||
|
return locale_ ? *static_cast<const std::locale*>(locale_) : std::locale();
|
||||||
|
}
|
||||||
|
|
||||||
template <typename Char>
|
template <typename Char>
|
||||||
FMT_FUNC Char internal::thousands_sep(locale_provider *lp) {
|
FMT_FUNC Char thousands_sep_impl(locale_ref loc) {
|
||||||
std::locale loc = lp ? lp->locale().get() : std::locale();
|
return std::use_facet<std::numpunct<Char> >(
|
||||||
return std::use_facet<std::numpunct<Char>>(loc).thousands_sep();
|
loc.get<std::locale>()).thousands_sep();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
template <typename Char>
|
template <typename Char>
|
||||||
FMT_FUNC Char internal::thousands_sep(locale_provider *lp) {
|
FMT_FUNC Char internal::thousands_sep_impl(locale_ref) {
|
||||||
return FMT_STATIC_THOUSANDS_SEPARATOR;
|
return FMT_STATIC_THOUSANDS_SEPARATOR;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -236,19 +243,19 @@ FMT_FUNC void system_error::init(
|
||||||
namespace internal {
|
namespace internal {
|
||||||
template <typename T>
|
template <typename T>
|
||||||
int char_traits<char>::format_float(
|
int char_traits<char>::format_float(
|
||||||
char *buffer, std::size_t size, const char *format, int precision, T value) {
|
char *buf, std::size_t size, const char *format, int precision, T value) {
|
||||||
return precision < 0 ?
|
return precision < 0 ?
|
||||||
FMT_SNPRINTF(buffer, size, format, value) :
|
FMT_SNPRINTF(buf, size, format, value) :
|
||||||
FMT_SNPRINTF(buffer, size, format, precision, value);
|
FMT_SNPRINTF(buf, size, format, precision, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
int char_traits<wchar_t>::format_float(
|
int char_traits<wchar_t>::format_float(
|
||||||
wchar_t *buffer, std::size_t size, const wchar_t *format, int precision,
|
wchar_t *buf, std::size_t size, const wchar_t *format, int precision,
|
||||||
T value) {
|
T value) {
|
||||||
return precision < 0 ?
|
return precision < 0 ?
|
||||||
FMT_SWPRINTF(buffer, size, format, value) :
|
FMT_SWPRINTF(buf, size, format, value) :
|
||||||
FMT_SWPRINTF(buffer, size, format, precision, value);
|
FMT_SWPRINTF(buf, size, format, precision, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
|
@ -337,6 +344,8 @@ const int16_t basic_data<T>::POW10_EXPONENTS[] = {
|
||||||
827, 853, 880, 907, 933, 960, 986, 1013, 1039, 1066
|
827, 853, 880, 907, 933, 960, 986, 1013, 1039, 1066
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <typename T> const char basic_data<T>::FOREGROUND_COLOR[] = "\x1b[38;2;";
|
||||||
|
template <typename T> const char basic_data<T>::BACKGROUND_COLOR[] = "\x1b[48;2;";
|
||||||
template <typename T> const char basic_data<T>::RESET_COLOR[] = "\x1b[0m";
|
template <typename T> const char basic_data<T>::RESET_COLOR[] = "\x1b[0m";
|
||||||
template <typename T> const wchar_t basic_data<T>::WRESET_COLOR[] = L"\x1b[0m";
|
template <typename T> const wchar_t basic_data<T>::WRESET_COLOR[] = L"\x1b[0m";
|
||||||
|
|
||||||
|
@ -363,7 +372,7 @@ class fp {
|
||||||
sizeof(significand_type) * char_size;
|
sizeof(significand_type) * char_size;
|
||||||
|
|
||||||
fp(): f(0), e(0) {}
|
fp(): f(0), e(0) {}
|
||||||
fp(uint64_t f, int e): f(f), e(e) {}
|
fp(uint64_t f_val, int e_val): f(f_val), e(e_val) {}
|
||||||
|
|
||||||
// Constructs fp from an IEEE754 double. It is a template to prevent compile
|
// Constructs fp from an IEEE754 double. It is a template to prevent compile
|
||||||
// errors on platforms where double is not IEEE754.
|
// errors on platforms where double is not IEEE754.
|
||||||
|
@ -454,19 +463,28 @@ FMT_FUNC fp get_cached_power(int min_exponent, int &pow10_exponent) {
|
||||||
return fp(data::POW10_SIGNIFICANDS[index], data::POW10_EXPONENTS[index]);
|
return fp(data::POW10_SIGNIFICANDS[index], data::POW10_EXPONENTS[index]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FMT_FUNC bool grisu2_round(
|
||||||
|
char *buf, int &size, int max_digits, uint64_t delta,
|
||||||
|
uint64_t remainder, uint64_t exp, uint64_t diff, int &exp10) {
|
||||||
|
while (remainder < diff && delta - remainder >= exp &&
|
||||||
|
(remainder + exp < diff || diff - remainder > remainder + exp - diff)) {
|
||||||
|
--buf[size - 1];
|
||||||
|
remainder += exp;
|
||||||
|
}
|
||||||
|
if (size > max_digits) {
|
||||||
|
--size;
|
||||||
|
++exp10;
|
||||||
|
if (buf[size] >= '5')
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// Generates output using Grisu2 digit-gen algorithm.
|
// Generates output using Grisu2 digit-gen algorithm.
|
||||||
FMT_FUNC void grisu2_gen_digits(
|
FMT_FUNC bool grisu2_gen_digits(
|
||||||
const fp &scaled_value, const fp &scaled_upper, uint64_t delta,
|
char *buf, int &size, uint32_t hi, uint64_t lo, int &exp,
|
||||||
char *buffer, size_t &size, int &dec_exp) {
|
uint64_t delta, const fp &one, const fp &diff, int max_digits) {
|
||||||
internal::fp one(1ull << -scaled_upper.e, scaled_upper.e);
|
// Generate digits for the most significant part (hi).
|
||||||
// hi (p1 in Grisu) contains the most significant digits of scaled_upper.
|
|
||||||
// hi = floor(scaled_upper / one).
|
|
||||||
uint32_t hi = static_cast<uint32_t>(scaled_upper.f >> -one.e);
|
|
||||||
// lo (p2 in Grisu) contains the least significants digits of scaled_upper.
|
|
||||||
// lo = scaled_upper mod 1.
|
|
||||||
uint64_t lo = scaled_upper.f & (one.f - 1);
|
|
||||||
size = 0;
|
|
||||||
auto exp = count_digits(hi); // kappa in Grisu.
|
|
||||||
while (exp > 0) {
|
while (exp > 0) {
|
||||||
uint32_t digit = 0;
|
uint32_t digit = 0;
|
||||||
// This optimization by miloyip reduces the number of integer divisions by
|
// This optimization by miloyip reduces the number of integer divisions by
|
||||||
|
@ -486,148 +504,32 @@ FMT_FUNC void grisu2_gen_digits(
|
||||||
FMT_ASSERT(false, "invalid number of digits");
|
FMT_ASSERT(false, "invalid number of digits");
|
||||||
}
|
}
|
||||||
if (digit != 0 || size != 0)
|
if (digit != 0 || size != 0)
|
||||||
buffer[size++] = static_cast<char>('0' + digit);
|
buf[size++] = static_cast<char>('0' + digit);
|
||||||
--exp;
|
--exp;
|
||||||
uint64_t remainder = (static_cast<uint64_t>(hi) << -one.e) + lo;
|
uint64_t remainder = (static_cast<uint64_t>(hi) << -one.e) + lo;
|
||||||
if (remainder <= delta) {
|
if (remainder <= delta || size > max_digits) {
|
||||||
dec_exp += exp;
|
return grisu2_round(
|
||||||
// TODO: use scaled_value
|
buf, size, max_digits, delta, remainder,
|
||||||
(void)scaled_value;
|
static_cast<uint64_t>(data::POWERS_OF_10_32[exp]) << -one.e,
|
||||||
return;
|
diff.f, exp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Generate digits for the least significant part (lo).
|
||||||
for (;;) {
|
for (;;) {
|
||||||
lo *= 10;
|
lo *= 10;
|
||||||
delta *= 10;
|
delta *= 10;
|
||||||
char digit = static_cast<char>(lo >> -one.e);
|
char digit = static_cast<char>(lo >> -one.e);
|
||||||
if (digit != 0 || size != 0)
|
if (digit != 0 || size != 0)
|
||||||
buffer[size++] = static_cast<char>('0' + digit);
|
buf[size++] = static_cast<char>('0' + digit);
|
||||||
lo &= one.f - 1;
|
lo &= one.f - 1;
|
||||||
--exp;
|
--exp;
|
||||||
if (lo < delta) {
|
if (lo < delta || size > max_digits) {
|
||||||
dec_exp += exp;
|
return grisu2_round(buf, size, max_digits, delta, lo, one.f,
|
||||||
return;
|
diff.f * data::POWERS_OF_10_32[-exp], exp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FMT_FUNC void grisu2_format_positive(double value, char *buffer, size_t &size,
|
|
||||||
int &dec_exp) {
|
|
||||||
FMT_ASSERT(value > 0, "value is nonpositive");
|
|
||||||
fp fp_value(value);
|
|
||||||
fp lower, upper; // w^- and w^+ in the Grisu paper.
|
|
||||||
fp_value.compute_boundaries(lower, upper);
|
|
||||||
// Find a cached power of 10 close to 1 / upper.
|
|
||||||
const int min_exp = -60; // alpha in Grisu.
|
|
||||||
auto dec_pow = get_cached_power( // \tilde{c}_{-k} in Grisu.
|
|
||||||
min_exp - (upper.e + fp::significand_size), dec_exp);
|
|
||||||
dec_exp = -dec_exp;
|
|
||||||
fp_value.normalize();
|
|
||||||
fp scaled_value = fp_value * dec_pow;
|
|
||||||
fp scaled_lower = lower * dec_pow; // \tilde{M}^- in Grisu.
|
|
||||||
fp scaled_upper = upper * dec_pow; // \tilde{M}^+ in Grisu.
|
|
||||||
++scaled_lower.f; // \tilde{M}^- + 1 ulp -> M^-_{\uparrow}.
|
|
||||||
--scaled_upper.f; // \tilde{M}^+ - 1 ulp -> M^+_{\downarrow}.
|
|
||||||
uint64_t delta = scaled_upper.f - scaled_lower.f;
|
|
||||||
grisu2_gen_digits(scaled_value, scaled_upper, delta, buffer, size, dec_exp);
|
|
||||||
}
|
|
||||||
|
|
||||||
FMT_FUNC void round(char *buffer, size_t &size, int &exp,
|
|
||||||
int digits_to_remove) {
|
|
||||||
size -= to_unsigned(digits_to_remove);
|
|
||||||
exp += digits_to_remove;
|
|
||||||
int digit = buffer[size] - '0';
|
|
||||||
// TODO: proper rounding and carry
|
|
||||||
if (digit > 5 || (digit == 5 && (digits_to_remove > 1 ||
|
|
||||||
(buffer[size - 1] - '0') % 2) != 0)) {
|
|
||||||
++buffer[size - 1];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Writes the exponent exp in the form "[+-]d{1,3}" to buffer.
|
|
||||||
FMT_FUNC char *write_exponent(char *buffer, int exp) {
|
|
||||||
FMT_ASSERT(-1000 < exp && exp < 1000, "exponent out of range");
|
|
||||||
if (exp < 0) {
|
|
||||||
*buffer++ = '-';
|
|
||||||
exp = -exp;
|
|
||||||
} else {
|
|
||||||
*buffer++ = '+';
|
|
||||||
}
|
|
||||||
if (exp >= 100) {
|
|
||||||
*buffer++ = static_cast<char>('0' + exp / 100);
|
|
||||||
exp %= 100;
|
|
||||||
const char *d = data::DIGITS + exp * 2;
|
|
||||||
*buffer++ = d[0];
|
|
||||||
*buffer++ = d[1];
|
|
||||||
} else {
|
|
||||||
const char *d = data::DIGITS + exp * 2;
|
|
||||||
*buffer++ = d[0];
|
|
||||||
*buffer++ = d[1];
|
|
||||||
}
|
|
||||||
return buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
FMT_FUNC void format_exp_notation(
|
|
||||||
char *buffer, size_t &size, int exp, int precision, bool upper) {
|
|
||||||
// Insert a decimal point after the first digit and add an exponent.
|
|
||||||
std::memmove(buffer + 2, buffer + 1, size - 1);
|
|
||||||
buffer[1] = '.';
|
|
||||||
exp += static_cast<int>(size) - 1;
|
|
||||||
int num_digits = precision - static_cast<int>(size) + 1;
|
|
||||||
if (num_digits > 0) {
|
|
||||||
std::uninitialized_fill_n(buffer + size + 1, num_digits, '0');
|
|
||||||
size += to_unsigned(num_digits);
|
|
||||||
} else if (num_digits < 0) {
|
|
||||||
round(buffer, size, exp, -num_digits);
|
|
||||||
}
|
|
||||||
char *p = buffer + size + 1;
|
|
||||||
*p++ = upper ? 'E' : 'e';
|
|
||||||
size = to_unsigned(write_exponent(p, exp) - buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Prettifies the output of the Grisu2 algorithm.
|
|
||||||
// The number is given as v = buffer * 10^exp.
|
|
||||||
FMT_FUNC void grisu2_prettify(char *buffer, size_t &size, int exp,
|
|
||||||
int precision, bool upper) {
|
|
||||||
// pow(10, full_exp - 1) <= v <= pow(10, full_exp).
|
|
||||||
int int_size = static_cast<int>(size);
|
|
||||||
int full_exp = int_size + exp;
|
|
||||||
const int exp_threshold = 21;
|
|
||||||
if (int_size <= full_exp && full_exp <= exp_threshold) {
|
|
||||||
// 1234e7 -> 12340000000[.0+]
|
|
||||||
std::uninitialized_fill_n(buffer + int_size, full_exp - int_size, '0');
|
|
||||||
char *p = buffer + full_exp;
|
|
||||||
if (precision > 0) {
|
|
||||||
*p++ = '.';
|
|
||||||
std::uninitialized_fill_n(p, precision, '0');
|
|
||||||
p += precision;
|
|
||||||
}
|
|
||||||
size = to_unsigned(p - buffer);
|
|
||||||
} else if (0 < full_exp && full_exp <= exp_threshold) {
|
|
||||||
// 1234e-2 -> 12.34[0+]
|
|
||||||
int fractional_size = -exp;
|
|
||||||
std::memmove(buffer + full_exp + 1, buffer + full_exp,
|
|
||||||
to_unsigned(fractional_size));
|
|
||||||
buffer[full_exp] = '.';
|
|
||||||
int num_zeros = precision - fractional_size;
|
|
||||||
if (num_zeros > 0) {
|
|
||||||
std::uninitialized_fill_n(buffer + size + 1, num_zeros, '0');
|
|
||||||
size += to_unsigned(num_zeros);
|
|
||||||
}
|
|
||||||
++size;
|
|
||||||
} else if (-6 < full_exp && full_exp <= 0) {
|
|
||||||
// 1234e-6 -> 0.001234
|
|
||||||
int offset = 2 - full_exp;
|
|
||||||
std::memmove(buffer + offset, buffer, size);
|
|
||||||
buffer[0] = '0';
|
|
||||||
buffer[1] = '.';
|
|
||||||
std::uninitialized_fill_n(buffer + 2, -full_exp, '0');
|
|
||||||
size = to_unsigned(int_size + offset);
|
|
||||||
} else {
|
|
||||||
format_exp_notation(buffer, size, exp, precision, upper);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#if FMT_CLANG_VERSION
|
#if FMT_CLANG_VERSION
|
||||||
# define FMT_FALLTHROUGH [[clang::fallthrough]];
|
# define FMT_FALLTHROUGH [[clang::fallthrough]];
|
||||||
#elif FMT_GCC_VERSION >= 700
|
#elif FMT_GCC_VERSION >= 700
|
||||||
|
@ -636,58 +538,270 @@ FMT_FUNC void grisu2_prettify(char *buffer, size_t &size, int exp,
|
||||||
# define FMT_FALLTHROUGH
|
# define FMT_FALLTHROUGH
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Formats a nonnegative value using Grisu2 algorithm. Grisu2 doesn't give any
|
struct gen_digits_params {
|
||||||
// guarantees on the shortness of the result.
|
int num_digits;
|
||||||
FMT_FUNC void grisu2_format(double value, char *buffer, size_t &size, char type,
|
bool fixed;
|
||||||
int precision, bool write_decimal_point) {
|
bool upper;
|
||||||
FMT_ASSERT(value >= 0, "value is negative");
|
bool trailing_zeros;
|
||||||
int dec_exp = 0; // K in Grisu.
|
};
|
||||||
if (value > 0) {
|
|
||||||
grisu2_format_positive(value, buffer, size, dec_exp);
|
struct prettify_handler {
|
||||||
|
char *data;
|
||||||
|
ptrdiff_t size;
|
||||||
|
buffer &buf;
|
||||||
|
|
||||||
|
explicit prettify_handler(buffer &b, ptrdiff_t n)
|
||||||
|
: data(b.data()), size(n), buf(b) {}
|
||||||
|
~prettify_handler() {
|
||||||
|
assert(buf.size() >= to_unsigned(size));
|
||||||
|
buf.resize(to_unsigned(size));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename F>
|
||||||
|
void insert(ptrdiff_t pos, ptrdiff_t n, F f) {
|
||||||
|
std::memmove(data + pos + n, data + pos, to_unsigned(size - pos));
|
||||||
|
f(data + pos);
|
||||||
|
size += n;
|
||||||
|
}
|
||||||
|
|
||||||
|
void insert(ptrdiff_t pos, char c) {
|
||||||
|
std::memmove(data + pos + 1, data + pos, to_unsigned(size - pos));
|
||||||
|
data[pos] = c;
|
||||||
|
++size;
|
||||||
|
}
|
||||||
|
|
||||||
|
void append(ptrdiff_t n, char c) {
|
||||||
|
std::uninitialized_fill_n(data + size, n, c);
|
||||||
|
size += n;
|
||||||
|
}
|
||||||
|
|
||||||
|
void append(char c) { data[size++] = c; }
|
||||||
|
|
||||||
|
void remove_trailing(char c) {
|
||||||
|
while (data[size - 1] == c) --size;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Writes the exponent exp in the form "[+-]d{2,3}" to buffer.
|
||||||
|
template <typename Handler>
|
||||||
|
FMT_FUNC void write_exponent(int exp, Handler &&h) {
|
||||||
|
FMT_ASSERT(-1000 < exp && exp < 1000, "exponent out of range");
|
||||||
|
if (exp < 0) {
|
||||||
|
h.append('-');
|
||||||
|
exp = -exp;
|
||||||
} else {
|
} else {
|
||||||
*buffer = '0';
|
h.append('+');
|
||||||
size = 1;
|
|
||||||
}
|
}
|
||||||
const int default_precision = 6;
|
if (exp >= 100) {
|
||||||
if (precision < 0)
|
h.append(static_cast<char>('0' + exp / 100));
|
||||||
precision = default_precision;
|
exp %= 100;
|
||||||
bool upper = false;
|
const char *d = data::DIGITS + exp * 2;
|
||||||
switch (type) {
|
h.append(d[0]);
|
||||||
case 'G':
|
h.append(d[1]);
|
||||||
upper = true;
|
} else {
|
||||||
FMT_FALLTHROUGH
|
const char *d = data::DIGITS + exp * 2;
|
||||||
case '\0': case 'g': {
|
h.append(d[0]);
|
||||||
int digits_to_remove = static_cast<int>(size) - precision;
|
h.append(d[1]);
|
||||||
if (digits_to_remove > 0) {
|
|
||||||
round(buffer, size, dec_exp, digits_to_remove);
|
|
||||||
// Remove trailing zeros.
|
|
||||||
while (size > 0 && buffer[size - 1] == '0') {
|
|
||||||
--size;
|
|
||||||
++dec_exp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
precision = 0;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
case 'F':
|
}
|
||||||
upper = true;
|
|
||||||
FMT_FALLTHROUGH
|
struct fill {
|
||||||
case 'f': {
|
size_t n;
|
||||||
int digits_to_remove = -dec_exp - precision;
|
void operator()(char *buf) const {
|
||||||
if (digits_to_remove > 0) {
|
buf[0] = '0';
|
||||||
if (digits_to_remove >= static_cast<int>(size))
|
buf[1] = '.';
|
||||||
digits_to_remove = static_cast<int>(size) - 1;
|
std::uninitialized_fill_n(buf + 2, n, '0');
|
||||||
round(buffer, size, dec_exp, digits_to_remove);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
case 'e': case 'E':
|
};
|
||||||
format_exp_notation(buffer, size, dec_exp, precision, type == 'E');
|
|
||||||
|
// The number is given as v = f * pow(10, exp), where f has size digits.
|
||||||
|
template <typename Handler>
|
||||||
|
FMT_FUNC void grisu2_prettify(const gen_digits_params ¶ms,
|
||||||
|
int size, int exp, Handler &&handler) {
|
||||||
|
if (!params.fixed) {
|
||||||
|
// Insert a decimal point after the first digit and add an exponent.
|
||||||
|
handler.insert(1, '.');
|
||||||
|
exp += size - 1;
|
||||||
|
if (size < params.num_digits)
|
||||||
|
handler.append(params.num_digits - size, '0');
|
||||||
|
handler.append(params.upper ? 'E' : 'e');
|
||||||
|
write_exponent(exp, handler);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (write_decimal_point && precision < 1)
|
// pow(10, full_exp - 1) <= v <= pow(10, full_exp).
|
||||||
precision = 1;
|
int full_exp = size + exp;
|
||||||
grisu2_prettify(buffer, size, dec_exp, precision, upper);
|
const int exp_threshold = 21;
|
||||||
|
if (size <= full_exp && full_exp <= exp_threshold) {
|
||||||
|
// 1234e7 -> 12340000000[.0+]
|
||||||
|
handler.append(full_exp - size, '0');
|
||||||
|
int num_zeros = params.num_digits - full_exp;
|
||||||
|
if (num_zeros > 0 && params.trailing_zeros) {
|
||||||
|
handler.append('.');
|
||||||
|
handler.append(num_zeros, '0');
|
||||||
|
}
|
||||||
|
} else if (full_exp > 0) {
|
||||||
|
// 1234e-2 -> 12.34[0+]
|
||||||
|
handler.insert(full_exp, '.');
|
||||||
|
if (!params.trailing_zeros) {
|
||||||
|
// Remove trailing zeros.
|
||||||
|
handler.remove_trailing('0');
|
||||||
|
} else if (params.num_digits > size) {
|
||||||
|
// Add trailing zeros.
|
||||||
|
ptrdiff_t num_zeros = params.num_digits - size;
|
||||||
|
handler.append(num_zeros, '0');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 1234e-6 -> 0.001234
|
||||||
|
handler.insert(0, 2 - full_exp, fill{to_unsigned(-full_exp)});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct char_counter {
|
||||||
|
ptrdiff_t size;
|
||||||
|
|
||||||
|
template <typename F>
|
||||||
|
void insert(ptrdiff_t, ptrdiff_t n, F) { size += n; }
|
||||||
|
void insert(ptrdiff_t, char) { ++size; }
|
||||||
|
void append(ptrdiff_t n, char) { size += n; }
|
||||||
|
void append(char) { ++size; }
|
||||||
|
void remove_trailing(char) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Converts format specifiers into parameters for digit generation and computes
|
||||||
|
// output buffer size for a number in the range [pow(10, exp - 1), pow(10, exp)
|
||||||
|
// or 0 if exp == 1.
|
||||||
|
FMT_FUNC gen_digits_params process_specs(const core_format_specs &specs,
|
||||||
|
int exp, buffer &buf) {
|
||||||
|
auto params = gen_digits_params();
|
||||||
|
int num_digits = specs.precision >= 0 ? specs.precision : 6;
|
||||||
|
switch (specs.type) {
|
||||||
|
case 'G':
|
||||||
|
params.upper = true;
|
||||||
|
FMT_FALLTHROUGH
|
||||||
|
case '\0': case 'g':
|
||||||
|
params.trailing_zeros = (specs.flags & HASH_FLAG) != 0;
|
||||||
|
if (-4 <= exp && exp < num_digits + 1) {
|
||||||
|
params.fixed = true;
|
||||||
|
if (!specs.type && params.trailing_zeros && exp >= 0)
|
||||||
|
num_digits = exp + 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'F':
|
||||||
|
params.upper = true;
|
||||||
|
FMT_FALLTHROUGH
|
||||||
|
case 'f': {
|
||||||
|
params.fixed = true;
|
||||||
|
params.trailing_zeros = true;
|
||||||
|
int adjusted_min_digits = num_digits + exp;
|
||||||
|
if (adjusted_min_digits > 0)
|
||||||
|
num_digits = adjusted_min_digits;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'E':
|
||||||
|
params.upper = true;
|
||||||
|
FMT_FALLTHROUGH
|
||||||
|
case 'e':
|
||||||
|
++num_digits;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
params.num_digits = num_digits;
|
||||||
|
char_counter counter{num_digits};
|
||||||
|
grisu2_prettify(params, params.num_digits, exp - num_digits, counter);
|
||||||
|
buf.resize(to_unsigned(counter.size));
|
||||||
|
return params;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Double>
|
||||||
|
FMT_FUNC typename std::enable_if<sizeof(Double) == sizeof(uint64_t), bool>::type
|
||||||
|
grisu2_format(Double value, buffer &buf, core_format_specs specs) {
|
||||||
|
FMT_ASSERT(value >= 0, "value is negative");
|
||||||
|
if (value == 0) {
|
||||||
|
gen_digits_params params = process_specs(specs, 1, buf);
|
||||||
|
const size_t size = 1;
|
||||||
|
buf[0] = '0';
|
||||||
|
grisu2_prettify(params, size, 0, prettify_handler(buf, size));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
fp fp_value(value);
|
||||||
|
fp lower, upper; // w^- and w^+ in the Grisu paper.
|
||||||
|
fp_value.compute_boundaries(lower, upper);
|
||||||
|
|
||||||
|
// Find a cached power of 10 close to 1 / upper and use it to scale upper.
|
||||||
|
const int min_exp = -60; // alpha in Grisu.
|
||||||
|
int cached_exp = 0; // K in Grisu.
|
||||||
|
auto cached_pow = get_cached_power( // \tilde{c}_{-k} in Grisu.
|
||||||
|
min_exp - (upper.e + fp::significand_size), cached_exp);
|
||||||
|
cached_exp = -cached_exp;
|
||||||
|
upper = upper * cached_pow; // \tilde{M}^+ in Grisu.
|
||||||
|
--upper.f; // \tilde{M}^+ - 1 ulp -> M^+_{\downarrow}.
|
||||||
|
fp one(1ull << -upper.e, upper.e);
|
||||||
|
// hi (p1 in Grisu) contains the most significant digits of scaled_upper.
|
||||||
|
// hi = floor(upper / one).
|
||||||
|
uint32_t hi = static_cast<uint32_t>(upper.f >> -one.e);
|
||||||
|
int exp = count_digits(hi); // kappa in Grisu.
|
||||||
|
gen_digits_params params = process_specs(specs, cached_exp + exp, buf);
|
||||||
|
fp_value.normalize();
|
||||||
|
fp scaled_value = fp_value * cached_pow;
|
||||||
|
lower = lower * cached_pow; // \tilde{M}^- in Grisu.
|
||||||
|
++lower.f; // \tilde{M}^- + 1 ulp -> M^-_{\uparrow}.
|
||||||
|
uint64_t delta = upper.f - lower.f;
|
||||||
|
fp diff = upper - scaled_value; // wp_w in Grisu.
|
||||||
|
// lo (p2 in Grisu) contains the least significants digits of scaled_upper.
|
||||||
|
// lo = supper % one.
|
||||||
|
uint64_t lo = upper.f & (one.f - 1);
|
||||||
|
int size = 0;
|
||||||
|
if (!grisu2_gen_digits(buf.data(), size, hi, lo, exp, delta, one, diff,
|
||||||
|
params.num_digits)) {
|
||||||
|
buf.clear();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
grisu2_prettify(params, size, cached_exp + exp, prettify_handler(buf, size));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Double>
|
||||||
|
void sprintf_format(Double value, internal::buffer &buf,
|
||||||
|
core_format_specs spec) {
|
||||||
|
// Buffer capacity must be non-zero, otherwise MSVC's vsnprintf_s will fail.
|
||||||
|
FMT_ASSERT(buf.capacity() != 0, "empty buffer");
|
||||||
|
|
||||||
|
// Build format string.
|
||||||
|
enum { MAX_FORMAT_SIZE = 10}; // longest format: %#-*.*Lg
|
||||||
|
char format[MAX_FORMAT_SIZE];
|
||||||
|
char *format_ptr = format;
|
||||||
|
*format_ptr++ = '%';
|
||||||
|
if (spec.has(HASH_FLAG))
|
||||||
|
*format_ptr++ = '#';
|
||||||
|
if (spec.precision >= 0) {
|
||||||
|
*format_ptr++ = '.';
|
||||||
|
*format_ptr++ = '*';
|
||||||
|
}
|
||||||
|
if (std::is_same<Double, long double>::value)
|
||||||
|
*format_ptr++ = 'L';
|
||||||
|
*format_ptr++ = spec.type;
|
||||||
|
*format_ptr = '\0';
|
||||||
|
|
||||||
|
// Format using snprintf.
|
||||||
|
char *start = FMT_NULL;
|
||||||
|
for (;;) {
|
||||||
|
std::size_t buffer_size = buf.capacity();
|
||||||
|
start = &buf[0];
|
||||||
|
int result = internal::char_traits<char>::format_float(
|
||||||
|
start, buffer_size, format, spec.precision, value);
|
||||||
|
if (result >= 0) {
|
||||||
|
unsigned n = internal::to_unsigned(result);
|
||||||
|
if (n < buf.capacity()) {
|
||||||
|
buf.resize(n);
|
||||||
|
break; // The buffer is large enough - continue with formatting.
|
||||||
|
}
|
||||||
|
buf.reserve(n + 1);
|
||||||
|
} else {
|
||||||
|
// If result is negative we ask to increase the capacity by at least 1,
|
||||||
|
// but as std::vector, the buffer grows exponentially.
|
||||||
|
buf.reserve(buf.capacity() + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
|
|
||||||
|
@ -812,11 +926,6 @@ FMT_FUNC void format_system_error(
|
||||||
format_error_code(out, error_code, message);
|
format_error_code(out, error_code, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Char>
|
|
||||||
void basic_fixed_buffer<Char>::grow(std::size_t) {
|
|
||||||
FMT_THROW(std::runtime_error("buffer overflow"));
|
|
||||||
}
|
|
||||||
|
|
||||||
FMT_FUNC void internal::error_handler::on_error(const char *message) {
|
FMT_FUNC void internal::error_handler::on_error(const char *message) {
|
||||||
FMT_THROW(format_error(message));
|
FMT_THROW(format_error(message));
|
||||||
}
|
}
|
||||||
|
@ -835,13 +944,14 @@ FMT_FUNC void report_windows_error(
|
||||||
|
|
||||||
FMT_FUNC void vprint(std::FILE *f, string_view format_str, format_args args) {
|
FMT_FUNC void vprint(std::FILE *f, string_view format_str, format_args args) {
|
||||||
memory_buffer buffer;
|
memory_buffer buffer;
|
||||||
vformat_to(buffer, format_str, args);
|
internal::vformat_to(buffer, format_str,
|
||||||
|
basic_format_args<buffer_context<char>::type>(args));
|
||||||
std::fwrite(buffer.data(), 1, buffer.size(), f);
|
std::fwrite(buffer.data(), 1, buffer.size(), f);
|
||||||
}
|
}
|
||||||
|
|
||||||
FMT_FUNC void vprint(std::FILE *f, wstring_view format_str, wformat_args args) {
|
FMT_FUNC void vprint(std::FILE *f, wstring_view format_str, wformat_args args) {
|
||||||
wmemory_buffer buffer;
|
wmemory_buffer buffer;
|
||||||
vformat_to(buffer, format_str, args);
|
internal::vformat_to(buffer, format_str, args);
|
||||||
std::fwrite(buffer.data(), sizeof(wchar_t), buffer.size(), f);
|
std::fwrite(buffer.data(), sizeof(wchar_t), buffer.size(), f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -853,10 +963,6 @@ FMT_FUNC void vprint(wstring_view format_str, wformat_args args) {
|
||||||
vprint(stdout, format_str, args);
|
vprint(stdout, format_str, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if !defined(FMT_STATIC_THOUSANDS_SEPARATOR)
|
|
||||||
FMT_FUNC locale locale_provider::locale() { return fmt::locale(); }
|
|
||||||
#endif
|
|
||||||
|
|
||||||
FMT_END_NAMESPACE
|
FMT_END_NAMESPACE
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
|
|
1467
externals/fmt/include/fmt/format.h
vendored
1467
externals/fmt/include/fmt/format.h
vendored
File diff suppressed because it is too large
Load diff
77
externals/fmt/include/fmt/locale.h
vendored
Normal file
77
externals/fmt/include/fmt/locale.h
vendored
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
// Formatting library for C++ - std::locale support
|
||||||
|
//
|
||||||
|
// Copyright (c) 2012 - present, Victor Zverovich
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// For the license information refer to format.h.
|
||||||
|
|
||||||
|
#ifndef FMT_LOCALE_H_
|
||||||
|
#define FMT_LOCALE_H_
|
||||||
|
|
||||||
|
#include "format.h"
|
||||||
|
#include <locale>
|
||||||
|
|
||||||
|
FMT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
|
namespace internal {
|
||||||
|
template <typename Char>
|
||||||
|
typename buffer_context<Char>::type::iterator vformat_to(
|
||||||
|
const std::locale &loc, basic_buffer<Char> &buf,
|
||||||
|
basic_string_view<Char> format_str,
|
||||||
|
basic_format_args<typename buffer_context<Char>::type> args) {
|
||||||
|
typedef back_insert_range<basic_buffer<Char> > range;
|
||||||
|
return vformat_to<arg_formatter<range>>(
|
||||||
|
buf, to_string_view(format_str), args, internal::locale_ref(loc));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Char>
|
||||||
|
std::basic_string<Char> vformat(
|
||||||
|
const std::locale &loc, basic_string_view<Char> format_str,
|
||||||
|
basic_format_args<typename buffer_context<Char>::type> args) {
|
||||||
|
basic_memory_buffer<Char> buffer;
|
||||||
|
internal::vformat_to(loc, buffer, format_str, args);
|
||||||
|
return fmt::to_string(buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename S, typename Char = FMT_CHAR(S)>
|
||||||
|
inline std::basic_string<Char> vformat(
|
||||||
|
const std::locale &loc, const S &format_str,
|
||||||
|
basic_format_args<typename buffer_context<Char>::type> args) {
|
||||||
|
return internal::vformat(loc, to_string_view(format_str), args);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename S, typename... Args>
|
||||||
|
inline std::basic_string<FMT_CHAR(S)> format(
|
||||||
|
const std::locale &loc, const S &format_str, const Args &... args) {
|
||||||
|
return internal::vformat(
|
||||||
|
loc, to_string_view(format_str),
|
||||||
|
*internal::checked_args<S, Args...>(format_str, args...));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename String, typename OutputIt, typename... Args>
|
||||||
|
inline typename std::enable_if<internal::is_output_iterator<OutputIt>::value,
|
||||||
|
OutputIt>::type
|
||||||
|
vformat_to(OutputIt out, const std::locale &loc, const String &format_str,
|
||||||
|
typename format_args_t<OutputIt, FMT_CHAR(String)>::type args) {
|
||||||
|
typedef output_range<OutputIt, FMT_CHAR(String)> range;
|
||||||
|
return vformat_to<arg_formatter<range>>(
|
||||||
|
range(out), to_string_view(format_str), args, internal::locale_ref(loc));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename OutputIt, typename S, typename... Args>
|
||||||
|
inline typename std::enable_if<
|
||||||
|
internal::is_string<S>::value &&
|
||||||
|
internal::is_output_iterator<OutputIt>::value, OutputIt>::type
|
||||||
|
format_to(OutputIt out, const std::locale &loc, const S &format_str,
|
||||||
|
const Args &... args) {
|
||||||
|
internal::check_format_string<Args...>(format_str);
|
||||||
|
typedef typename format_context_t<OutputIt, FMT_CHAR(S)>::type context;
|
||||||
|
format_arg_store<context, Args...> as{args...};
|
||||||
|
return vformat_to(out, loc, to_string_view(format_str),
|
||||||
|
basic_format_args<context>(as));
|
||||||
|
}
|
||||||
|
|
||||||
|
FMT_END_NAMESPACE
|
||||||
|
|
||||||
|
#endif // FMT_LOCALE_H_
|
20
externals/fmt/include/fmt/ostream.h
vendored
20
externals/fmt/include/fmt/ostream.h
vendored
|
@ -1,6 +1,6 @@
|
||||||
// Formatting library for C++ - std::ostream support
|
// Formatting library for C++ - std::ostream support
|
||||||
//
|
//
|
||||||
// Copyright (c) 2012 - 2016, Victor Zverovich
|
// Copyright (c) 2012 - present, Victor Zverovich
|
||||||
// All rights reserved.
|
// All rights reserved.
|
||||||
//
|
//
|
||||||
// For the license information refer to format.h.
|
// For the license information refer to format.h.
|
||||||
|
@ -129,7 +129,7 @@ inline void vprint(std::basic_ostream<Char> &os,
|
||||||
basic_string_view<Char> format_str,
|
basic_string_view<Char> format_str,
|
||||||
basic_format_args<typename buffer_context<Char>::type> args) {
|
basic_format_args<typename buffer_context<Char>::type> args) {
|
||||||
basic_memory_buffer<Char> buffer;
|
basic_memory_buffer<Char> buffer;
|
||||||
vformat_to(buffer, format_str, args);
|
internal::vformat_to(buffer, format_str, args);
|
||||||
internal::write(os, buffer);
|
internal::write(os, buffer);
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
|
@ -141,16 +141,12 @@ inline void vprint(std::basic_ostream<Char> &os,
|
||||||
fmt::print(cerr, "Don't {}!", "panic");
|
fmt::print(cerr, "Don't {}!", "panic");
|
||||||
\endrst
|
\endrst
|
||||||
*/
|
*/
|
||||||
template <typename... Args>
|
template <typename S, typename... Args>
|
||||||
inline void print(std::ostream &os, string_view format_str,
|
inline typename std::enable_if<internal::is_string<S>::value>::type
|
||||||
const Args & ... args) {
|
print(std::basic_ostream<FMT_CHAR(S)> &os, const S &format_str,
|
||||||
vprint<char>(os, format_str, make_format_args<format_context>(args...));
|
const Args & ... args) {
|
||||||
}
|
internal::checked_args<S, Args...> ca(format_str, args...);
|
||||||
|
vprint(os, to_string_view(format_str), *ca);
|
||||||
template <typename... Args>
|
|
||||||
inline void print(std::wostream &os, wstring_view format_str,
|
|
||||||
const Args & ... args) {
|
|
||||||
vprint<wchar_t>(os, format_str, make_format_args<wformat_context>(args...));
|
|
||||||
}
|
}
|
||||||
FMT_END_NAMESPACE
|
FMT_END_NAMESPACE
|
||||||
|
|
||||||
|
|
4
externals/fmt/include/fmt/posix.h
vendored
4
externals/fmt/include/fmt/posix.h
vendored
|
@ -137,7 +137,7 @@ class buffered_file {
|
||||||
buffered_file() FMT_NOEXCEPT : file_(FMT_NULL) {}
|
buffered_file() FMT_NOEXCEPT : file_(FMT_NULL) {}
|
||||||
|
|
||||||
// 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_DTOR_NOEXCEPT;
|
FMT_API ~buffered_file() FMT_NOEXCEPT;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
buffered_file(const buffered_file &) = delete;
|
buffered_file(const buffered_file &) = delete;
|
||||||
|
@ -223,7 +223,7 @@ 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_DTOR_NOEXCEPT;
|
FMT_API ~file() FMT_NOEXCEPT;
|
||||||
|
|
||||||
// Returns the file descriptor.
|
// Returns the file descriptor.
|
||||||
int descriptor() const FMT_NOEXCEPT { return fd_; }
|
int descriptor() const FMT_NOEXCEPT { return fd_; }
|
||||||
|
|
367
externals/fmt/include/fmt/printf.h
vendored
367
externals/fmt/include/fmt/printf.h
vendored
|
@ -16,6 +16,130 @@
|
||||||
FMT_BEGIN_NAMESPACE
|
FMT_BEGIN_NAMESPACE
|
||||||
namespace internal {
|
namespace internal {
|
||||||
|
|
||||||
|
// An iterator that produces a null terminator on *end. This simplifies parsing
|
||||||
|
// and allows comparing the performance of processing a null-terminated string
|
||||||
|
// vs string_view.
|
||||||
|
template <typename Char>
|
||||||
|
class null_terminating_iterator {
|
||||||
|
public:
|
||||||
|
typedef std::ptrdiff_t difference_type;
|
||||||
|
typedef Char value_type;
|
||||||
|
typedef const Char* pointer;
|
||||||
|
typedef const Char& reference;
|
||||||
|
typedef std::random_access_iterator_tag iterator_category;
|
||||||
|
|
||||||
|
null_terminating_iterator() : ptr_(0), end_(0) {}
|
||||||
|
|
||||||
|
FMT_CONSTEXPR null_terminating_iterator(const Char *ptr, const Char *end)
|
||||||
|
: ptr_(ptr), end_(end) {}
|
||||||
|
|
||||||
|
template <typename Range>
|
||||||
|
FMT_CONSTEXPR explicit null_terminating_iterator(const Range &r)
|
||||||
|
: ptr_(r.begin()), end_(r.end()) {}
|
||||||
|
|
||||||
|
FMT_CONSTEXPR null_terminating_iterator &operator=(const Char *ptr) {
|
||||||
|
assert(ptr <= end_);
|
||||||
|
ptr_ = ptr;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
FMT_CONSTEXPR Char operator*() const {
|
||||||
|
return ptr_ != end_ ? *ptr_ : Char();
|
||||||
|
}
|
||||||
|
|
||||||
|
FMT_CONSTEXPR null_terminating_iterator operator++() {
|
||||||
|
++ptr_;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
FMT_CONSTEXPR null_terminating_iterator operator++(int) {
|
||||||
|
null_terminating_iterator result(*this);
|
||||||
|
++ptr_;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
FMT_CONSTEXPR null_terminating_iterator operator--() {
|
||||||
|
--ptr_;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
FMT_CONSTEXPR null_terminating_iterator operator+(difference_type n) {
|
||||||
|
return null_terminating_iterator(ptr_ + n, end_);
|
||||||
|
}
|
||||||
|
|
||||||
|
FMT_CONSTEXPR null_terminating_iterator operator-(difference_type n) {
|
||||||
|
return null_terminating_iterator(ptr_ - n, end_);
|
||||||
|
}
|
||||||
|
|
||||||
|
FMT_CONSTEXPR null_terminating_iterator operator+=(difference_type n) {
|
||||||
|
ptr_ += n;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
FMT_CONSTEXPR difference_type operator-(
|
||||||
|
null_terminating_iterator other) const {
|
||||||
|
return ptr_ - other.ptr_;
|
||||||
|
}
|
||||||
|
|
||||||
|
FMT_CONSTEXPR bool operator!=(null_terminating_iterator other) const {
|
||||||
|
return ptr_ != other.ptr_;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator>=(null_terminating_iterator other) const {
|
||||||
|
return ptr_ >= other.ptr_;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This should be a friend specialization pointer_from<Char> but the latter
|
||||||
|
// doesn't compile by gcc 5.1 due to a compiler bug.
|
||||||
|
template <typename CharT>
|
||||||
|
friend FMT_CONSTEXPR_DECL const CharT *pointer_from(
|
||||||
|
null_terminating_iterator<CharT> it);
|
||||||
|
|
||||||
|
private:
|
||||||
|
const Char *ptr_;
|
||||||
|
const Char *end_;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
FMT_CONSTEXPR const T *pointer_from(const T *p) { return p; }
|
||||||
|
|
||||||
|
template <typename Char>
|
||||||
|
FMT_CONSTEXPR const Char *pointer_from(null_terminating_iterator<Char> it) {
|
||||||
|
return it.ptr_;
|
||||||
|
}
|
||||||
|
|
||||||
|
// DEPRECATED: Parses the input as an unsigned integer. This function assumes
|
||||||
|
// that the first character is a digit and presence of a non-digit character at
|
||||||
|
// the end.
|
||||||
|
// it: an iterator pointing to the beginning of the input range.
|
||||||
|
template <typename Iterator, typename ErrorHandler>
|
||||||
|
FMT_CONSTEXPR unsigned parse_nonnegative_int(Iterator &it, ErrorHandler &&eh) {
|
||||||
|
assert('0' <= *it && *it <= '9');
|
||||||
|
if (*it == '0') {
|
||||||
|
++it;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
unsigned value = 0;
|
||||||
|
// Convert to unsigned to prevent a warning.
|
||||||
|
unsigned max_int = (std::numeric_limits<int>::max)();
|
||||||
|
unsigned big = max_int / 10;
|
||||||
|
do {
|
||||||
|
// Check for overflow.
|
||||||
|
if (value > big) {
|
||||||
|
value = max_int + 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
value = value * 10 + unsigned(*it - '0');
|
||||||
|
// Workaround for MSVC "setup_exception stack overflow" error:
|
||||||
|
auto next = it;
|
||||||
|
++next;
|
||||||
|
it = next;
|
||||||
|
} while ('0' <= *it && *it <= '9');
|
||||||
|
if (value > max_int)
|
||||||
|
eh.on_error("number is too big");
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
// 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>
|
template <bool IsSigned>
|
||||||
|
@ -133,7 +257,7 @@ class arg_converter: public function<void> {
|
||||||
// unsigned).
|
// unsigned).
|
||||||
template <typename T, typename Context, typename Char>
|
template <typename T, typename Context, typename Char>
|
||||||
void convert_arg(basic_format_arg<Context> &arg, Char type) {
|
void convert_arg(basic_format_arg<Context> &arg, Char type) {
|
||||||
fmt::visit(arg_converter<T, Context>(arg, type), arg);
|
visit_format_arg(arg_converter<T, Context>(arg, type), arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Converts an integer argument to char for printf.
|
// Converts an integer argument to char for printf.
|
||||||
|
@ -192,8 +316,16 @@ class printf_width_handler: public function<unsigned> {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <typename Char, typename Context>
|
||||||
|
void printf(basic_buffer<Char> &buf, basic_string_view<Char> format,
|
||||||
|
basic_format_args<Context> args) {
|
||||||
|
Context(std::back_inserter(buf), format, args).format();
|
||||||
|
}
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
|
|
||||||
|
using internal::printf; // For printing into memory_buffer.
|
||||||
|
|
||||||
template <typename Range>
|
template <typename Range>
|
||||||
class printf_arg_formatter;
|
class printf_arg_formatter;
|
||||||
|
|
||||||
|
@ -222,12 +354,12 @@ class printf_arg_formatter:
|
||||||
context_type &context_;
|
context_type &context_;
|
||||||
|
|
||||||
void write_null_pointer(char) {
|
void write_null_pointer(char) {
|
||||||
this->spec()->type_ = 0;
|
this->spec()->type = 0;
|
||||||
this->write("(nil)");
|
this->write("(nil)");
|
||||||
}
|
}
|
||||||
|
|
||||||
void write_null_pointer(wchar_t) {
|
void write_null_pointer(wchar_t) {
|
||||||
this->spec()->type_ = 0;
|
this->spec()->type = 0;
|
||||||
this->write(L"(nil)");
|
this->write(L"(nil)");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -243,7 +375,8 @@ class printf_arg_formatter:
|
||||||
*/
|
*/
|
||||||
printf_arg_formatter(internal::basic_buffer<char_type> &buffer,
|
printf_arg_formatter(internal::basic_buffer<char_type> &buffer,
|
||||||
format_specs &spec, context_type &ctx)
|
format_specs &spec, context_type &ctx)
|
||||||
: base(back_insert_range<internal::basic_buffer<char_type>>(buffer), &spec),
|
: base(back_insert_range<internal::basic_buffer<char_type>>(buffer), &spec,
|
||||||
|
ctx.locale()),
|
||||||
context_(ctx) {}
|
context_(ctx) {}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
|
@ -253,15 +386,15 @@ class printf_arg_formatter:
|
||||||
// use std::is_same instead.
|
// use std::is_same instead.
|
||||||
if (std::is_same<T, bool>::value) {
|
if (std::is_same<T, bool>::value) {
|
||||||
format_specs &fmt_spec = *this->spec();
|
format_specs &fmt_spec = *this->spec();
|
||||||
if (fmt_spec.type_ != 's')
|
if (fmt_spec.type != 's')
|
||||||
return base::operator()(value ? 1 : 0);
|
return base::operator()(value ? 1 : 0);
|
||||||
fmt_spec.type_ = 0;
|
fmt_spec.type = 0;
|
||||||
this->write(value != 0);
|
this->write(value != 0);
|
||||||
} else if (std::is_same<T, char_type>::value) {
|
} else if (std::is_same<T, char_type>::value) {
|
||||||
format_specs &fmt_spec = *this->spec();
|
format_specs &fmt_spec = *this->spec();
|
||||||
if (fmt_spec.type_ && fmt_spec.type_ != 'c')
|
if (fmt_spec.type && fmt_spec.type != 'c')
|
||||||
return (*this)(static_cast<int>(value));
|
return (*this)(static_cast<int>(value));
|
||||||
fmt_spec.flags_ = 0;
|
fmt_spec.flags = 0;
|
||||||
fmt_spec.align_ = ALIGN_RIGHT;
|
fmt_spec.align_ = ALIGN_RIGHT;
|
||||||
return base::operator()(value);
|
return base::operator()(value);
|
||||||
} else {
|
} else {
|
||||||
|
@ -280,7 +413,7 @@ class printf_arg_formatter:
|
||||||
iterator operator()(const char *value) {
|
iterator operator()(const char *value) {
|
||||||
if (value)
|
if (value)
|
||||||
base::operator()(value);
|
base::operator()(value);
|
||||||
else if (this->spec()->type_ == 'p')
|
else if (this->spec()->type == 'p')
|
||||||
write_null_pointer(char_type());
|
write_null_pointer(char_type());
|
||||||
else
|
else
|
||||||
this->write("(null)");
|
this->write("(null)");
|
||||||
|
@ -291,7 +424,7 @@ class printf_arg_formatter:
|
||||||
iterator operator()(const wchar_t *value) {
|
iterator operator()(const wchar_t *value) {
|
||||||
if (value)
|
if (value)
|
||||||
base::operator()(value);
|
base::operator()(value);
|
||||||
else if (this->spec()->type_ == 'p')
|
else if (this->spec()->type == 'p')
|
||||||
write_null_pointer(char_type());
|
write_null_pointer(char_type());
|
||||||
else
|
else
|
||||||
this->write(L"(null)");
|
this->write(L"(null)");
|
||||||
|
@ -310,7 +443,7 @@ class printf_arg_formatter:
|
||||||
iterator operator()(const void *value) {
|
iterator operator()(const void *value) {
|
||||||
if (value)
|
if (value)
|
||||||
return base::operator()(value);
|
return base::operator()(value);
|
||||||
this->spec()->type_ = 0;
|
this->spec()->type = 0;
|
||||||
write_null_pointer(char_type());
|
write_null_pointer(char_type());
|
||||||
return this->out();
|
return this->out();
|
||||||
}
|
}
|
||||||
|
@ -394,16 +527,16 @@ void basic_printf_context<OutputIt, Char, AF>::parse_flags(
|
||||||
spec.align_ = ALIGN_LEFT;
|
spec.align_ = ALIGN_LEFT;
|
||||||
break;
|
break;
|
||||||
case '+':
|
case '+':
|
||||||
spec.flags_ |= SIGN_FLAG | PLUS_FLAG;
|
spec.flags |= SIGN_FLAG | PLUS_FLAG;
|
||||||
break;
|
break;
|
||||||
case '0':
|
case '0':
|
||||||
spec.fill_ = '0';
|
spec.fill_ = '0';
|
||||||
break;
|
break;
|
||||||
case ' ':
|
case ' ':
|
||||||
spec.flags_ |= SIGN_FLAG;
|
spec.flags |= SIGN_FLAG;
|
||||||
break;
|
break;
|
||||||
case '#':
|
case '#':
|
||||||
spec.flags_ |= HASH_FLAG;
|
spec.flags |= HASH_FLAG;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
--it;
|
--it;
|
||||||
|
@ -453,8 +586,8 @@ unsigned basic_printf_context<OutputIt, Char, AF>::parse_header(
|
||||||
spec.width_ = parse_nonnegative_int(it, eh);
|
spec.width_ = parse_nonnegative_int(it, eh);
|
||||||
} else if (*it == '*') {
|
} else if (*it == '*') {
|
||||||
++it;
|
++it;
|
||||||
spec.width_ =
|
spec.width_ = visit_format_arg(
|
||||||
fmt::visit(internal::printf_width_handler<char_type>(spec), get_arg(it));
|
internal::printf_width_handler<char_type>(spec), get_arg(it));
|
||||||
}
|
}
|
||||||
return arg_index;
|
return arg_index;
|
||||||
}
|
}
|
||||||
|
@ -486,19 +619,19 @@ void basic_printf_context<OutputIt, Char, AF>::format() {
|
||||||
++it;
|
++it;
|
||||||
if ('0' <= *it && *it <= '9') {
|
if ('0' <= *it && *it <= '9') {
|
||||||
internal::error_handler eh;
|
internal::error_handler eh;
|
||||||
spec.precision_ = static_cast<int>(parse_nonnegative_int(it, eh));
|
spec.precision = static_cast<int>(parse_nonnegative_int(it, eh));
|
||||||
} else if (*it == '*') {
|
} else if (*it == '*') {
|
||||||
++it;
|
++it;
|
||||||
spec.precision_ =
|
spec.precision =
|
||||||
fmt::visit(internal::printf_precision_handler(), get_arg(it));
|
visit_format_arg(internal::printf_precision_handler(), get_arg(it));
|
||||||
} else {
|
} else {
|
||||||
spec.precision_ = 0;
|
spec.precision = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
format_arg arg = get_arg(it, arg_index);
|
format_arg arg = get_arg(it, arg_index);
|
||||||
if (spec.flag(HASH_FLAG) && fmt::visit(internal::is_zero_int(), arg))
|
if (spec.has(HASH_FLAG) && visit_format_arg(internal::is_zero_int(), arg))
|
||||||
spec.flags_ &= ~internal::to_unsigned<int>(HASH_FLAG);
|
spec.flags = static_cast<uint_least8_t>(spec.flags & (~internal::to_unsigned<int>(HASH_FLAG)));
|
||||||
if (spec.fill_ == '0') {
|
if (spec.fill_ == '0') {
|
||||||
if (arg.is_arithmetic())
|
if (arg.is_arithmetic())
|
||||||
spec.align_ = ALIGN_NUMERIC;
|
spec.align_ = ALIGN_NUMERIC;
|
||||||
|
@ -542,16 +675,17 @@ void basic_printf_context<OutputIt, Char, AF>::format() {
|
||||||
// Parse type.
|
// Parse type.
|
||||||
if (!*it)
|
if (!*it)
|
||||||
FMT_THROW(format_error("invalid format string"));
|
FMT_THROW(format_error("invalid format string"));
|
||||||
spec.type_ = static_cast<char>(*it++);
|
spec.type = static_cast<char>(*it++);
|
||||||
if (arg.is_integral()) {
|
if (arg.is_integral()) {
|
||||||
// Normalize type.
|
// Normalize type.
|
||||||
switch (spec.type_) {
|
switch (spec.type) {
|
||||||
case 'i': case 'u':
|
case 'i': case 'u':
|
||||||
spec.type_ = 'd';
|
spec.type = 'd';
|
||||||
break;
|
break;
|
||||||
case 'c':
|
case 'c':
|
||||||
// TODO: handle wchar_t better?
|
// TODO: handle wchar_t better?
|
||||||
fmt::visit(internal::char_converter<basic_printf_context>(arg), arg);
|
visit_format_arg(
|
||||||
|
internal::char_converter<basic_printf_context>(arg), arg);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -559,35 +693,50 @@ void basic_printf_context<OutputIt, Char, AF>::format() {
|
||||||
start = it;
|
start = it;
|
||||||
|
|
||||||
// Format argument.
|
// Format argument.
|
||||||
fmt::visit(AF(buffer, spec, *this), arg);
|
visit_format_arg(AF(buffer, spec, *this), arg);
|
||||||
}
|
}
|
||||||
buffer.append(pointer_from(start), pointer_from(it));
|
buffer.append(pointer_from(start), pointer_from(it));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Char, typename Context>
|
|
||||||
void printf(internal::basic_buffer<Char> &buf, basic_string_view<Char> format,
|
|
||||||
basic_format_args<Context> args) {
|
|
||||||
Context(std::back_inserter(buf), format, args).format();
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename Buffer>
|
template <typename Buffer>
|
||||||
struct printf_context {
|
struct basic_printf_context_t {
|
||||||
typedef basic_printf_context<
|
typedef basic_printf_context<
|
||||||
std::back_insert_iterator<Buffer>, typename Buffer::value_type> type;
|
std::back_insert_iterator<Buffer>, typename Buffer::value_type> type;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename ...Args>
|
typedef basic_printf_context_t<internal::buffer>::type printf_context;
|
||||||
inline format_arg_store<printf_context<internal::buffer>::type, Args...>
|
typedef basic_printf_context_t<internal::wbuffer>::type wprintf_context;
|
||||||
make_printf_args(const Args & ... args) {
|
|
||||||
return format_arg_store<printf_context<internal::buffer>::type, Args...>(
|
|
||||||
args...);
|
|
||||||
}
|
|
||||||
typedef basic_format_args<printf_context<internal::buffer>::type> printf_args;
|
|
||||||
typedef basic_format_args<printf_context<internal::wbuffer>::type> wprintf_args;
|
|
||||||
|
|
||||||
inline std::string vsprintf(string_view format, printf_args args) {
|
typedef basic_format_args<printf_context> printf_args;
|
||||||
memory_buffer buffer;
|
typedef basic_format_args<wprintf_context> wprintf_args;
|
||||||
printf(buffer, format, args);
|
|
||||||
|
/**
|
||||||
|
\rst
|
||||||
|
Constructs an `~fmt::format_arg_store` object that contains references to
|
||||||
|
arguments and can be implicitly converted to `~fmt::printf_args`.
|
||||||
|
\endrst
|
||||||
|
*/
|
||||||
|
template<typename... Args>
|
||||||
|
inline format_arg_store<printf_context, Args...>
|
||||||
|
make_printf_args(const Args &... args) { return {args...}; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
\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... Args>
|
||||||
|
inline format_arg_store<wprintf_context, Args...>
|
||||||
|
make_wprintf_args(const Args &... args) { return {args...}; }
|
||||||
|
|
||||||
|
template <typename S, typename Char = FMT_CHAR(S)>
|
||||||
|
inline std::basic_string<Char>
|
||||||
|
vsprintf(const S &format,
|
||||||
|
basic_format_args<typename basic_printf_context_t<
|
||||||
|
internal::basic_buffer<Char>>::type> args) {
|
||||||
|
basic_memory_buffer<Char> buffer;
|
||||||
|
printf(buffer, to_string_view(format), args);
|
||||||
return to_string(buffer);
|
return to_string(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -600,30 +749,24 @@ inline std::string vsprintf(string_view format, printf_args args) {
|
||||||
std::string message = fmt::sprintf("The answer is %d", 42);
|
std::string message = fmt::sprintf("The answer is %d", 42);
|
||||||
\endrst
|
\endrst
|
||||||
*/
|
*/
|
||||||
template <typename... Args>
|
template <typename S, typename... Args>
|
||||||
inline std::string sprintf(string_view format_str, const Args & ... args) {
|
inline FMT_ENABLE_IF_T(
|
||||||
return vsprintf(format_str,
|
internal::is_string<S>::value, std::basic_string<FMT_CHAR(S)>)
|
||||||
make_format_args<typename printf_context<internal::buffer>::type>(args...));
|
sprintf(const S &format, const Args & ... args) {
|
||||||
|
internal::check_format_string<Args...>(format);
|
||||||
|
typedef internal::basic_buffer<FMT_CHAR(S)> buffer;
|
||||||
|
typedef typename basic_printf_context_t<buffer>::type context;
|
||||||
|
format_arg_store<context, Args...> as{ args... };
|
||||||
|
return vsprintf(to_string_view(format),
|
||||||
|
basic_format_args<context>(as));
|
||||||
}
|
}
|
||||||
|
|
||||||
inline std::wstring vsprintf(wstring_view format, wprintf_args args) {
|
template <typename S, typename Char = FMT_CHAR(S)>
|
||||||
wmemory_buffer buffer;
|
inline int vfprintf(std::FILE *f, const S &format,
|
||||||
printf(buffer, format, args);
|
basic_format_args<typename basic_printf_context_t<
|
||||||
return to_string(buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename... Args>
|
|
||||||
inline std::wstring sprintf(wstring_view format_str, const Args & ... args) {
|
|
||||||
return vsprintf(format_str,
|
|
||||||
make_format_args<typename printf_context<internal::wbuffer>::type>(args...));
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename Char>
|
|
||||||
inline int vfprintf(std::FILE *f, basic_string_view<Char> format,
|
|
||||||
basic_format_args<typename printf_context<
|
|
||||||
internal::basic_buffer<Char>>::type> args) {
|
internal::basic_buffer<Char>>::type> args) {
|
||||||
basic_memory_buffer<Char> buffer;
|
basic_memory_buffer<Char> buffer;
|
||||||
printf(buffer, format, args);
|
printf(buffer, to_string_view(format), args);
|
||||||
std::size_t size = buffer.size();
|
std::size_t size = buffer.size();
|
||||||
return std::fwrite(
|
return std::fwrite(
|
||||||
buffer.data(), sizeof(Char), size, f) < size ? -1 : static_cast<int>(size);
|
buffer.data(), sizeof(Char), size, f) < size ? -1 : static_cast<int>(size);
|
||||||
|
@ -638,26 +781,22 @@ inline int vfprintf(std::FILE *f, basic_string_view<Char> format,
|
||||||
fmt::fprintf(stderr, "Don't %s!", "panic");
|
fmt::fprintf(stderr, "Don't %s!", "panic");
|
||||||
\endrst
|
\endrst
|
||||||
*/
|
*/
|
||||||
template <typename... Args>
|
template <typename S, typename... Args>
|
||||||
inline int fprintf(std::FILE *f, string_view format_str, const Args & ... args) {
|
inline FMT_ENABLE_IF_T(internal::is_string<S>::value, int)
|
||||||
auto vargs = make_format_args<
|
fprintf(std::FILE *f, const S &format, const Args & ... args) {
|
||||||
typename printf_context<internal::buffer>::type>(args...);
|
internal::check_format_string<Args...>(format);
|
||||||
return vfprintf<char>(f, format_str, vargs);
|
typedef internal::basic_buffer<FMT_CHAR(S)> buffer;
|
||||||
|
typedef typename basic_printf_context_t<buffer>::type context;
|
||||||
|
format_arg_store<context, Args...> as{ args... };
|
||||||
|
return vfprintf(f, to_string_view(format),
|
||||||
|
basic_format_args<context>(as));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename... Args>
|
template <typename S, typename Char = FMT_CHAR(S)>
|
||||||
inline int fprintf(std::FILE *f, wstring_view format_str,
|
inline int vprintf(const S &format,
|
||||||
const Args & ... args) {
|
basic_format_args<typename basic_printf_context_t<
|
||||||
return vfprintf(f, format_str,
|
internal::basic_buffer<Char>>::type> args) {
|
||||||
make_format_args<typename printf_context<internal::wbuffer>::type>(args...));
|
return vfprintf(stdout, to_string_view(format), args);
|
||||||
}
|
|
||||||
|
|
||||||
inline int vprintf(string_view format, printf_args args) {
|
|
||||||
return vfprintf(stdout, format, args);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline int vprintf(wstring_view format, wprintf_args args) {
|
|
||||||
return vfprintf(stdout, format, args);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -669,30 +808,24 @@ inline int vprintf(wstring_view format, wprintf_args args) {
|
||||||
fmt::printf("Elapsed time: %.2f seconds", 1.23);
|
fmt::printf("Elapsed time: %.2f seconds", 1.23);
|
||||||
\endrst
|
\endrst
|
||||||
*/
|
*/
|
||||||
template <typename... Args>
|
template <typename S, typename... Args>
|
||||||
inline int printf(string_view format_str, const Args & ... args) {
|
inline FMT_ENABLE_IF_T(internal::is_string<S>::value, int)
|
||||||
return vprintf(format_str,
|
printf(const S &format_str, const Args & ... args) {
|
||||||
make_format_args<typename printf_context<internal::buffer>::type>(args...));
|
internal::check_format_string<Args...>(format_str);
|
||||||
|
typedef internal::basic_buffer<FMT_CHAR(S)> buffer;
|
||||||
|
typedef typename basic_printf_context_t<buffer>::type context;
|
||||||
|
format_arg_store<context, Args...> as{ args... };
|
||||||
|
return vprintf(to_string_view(format_str),
|
||||||
|
basic_format_args<context>(as));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename... Args>
|
template <typename S, typename Char = FMT_CHAR(S)>
|
||||||
inline int printf(wstring_view format_str, const Args & ... args) {
|
inline int vfprintf(std::basic_ostream<Char> &os,
|
||||||
return vprintf(format_str,
|
const S &format,
|
||||||
make_format_args<typename printf_context<internal::wbuffer>::type>(args...));
|
basic_format_args<typename basic_printf_context_t<
|
||||||
}
|
internal::basic_buffer<Char>>::type> args) {
|
||||||
|
basic_memory_buffer<Char> buffer;
|
||||||
inline int vfprintf(std::ostream &os, string_view format_str,
|
printf(buffer, to_string_view(format), args);
|
||||||
printf_args args) {
|
|
||||||
memory_buffer buffer;
|
|
||||||
printf(buffer, format_str, args);
|
|
||||||
internal::write(os, buffer);
|
|
||||||
return static_cast<int>(buffer.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
inline int vfprintf(std::wostream &os, wstring_view format_str,
|
|
||||||
wprintf_args args) {
|
|
||||||
wmemory_buffer buffer;
|
|
||||||
printf(buffer, format_str, args);
|
|
||||||
internal::write(os, buffer);
|
internal::write(os, buffer);
|
||||||
return static_cast<int>(buffer.size());
|
return static_cast<int>(buffer.size());
|
||||||
}
|
}
|
||||||
|
@ -706,20 +839,16 @@ inline int vfprintf(std::wostream &os, wstring_view format_str,
|
||||||
fmt::fprintf(cerr, "Don't %s!", "panic");
|
fmt::fprintf(cerr, "Don't %s!", "panic");
|
||||||
\endrst
|
\endrst
|
||||||
*/
|
*/
|
||||||
template <typename... Args>
|
template <typename S, typename... Args>
|
||||||
inline int fprintf(std::ostream &os, string_view format_str,
|
inline FMT_ENABLE_IF_T(internal::is_string<S>::value, int)
|
||||||
const Args & ... args) {
|
fprintf(std::basic_ostream<FMT_CHAR(S)> &os,
|
||||||
auto vargs = make_format_args<
|
const S &format_str, const Args & ... args) {
|
||||||
typename printf_context<internal::buffer>::type>(args...);
|
internal::check_format_string<Args...>(format_str);
|
||||||
return vfprintf(os, format_str, vargs);
|
typedef internal::basic_buffer<FMT_CHAR(S)> buffer;
|
||||||
}
|
typedef typename basic_printf_context_t<buffer>::type context;
|
||||||
|
format_arg_store<context, Args...> as{ args... };
|
||||||
template <typename... Args>
|
return vfprintf(os, to_string_view(format_str),
|
||||||
inline int fprintf(std::wostream &os, wstring_view format_str,
|
basic_format_args<context>(as));
|
||||||
const Args & ... args) {
|
|
||||||
auto vargs = make_format_args<
|
|
||||||
typename printf_context<internal::buffer>::type>(args...);
|
|
||||||
return vfprintf(os, format_str, vargs);
|
|
||||||
}
|
}
|
||||||
FMT_END_NAMESPACE
|
FMT_END_NAMESPACE
|
||||||
|
|
||||||
|
|
38
externals/fmt/include/fmt/time.h
vendored
38
externals/fmt/include/fmt/time.h
vendored
|
@ -1,6 +1,6 @@
|
||||||
// Formatting library for C++ - time formatting
|
// Formatting library for C++ - time formatting
|
||||||
//
|
//
|
||||||
// Copyright (c) 2012 - 2016, Victor Zverovich
|
// Copyright (c) 2012 - present, Victor Zverovich
|
||||||
// All rights reserved.
|
// All rights reserved.
|
||||||
//
|
//
|
||||||
// For the license information refer to format.h.
|
// For the license information refer to format.h.
|
||||||
|
@ -10,6 +10,7 @@
|
||||||
|
|
||||||
#include "format.h"
|
#include "format.h"
|
||||||
#include <ctime>
|
#include <ctime>
|
||||||
|
#include <locale>
|
||||||
|
|
||||||
FMT_BEGIN_NAMESPACE
|
FMT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
|
@ -22,7 +23,7 @@ inline null<> localtime_r FMT_NOMACRO(...) { return null<>(); }
|
||||||
inline null<> localtime_s(...) { return null<>(); }
|
inline null<> localtime_s(...) { return null<>(); }
|
||||||
inline null<> gmtime_r(...) { return null<>(); }
|
inline null<> gmtime_r(...) { return null<>(); }
|
||||||
inline null<> gmtime_s(...) { return null<>(); }
|
inline null<> gmtime_s(...) { return null<>(); }
|
||||||
}
|
} // namespace internal
|
||||||
|
|
||||||
// Thread-safe replacement for std::localtime
|
// Thread-safe replacement for std::localtime
|
||||||
inline std::tm localtime(std::time_t time) {
|
inline std::tm localtime(std::time_t time) {
|
||||||
|
@ -46,18 +47,20 @@ inline std::tm localtime(std::time_t time) {
|
||||||
|
|
||||||
bool fallback(int res) { return res == 0; }
|
bool fallback(int res) { return res == 0; }
|
||||||
|
|
||||||
|
#if !FMT_MSC_VER
|
||||||
bool fallback(internal::null<>) {
|
bool fallback(internal::null<>) {
|
||||||
using namespace fmt::internal;
|
using namespace fmt::internal;
|
||||||
std::tm *tm = std::localtime(&time_);
|
std::tm *tm = std::localtime(&time_);
|
||||||
if (tm) tm_ = *tm;
|
if (tm) tm_ = *tm;
|
||||||
return tm != FMT_NULL;
|
return tm != FMT_NULL;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
dispatcher lt(time);
|
dispatcher lt(time);
|
||||||
if (lt.run())
|
|
||||||
return lt.tm_;
|
|
||||||
// Too big time values may be unsupported.
|
// Too big time values may be unsupported.
|
||||||
FMT_THROW(format_error("time_t value out of range"));
|
if (!lt.run())
|
||||||
|
FMT_THROW(format_error("time_t value out of range"));
|
||||||
|
return lt.tm_;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Thread-safe replacement for std::gmtime
|
// Thread-safe replacement for std::gmtime
|
||||||
|
@ -82,17 +85,19 @@ inline std::tm gmtime(std::time_t time) {
|
||||||
|
|
||||||
bool fallback(int res) { return res == 0; }
|
bool fallback(int res) { return res == 0; }
|
||||||
|
|
||||||
|
#if !FMT_MSC_VER
|
||||||
bool fallback(internal::null<>) {
|
bool fallback(internal::null<>) {
|
||||||
std::tm *tm = std::gmtime(&time_);
|
std::tm *tm = std::gmtime(&time_);
|
||||||
if (tm) tm_ = *tm;
|
if (tm) tm_ = *tm;
|
||||||
return tm != FMT_NULL;
|
return tm != FMT_NULL;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
dispatcher gt(time);
|
dispatcher gt(time);
|
||||||
if (gt.run())
|
|
||||||
return gt.tm_;
|
|
||||||
// Too big time values may be unsupported.
|
// Too big time values may be unsupported.
|
||||||
FMT_THROW(format_error("time_t value out of range"));
|
if (!gt.run())
|
||||||
|
FMT_THROW(format_error("time_t value out of range"));
|
||||||
|
return gt.tm_;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace internal {
|
namespace internal {
|
||||||
|
@ -111,22 +116,21 @@ template <typename Char>
|
||||||
struct formatter<std::tm, Char> {
|
struct formatter<std::tm, Char> {
|
||||||
template <typename ParseContext>
|
template <typename ParseContext>
|
||||||
auto parse(ParseContext &ctx) -> decltype(ctx.begin()) {
|
auto parse(ParseContext &ctx) -> decltype(ctx.begin()) {
|
||||||
auto it = internal::null_terminating_iterator<Char>(ctx);
|
auto it = ctx.begin();
|
||||||
if (*it == ':')
|
if (it != ctx.end() && *it == ':')
|
||||||
++it;
|
++it;
|
||||||
auto end = it;
|
auto end = it;
|
||||||
while (*end && *end != '}')
|
while (end != ctx.end() && *end != '}')
|
||||||
++end;
|
++end;
|
||||||
tm_format.reserve(end - it + 1);
|
tm_format.reserve(internal::to_unsigned(end - it + 1));
|
||||||
using internal::pointer_from;
|
tm_format.append(it, end);
|
||||||
tm_format.append(pointer_from(it), pointer_from(end));
|
|
||||||
tm_format.push_back('\0');
|
tm_format.push_back('\0');
|
||||||
return pointer_from(end);
|
return end;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename FormatContext>
|
template <typename FormatContext>
|
||||||
auto format(const std::tm &tm, FormatContext &ctx) -> decltype(ctx.out()) {
|
auto format(const std::tm &tm, FormatContext &ctx) -> decltype(ctx.out()) {
|
||||||
internal::basic_buffer<Char> &buf = internal::get_container(ctx.out());
|
basic_memory_buffer<Char> buf;
|
||||||
std::size_t start = buf.size();
|
std::size_t start = buf.size();
|
||||||
for (;;) {
|
for (;;) {
|
||||||
std::size_t size = buf.capacity() - start;
|
std::size_t size = buf.capacity() - start;
|
||||||
|
@ -146,7 +150,7 @@ struct formatter<std::tm, Char> {
|
||||||
const std::size_t MIN_GROWTH = 10;
|
const std::size_t MIN_GROWTH = 10;
|
||||||
buf.reserve(buf.capacity() + (size > MIN_GROWTH ? size : MIN_GROWTH));
|
buf.reserve(buf.capacity() + (size > MIN_GROWTH ? size : MIN_GROWTH));
|
||||||
}
|
}
|
||||||
return ctx.out();
|
return std::copy(buf.begin(), buf.end(), ctx.out());
|
||||||
}
|
}
|
||||||
|
|
||||||
basic_memory_buffer<Char> tm_format;
|
basic_memory_buffer<Char> tm_format;
|
||||||
|
|
26
externals/fmt/src/format.cc
vendored
26
externals/fmt/src/format.cc
vendored
|
@ -9,16 +9,16 @@
|
||||||
|
|
||||||
FMT_BEGIN_NAMESPACE
|
FMT_BEGIN_NAMESPACE
|
||||||
template struct internal::basic_data<void>;
|
template struct internal::basic_data<void>;
|
||||||
|
template FMT_API internal::locale_ref::locale_ref(const std::locale &loc);
|
||||||
|
template FMT_API std::locale internal::locale_ref::get<std::locale>() const;
|
||||||
|
|
||||||
// Explicit instantiations for char.
|
// Explicit instantiations for char.
|
||||||
|
|
||||||
template FMT_API char internal::thousands_sep(locale_provider *lp);
|
template FMT_API char internal::thousands_sep_impl(locale_ref);
|
||||||
|
|
||||||
template void internal::basic_buffer<char>::append(const char *, const char *);
|
template FMT_API void internal::basic_buffer<char>::append(const char *, const char *);
|
||||||
|
|
||||||
template void basic_fixed_buffer<char>::grow(std::size_t);
|
template FMT_API void internal::arg_map<format_context>::init(
|
||||||
|
|
||||||
template void internal::arg_map<format_context>::init(
|
|
||||||
const basic_format_args<format_context> &args);
|
const basic_format_args<format_context> &args);
|
||||||
|
|
||||||
template FMT_API int internal::char_traits<char>::format_float(
|
template FMT_API int internal::char_traits<char>::format_float(
|
||||||
|
@ -30,16 +30,22 @@ template FMT_API int internal::char_traits<char>::format_float(
|
||||||
template FMT_API std::string internal::vformat<char>(
|
template FMT_API std::string internal::vformat<char>(
|
||||||
string_view, basic_format_args<format_context>);
|
string_view, basic_format_args<format_context>);
|
||||||
|
|
||||||
|
template FMT_API format_context::iterator internal::vformat_to(
|
||||||
|
internal::buffer &, string_view, basic_format_args<format_context>);
|
||||||
|
|
||||||
|
template FMT_API void internal::sprintf_format(
|
||||||
|
double, internal::buffer &, core_format_specs);
|
||||||
|
template FMT_API void internal::sprintf_format(
|
||||||
|
long double, internal::buffer &, core_format_specs);
|
||||||
|
|
||||||
// Explicit instantiations for wchar_t.
|
// Explicit instantiations for wchar_t.
|
||||||
|
|
||||||
template FMT_API wchar_t internal::thousands_sep(locale_provider *);
|
template FMT_API wchar_t internal::thousands_sep_impl(locale_ref);
|
||||||
|
|
||||||
template void internal::basic_buffer<wchar_t>::append(
|
template FMT_API void internal::basic_buffer<wchar_t>::append(
|
||||||
const wchar_t *, const wchar_t *);
|
const wchar_t *, const wchar_t *);
|
||||||
|
|
||||||
template void basic_fixed_buffer<wchar_t>::grow(std::size_t);
|
template FMT_API void internal::arg_map<wformat_context>::init(
|
||||||
|
|
||||||
template void internal::arg_map<wformat_context>::init(
|
|
||||||
const basic_format_args<wformat_context> &);
|
const basic_format_args<wformat_context> &);
|
||||||
|
|
||||||
template FMT_API int internal::char_traits<wchar_t>::format_float(
|
template FMT_API int internal::char_traits<wchar_t>::format_float(
|
||||||
|
|
2
externals/fmt/support/AndroidManifest.xml
vendored
2
externals/fmt/support/AndroidManifest.xml
vendored
|
@ -1 +1 @@
|
||||||
<manifest package="fmt" />
|
<manifest package="net.fmtlib" />
|
||||||
|
|
25
externals/fmt/support/build.gradle
vendored
25
externals/fmt/support/build.gradle
vendored
|
@ -1,14 +1,24 @@
|
||||||
|
|
||||||
// General gradle arguments for root project
|
// General gradle arguments for root project
|
||||||
buildscript {
|
buildscript {
|
||||||
repositories {
|
repositories {
|
||||||
google()
|
google()
|
||||||
jcenter()
|
jcenter()
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath 'com.android.tools.build:gradle:3.0.1'
|
//
|
||||||
|
// https://developer.android.com/studio/releases/gradle-plugin
|
||||||
|
//
|
||||||
|
// Notice that 3.1.3 here is the version of [Android Gradle Plugin]
|
||||||
|
// Accroding to URL above you will need Gradle 4.4 or higher
|
||||||
|
//
|
||||||
|
classpath 'com.android.tools.build:gradle:3.1.3'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
repositories {
|
||||||
|
google()
|
||||||
|
jcenter()
|
||||||
|
}
|
||||||
|
|
||||||
// Output: Shared library (.so) for Android
|
// Output: Shared library (.so) for Android
|
||||||
apply plugin: 'com.android.library'
|
apply plugin: 'com.android.library'
|
||||||
|
@ -24,20 +34,17 @@ android {
|
||||||
splits {
|
splits {
|
||||||
abi {
|
abi {
|
||||||
enable true
|
enable true
|
||||||
// Be general, as much as possible ...
|
|
||||||
// universalApk true
|
|
||||||
|
|
||||||
// Specify platforms for Application
|
// Specify platforms for Application
|
||||||
reset()
|
reset()
|
||||||
include "x86", "x86_64", "armeabi-v7a", "arm64-v8a"
|
include "arm64-v8a", "armeabi-v7a", "x86_64"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
minSdkVersion 21 // Android 5.0+
|
minSdkVersion 21 // Android 5.0+
|
||||||
targetSdkVersion 25 // Follow Compile SDK
|
targetSdkVersion 25 // Follow Compile SDK
|
||||||
versionCode 16 // Follow release count
|
versionCode 20 // Follow release count
|
||||||
versionName "4.1.0" // Follow Official version
|
versionName "5.2.1" // Follow Official version
|
||||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||||
|
|
||||||
externalNativeBuild {
|
externalNativeBuild {
|
||||||
|
@ -46,7 +53,7 @@ android {
|
||||||
arguments "-DBUILD_SHARED_LIBS=true" // Build shared object
|
arguments "-DBUILD_SHARED_LIBS=true" // Build shared object
|
||||||
arguments "-DFMT_TEST=false" // Skip test
|
arguments "-DFMT_TEST=false" // Skip test
|
||||||
arguments "-DFMT_DOC=false" // Skip document
|
arguments "-DFMT_DOC=false" // Skip document
|
||||||
cppFlags "-std=c++14"
|
cppFlags "-std=c++17"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
println("Gradle CMake Plugin: ")
|
println("Gradle CMake Plugin: ")
|
||||||
|
|
11
externals/fmt/support/cmake/fmt.pc.in
vendored
Normal file
11
externals/fmt/support/cmake/fmt.pc.in
vendored
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
prefix=@CMAKE_INSTALL_PREFIX@
|
||||||
|
exec_prefix=@CMAKE_INSTALL_PREFIX@
|
||||||
|
libdir=@CMAKE_INSTALL_FULL_LIBDIR@
|
||||||
|
includedir=@CMAKE_INSTALL_FULL_INCLUDEDIR@
|
||||||
|
|
||||||
|
Name: fmt
|
||||||
|
Description: A modern formatting library
|
||||||
|
Version: @FMT_VERSION@
|
||||||
|
Libs: -L${libdir} -lfmt
|
||||||
|
Cflags: -I${includedir}
|
||||||
|
|
10
externals/fmt/support/rst2md.py
vendored
Normal file → Executable file
10
externals/fmt/support/rst2md.py
vendored
Normal file → Executable file
|
@ -1,6 +1,7 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
# reStructuredText (RST) to GitHub-flavored Markdown converter
|
# reStructuredText (RST) to GitHub-flavored Markdown converter
|
||||||
|
|
||||||
import re
|
import re, sys
|
||||||
from docutils import core, nodes, writers
|
from docutils import core, nodes, writers
|
||||||
|
|
||||||
|
|
||||||
|
@ -35,6 +36,9 @@ class Translator(nodes.NodeVisitor):
|
||||||
self.version = re.match(r'(\d+\.\d+\.\d+).*', node.children[0]).group(1)
|
self.version = re.match(r'(\d+\.\d+\.\d+).*', node.children[0]).group(1)
|
||||||
raise nodes.SkipChildren
|
raise nodes.SkipChildren
|
||||||
|
|
||||||
|
def visit_title_reference(self, node):
|
||||||
|
raise Exception(node)
|
||||||
|
|
||||||
def depart_title(self, node):
|
def depart_title(self, node):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@ -149,3 +153,7 @@ class MDWriter(writers.Writer):
|
||||||
def convert(rst_path):
|
def convert(rst_path):
|
||||||
"""Converts RST file to Markdown."""
|
"""Converts RST file to Markdown."""
|
||||||
return core.publish_file(source_path=rst_path, writer=MDWriter())
|
return core.publish_file(source_path=rst_path, writer=MDWriter())
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
convert(sys.argv[1])
|
||||||
|
|
13
externals/fmt/test/CMakeLists.txt
vendored
13
externals/fmt/test/CMakeLists.txt
vendored
|
@ -85,10 +85,14 @@ function(add_fmt_test name)
|
||||||
endfunction()
|
endfunction()
|
||||||
|
|
||||||
add_fmt_test(assert-test)
|
add_fmt_test(assert-test)
|
||||||
|
add_fmt_test(chrono-test)
|
||||||
add_fmt_test(core-test)
|
add_fmt_test(core-test)
|
||||||
add_fmt_test(gtest-extra-test)
|
add_fmt_test(gtest-extra-test)
|
||||||
add_fmt_test(format-test mock-allocator.h)
|
add_fmt_test(format-test mock-allocator.h)
|
||||||
add_fmt_test(format-impl-test)
|
if (NOT (MSVC AND BUILD_SHARED_LIBS))
|
||||||
|
add_fmt_test(format-impl-test)
|
||||||
|
endif ()
|
||||||
|
add_fmt_test(locale-test)
|
||||||
add_fmt_test(ostream-test)
|
add_fmt_test(ostream-test)
|
||||||
add_fmt_test(printf-test)
|
add_fmt_test(printf-test)
|
||||||
add_fmt_test(time-test)
|
add_fmt_test(time-test)
|
||||||
|
@ -165,8 +169,11 @@ if (FMT_PEDANTIC)
|
||||||
"-DCXX_STANDARD_FLAG=${CXX_STANDARD_FLAG}"
|
"-DCXX_STANDARD_FLAG=${CXX_STANDARD_FLAG}"
|
||||||
"-DPEDANTIC_COMPILE_FLAGS=${PEDANTIC_COMPILE_FLAGS}"
|
"-DPEDANTIC_COMPILE_FLAGS=${PEDANTIC_COMPILE_FLAGS}"
|
||||||
"-DSUPPORTS_USER_DEFINED_LITERALS=${SUPPORTS_USER_DEFINED_LITERALS}")
|
"-DSUPPORTS_USER_DEFINED_LITERALS=${SUPPORTS_USER_DEFINED_LITERALS}")
|
||||||
|
endif ()
|
||||||
|
|
||||||
# test if the targets are findable from the build directory
|
# These tests are disabled on Windows because they take too long.
|
||||||
|
if (FMT_PEDANTIC AND NOT WIN32)
|
||||||
|
# Test if the targets are found from the build directory.
|
||||||
add_test(find-package-test ${CMAKE_CTEST_COMMAND}
|
add_test(find-package-test ${CMAKE_CTEST_COMMAND}
|
||||||
-C ${CMAKE_BUILD_TYPE}
|
-C ${CMAKE_BUILD_TYPE}
|
||||||
--build-and-test
|
--build-and-test
|
||||||
|
@ -181,7 +188,7 @@ if (FMT_PEDANTIC)
|
||||||
"-DPEDANTIC_COMPILE_FLAGS=${PEDANTIC_COMPILE_FLAGS}"
|
"-DPEDANTIC_COMPILE_FLAGS=${PEDANTIC_COMPILE_FLAGS}"
|
||||||
"-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}")
|
"-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}")
|
||||||
|
|
||||||
# test if the targets are findable when add_subdirectory is used
|
# Test if the targets are found when add_subdirectory is used.
|
||||||
add_test(add-subdirectory-test ${CMAKE_CTEST_COMMAND}
|
add_test(add-subdirectory-test ${CMAKE_CTEST_COMMAND}
|
||||||
-C ${CMAKE_BUILD_TYPE}
|
-C ${CMAKE_BUILD_TYPE}
|
||||||
--build-and-test
|
--build-and-test
|
||||||
|
|
185
externals/fmt/test/chrono-test.cc
vendored
Normal file
185
externals/fmt/test/chrono-test.cc
vendored
Normal file
|
@ -0,0 +1,185 @@
|
||||||
|
// Formatting library for C++ - time formatting tests
|
||||||
|
//
|
||||||
|
// Copyright (c) 2012 - present, Victor Zverovich
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// For the license information refer to format.h.
|
||||||
|
|
||||||
|
#include "fmt/chrono.h"
|
||||||
|
#include "gtest-extra.h"
|
||||||
|
|
||||||
|
#include <iomanip>
|
||||||
|
|
||||||
|
std::tm make_tm() {
|
||||||
|
auto time = std::tm();
|
||||||
|
time.tm_mday = 1;
|
||||||
|
return time;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::tm make_hour(int h) {
|
||||||
|
auto time = make_tm();
|
||||||
|
time.tm_hour = h;
|
||||||
|
return time;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::tm make_minute(int m) {
|
||||||
|
auto time = make_tm();
|
||||||
|
time.tm_min = m;
|
||||||
|
return time;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::tm make_second(int s) {
|
||||||
|
auto time = make_tm();
|
||||||
|
time.tm_sec = s;
|
||||||
|
return time;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string format_tm(const std::tm &time, const char *spec,
|
||||||
|
const std::locale &loc) {
|
||||||
|
auto &facet = std::use_facet<std::time_put<char>>(loc);
|
||||||
|
std::ostringstream os;
|
||||||
|
os.imbue(loc);
|
||||||
|
facet.put(os, os, ' ', &time, spec, spec + std::strlen(spec));
|
||||||
|
return os.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
#define EXPECT_TIME(spec, time, duration) { \
|
||||||
|
std::locale loc("ja_JP.utf8"); \
|
||||||
|
EXPECT_EQ(format_tm(time, spec, loc), \
|
||||||
|
fmt::format(loc, "{:" spec "}", duration)); \
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ChronoTest, FormatDefault) {
|
||||||
|
EXPECT_EQ("42s", fmt::format("{}", std::chrono::seconds(42)));
|
||||||
|
EXPECT_EQ("42as",
|
||||||
|
fmt::format("{}", std::chrono::duration<int, std::atto>(42)));
|
||||||
|
EXPECT_EQ("42fs",
|
||||||
|
fmt::format("{}", std::chrono::duration<int, std::femto>(42)));
|
||||||
|
EXPECT_EQ("42ps",
|
||||||
|
fmt::format("{}", std::chrono::duration<int, std::pico>(42)));
|
||||||
|
EXPECT_EQ("42ns", fmt::format("{}", std::chrono::nanoseconds(42)));
|
||||||
|
EXPECT_EQ("42µs", fmt::format("{}", std::chrono::microseconds(42)));
|
||||||
|
EXPECT_EQ("42ms", fmt::format("{}", std::chrono::milliseconds(42)));
|
||||||
|
EXPECT_EQ("42cs",
|
||||||
|
fmt::format("{}", std::chrono::duration<int, std::centi>(42)));
|
||||||
|
EXPECT_EQ("42ds",
|
||||||
|
fmt::format("{}", std::chrono::duration<int, std::deci>(42)));
|
||||||
|
EXPECT_EQ("42s", fmt::format("{}", std::chrono::seconds(42)));
|
||||||
|
EXPECT_EQ("42das",
|
||||||
|
fmt::format("{}", std::chrono::duration<int, std::deca>(42)));
|
||||||
|
EXPECT_EQ("42hs",
|
||||||
|
fmt::format("{}", std::chrono::duration<int, std::hecto>(42)));
|
||||||
|
EXPECT_EQ("42ks",
|
||||||
|
fmt::format("{}", std::chrono::duration<int, std::kilo>(42)));
|
||||||
|
EXPECT_EQ("42Ms",
|
||||||
|
fmt::format("{}", std::chrono::duration<int, std::mega>(42)));
|
||||||
|
EXPECT_EQ("42Gs",
|
||||||
|
fmt::format("{}", std::chrono::duration<int, std::giga>(42)));
|
||||||
|
EXPECT_EQ("42Ts",
|
||||||
|
fmt::format("{}", std::chrono::duration<int, std::tera>(42)));
|
||||||
|
EXPECT_EQ("42Ps",
|
||||||
|
fmt::format("{}", std::chrono::duration<int, std::peta>(42)));
|
||||||
|
EXPECT_EQ("42Es",
|
||||||
|
fmt::format("{}", std::chrono::duration<int, std::exa>(42)));
|
||||||
|
EXPECT_EQ("42m", fmt::format("{}", std::chrono::minutes(42)));
|
||||||
|
EXPECT_EQ("42h", fmt::format("{}", std::chrono::hours(42)));
|
||||||
|
EXPECT_EQ("42[15]s",
|
||||||
|
fmt::format("{}",
|
||||||
|
std::chrono::duration<int, std::ratio<15, 1>>(42)));
|
||||||
|
EXPECT_EQ("42[15/4]s",
|
||||||
|
fmt::format("{}",
|
||||||
|
std::chrono::duration<int, std::ratio<15, 4>>(42)));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ChronoTest, Align) {
|
||||||
|
auto s = std::chrono::seconds(42);
|
||||||
|
EXPECT_EQ("42s ", fmt::format("{:5}", s));
|
||||||
|
EXPECT_EQ("42s ", fmt::format("{:{}}", s, 5));
|
||||||
|
EXPECT_EQ(" 42s", fmt::format("{:>5}", s));
|
||||||
|
EXPECT_EQ("**42s**", fmt::format("{:*^7}", s));
|
||||||
|
EXPECT_EQ("03:25:45 ",
|
||||||
|
fmt::format("{:12%H:%M:%S}", std::chrono::seconds(12345)));
|
||||||
|
EXPECT_EQ(" 03:25:45",
|
||||||
|
fmt::format("{:>12%H:%M:%S}", std::chrono::seconds(12345)));
|
||||||
|
EXPECT_EQ("~~03:25:45~~",
|
||||||
|
fmt::format("{:~^12%H:%M:%S}", std::chrono::seconds(12345)));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ChronoTest, FormatSpecs) {
|
||||||
|
EXPECT_EQ("%", fmt::format("{:%%}", std::chrono::seconds(0)));
|
||||||
|
EXPECT_EQ("\n", fmt::format("{:%n}", std::chrono::seconds(0)));
|
||||||
|
EXPECT_EQ("\t", fmt::format("{:%t}", std::chrono::seconds(0)));
|
||||||
|
EXPECT_EQ("00", fmt::format("{:%S}", std::chrono::seconds(0)));
|
||||||
|
EXPECT_EQ("00", fmt::format("{:%S}", std::chrono::seconds(60)));
|
||||||
|
EXPECT_EQ("42", fmt::format("{:%S}", std::chrono::seconds(42)));
|
||||||
|
EXPECT_EQ("01.234", fmt::format("{:%S}", std::chrono::milliseconds(1234)));
|
||||||
|
EXPECT_EQ("00", fmt::format("{:%M}", std::chrono::minutes(0)));
|
||||||
|
EXPECT_EQ("00", fmt::format("{:%M}", std::chrono::minutes(60)));
|
||||||
|
EXPECT_EQ("42", fmt::format("{:%M}", std::chrono::minutes(42)));
|
||||||
|
EXPECT_EQ("01", fmt::format("{:%M}", std::chrono::seconds(61)));
|
||||||
|
EXPECT_EQ("00", fmt::format("{:%H}", std::chrono::hours(0)));
|
||||||
|
EXPECT_EQ("00", fmt::format("{:%H}", std::chrono::hours(24)));
|
||||||
|
EXPECT_EQ("14", fmt::format("{:%H}", std::chrono::hours(14)));
|
||||||
|
EXPECT_EQ("01", fmt::format("{:%H}", std::chrono::minutes(61)));
|
||||||
|
EXPECT_EQ("12", fmt::format("{:%I}", std::chrono::hours(0)));
|
||||||
|
EXPECT_EQ("12", fmt::format("{:%I}", std::chrono::hours(12)));
|
||||||
|
EXPECT_EQ("12", fmt::format("{:%I}", std::chrono::hours(24)));
|
||||||
|
EXPECT_EQ("04", fmt::format("{:%I}", std::chrono::hours(4)));
|
||||||
|
EXPECT_EQ("02", fmt::format("{:%I}", std::chrono::hours(14)));
|
||||||
|
EXPECT_EQ("03:25:45",
|
||||||
|
fmt::format("{:%H:%M:%S}", std::chrono::seconds(12345)));
|
||||||
|
EXPECT_EQ("03:25", fmt::format("{:%R}", std::chrono::seconds(12345)));
|
||||||
|
EXPECT_EQ("03:25:45", fmt::format("{:%T}", std::chrono::seconds(12345)));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ChronoTest, InvalidSpecs) {
|
||||||
|
auto sec = std::chrono::seconds(0);
|
||||||
|
EXPECT_THROW_MSG(fmt::format("{:%a}", sec), fmt::format_error, "no date");
|
||||||
|
EXPECT_THROW_MSG(fmt::format("{:%A}", sec), fmt::format_error, "no date");
|
||||||
|
EXPECT_THROW_MSG(fmt::format("{:%c}", sec), fmt::format_error, "no date");
|
||||||
|
EXPECT_THROW_MSG(fmt::format("{:%x}", sec), fmt::format_error, "no date");
|
||||||
|
EXPECT_THROW_MSG(fmt::format("{:%Ex}", sec), fmt::format_error, "no date");
|
||||||
|
EXPECT_THROW_MSG(fmt::format("{:%X}", sec), fmt::format_error, "no date");
|
||||||
|
EXPECT_THROW_MSG(fmt::format("{:%EX}", sec), fmt::format_error, "no date");
|
||||||
|
EXPECT_THROW_MSG(fmt::format("{:%D}", sec), fmt::format_error, "no date");
|
||||||
|
EXPECT_THROW_MSG(fmt::format("{:%F}", sec), fmt::format_error, "no date");
|
||||||
|
EXPECT_THROW_MSG(fmt::format("{:%Ec}", sec), fmt::format_error, "no date");
|
||||||
|
EXPECT_THROW_MSG(fmt::format("{:%w}", sec), fmt::format_error, "no date");
|
||||||
|
EXPECT_THROW_MSG(fmt::format("{:%u}", sec), fmt::format_error, "no date");
|
||||||
|
EXPECT_THROW_MSG(fmt::format("{:%b}", sec), fmt::format_error, "no date");
|
||||||
|
EXPECT_THROW_MSG(fmt::format("{:%B}", sec), fmt::format_error, "no date");
|
||||||
|
EXPECT_THROW_MSG(fmt::format("{:%z}", sec), fmt::format_error, "no date");
|
||||||
|
EXPECT_THROW_MSG(fmt::format("{:%Z}", sec), fmt::format_error, "no date");
|
||||||
|
EXPECT_THROW_MSG(fmt::format("{:%q}", sec), fmt::format_error,
|
||||||
|
"invalid format");
|
||||||
|
EXPECT_THROW_MSG(fmt::format("{:%Eq}", sec), fmt::format_error,
|
||||||
|
"invalid format");
|
||||||
|
EXPECT_THROW_MSG(fmt::format("{:%Oq}", sec), fmt::format_error,
|
||||||
|
"invalid format");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ChronoTest, Locale) {
|
||||||
|
const char *loc_name = "ja_JP.utf8";
|
||||||
|
bool has_locale = false;
|
||||||
|
std::locale loc;
|
||||||
|
try {
|
||||||
|
loc = std::locale(loc_name);
|
||||||
|
has_locale = true;
|
||||||
|
} catch (const std::runtime_error &) {}
|
||||||
|
if (!has_locale) {
|
||||||
|
fmt::print("{} locale is missing.\n", loc_name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
EXPECT_TIME("%OH", make_hour(14), std::chrono::hours(14));
|
||||||
|
EXPECT_TIME("%OI", make_hour(14), std::chrono::hours(14));
|
||||||
|
EXPECT_TIME("%OM", make_minute(42), std::chrono::minutes(42));
|
||||||
|
EXPECT_TIME("%OS", make_second(42), std::chrono::seconds(42));
|
||||||
|
auto time = make_tm();
|
||||||
|
time.tm_hour = 3;
|
||||||
|
time.tm_min = 25;
|
||||||
|
time.tm_sec = 45;
|
||||||
|
auto sec = std::chrono::seconds(12345);
|
||||||
|
EXPECT_TIME("%r", time, sec);
|
||||||
|
EXPECT_TIME("%p", time, sec);
|
||||||
|
}
|
167
externals/fmt/test/core-test.cc
vendored
167
externals/fmt/test/core-test.cc
vendored
|
@ -13,6 +13,7 @@
|
||||||
#include <limits>
|
#include <limits>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
#include "test-assert.h"
|
#include "test-assert.h"
|
||||||
|
|
||||||
|
@ -64,6 +65,7 @@ struct formatter<test_struct, Char> {
|
||||||
};
|
};
|
||||||
FMT_END_NAMESPACE
|
FMT_END_NAMESPACE
|
||||||
|
|
||||||
|
#if !FMT_GCC_VERSION || FMT_GCC_VERSION >= 470
|
||||||
TEST(BufferTest, Noncopyable) {
|
TEST(BufferTest, Noncopyable) {
|
||||||
EXPECT_FALSE(std::is_copy_constructible<basic_buffer<char> >::value);
|
EXPECT_FALSE(std::is_copy_constructible<basic_buffer<char> >::value);
|
||||||
#if !FMT_MSC_VER
|
#if !FMT_MSC_VER
|
||||||
|
@ -79,11 +81,12 @@ TEST(BufferTest, Nonmoveable) {
|
||||||
EXPECT_FALSE(std::is_move_assignable<basic_buffer<char> >::value);
|
EXPECT_FALSE(std::is_move_assignable<basic_buffer<char> >::value);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// A test buffer with a dummy grow method.
|
// A test buffer with a dummy grow method.
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct test_buffer : basic_buffer<T> {
|
struct test_buffer : basic_buffer<T> {
|
||||||
void grow(std::size_t capacity) { this->set(nullptr, capacity); }
|
void grow(std::size_t capacity) { this->set(FMT_NULL, capacity); }
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
|
@ -103,7 +106,7 @@ struct mock_buffer : basic_buffer<T> {
|
||||||
TEST(BufferTest, Ctor) {
|
TEST(BufferTest, Ctor) {
|
||||||
{
|
{
|
||||||
mock_buffer<int> buffer;
|
mock_buffer<int> buffer;
|
||||||
EXPECT_EQ(nullptr, &buffer[0]);
|
EXPECT_EQ(FMT_NULL, &buffer[0]);
|
||||||
EXPECT_EQ(static_cast<size_t>(0), buffer.size());
|
EXPECT_EQ(static_cast<size_t>(0), buffer.size());
|
||||||
EXPECT_EQ(static_cast<size_t>(0), buffer.capacity());
|
EXPECT_EQ(static_cast<size_t>(0), buffer.capacity());
|
||||||
}
|
}
|
||||||
|
@ -218,14 +221,16 @@ struct custom_context {
|
||||||
|
|
||||||
const char *format(const T &, custom_context& ctx) {
|
const char *format(const T &, custom_context& ctx) {
|
||||||
ctx.called = true;
|
ctx.called = true;
|
||||||
return nullptr;
|
return FMT_NULL;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
bool called;
|
bool called;
|
||||||
|
|
||||||
fmt::parse_context parse_context() { return fmt::parse_context(""); }
|
fmt::format_parse_context parse_context() {
|
||||||
|
return fmt::format_parse_context("");
|
||||||
|
}
|
||||||
void advance_to(const char *) {}
|
void advance_to(const char *) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -364,8 +369,8 @@ TEST(ArgTest, WStringArg) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(ArgTest, PointerArg) {
|
TEST(ArgTest, PointerArg) {
|
||||||
void *p = nullptr;
|
void *p = FMT_NULL;
|
||||||
const void *cp = nullptr;
|
const void *cp = FMT_NULL;
|
||||||
CHECK_ARG_(char, cp, p);
|
CHECK_ARG_(char, cp, p);
|
||||||
CHECK_ARG_(wchar_t, cp, p);
|
CHECK_ARG_(wchar_t, cp, p);
|
||||||
CHECK_ARG(cp, );
|
CHECK_ARG(cp, );
|
||||||
|
@ -376,7 +381,7 @@ struct check_custom {
|
||||||
fmt::basic_format_arg<fmt::format_context>::handle h) const {
|
fmt::basic_format_arg<fmt::format_context>::handle h) const {
|
||||||
struct test_buffer : fmt::internal::basic_buffer<char> {
|
struct test_buffer : fmt::internal::basic_buffer<char> {
|
||||||
char data[10];
|
char data[10];
|
||||||
test_buffer() : basic_buffer(data, 0, 10) {}
|
test_buffer() : fmt::internal::basic_buffer<char>(data, 0, 10) {}
|
||||||
void grow(std::size_t) {}
|
void grow(std::size_t) {}
|
||||||
} buffer;
|
} buffer;
|
||||||
fmt::internal::basic_buffer<char> &base = buffer;
|
fmt::internal::basic_buffer<char> &base = buffer;
|
||||||
|
@ -451,6 +456,76 @@ TEST(CoreTest, IsEnumConvertibleToInt) {
|
||||||
EXPECT_TRUE((fmt::convert_to_int<enum_with_underlying_type, char>::value));
|
EXPECT_TRUE((fmt::convert_to_int<enum_with_underlying_type, char>::value));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace my_ns {
|
||||||
|
template <typename Char>
|
||||||
|
class my_string {
|
||||||
|
public:
|
||||||
|
my_string(const Char *s) : s_(s) {}
|
||||||
|
const Char * data() const FMT_NOEXCEPT { return s_.data(); }
|
||||||
|
std::size_t length() const FMT_NOEXCEPT { return s_.size(); }
|
||||||
|
operator const Char*() const { return s_.c_str(); }
|
||||||
|
private:
|
||||||
|
std::basic_string<Char> s_;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Char>
|
||||||
|
inline fmt::basic_string_view<Char>
|
||||||
|
to_string_view(const my_string<Char> &s) FMT_NOEXCEPT {
|
||||||
|
return { s.data(), s.length() };
|
||||||
|
}
|
||||||
|
|
||||||
|
struct non_string {};
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace FakeQt {
|
||||||
|
class QString {
|
||||||
|
public:
|
||||||
|
QString(const wchar_t *s) : s_(std::make_shared<std::wstring>(s)) {}
|
||||||
|
const wchar_t *utf16() const FMT_NOEXCEPT { return s_->data(); }
|
||||||
|
int size() const FMT_NOEXCEPT { return static_cast<int>(s_->size()); }
|
||||||
|
#ifdef FMT_STRING_VIEW
|
||||||
|
operator FMT_STRING_VIEW<wchar_t>() const FMT_NOEXCEPT { return *s_; }
|
||||||
|
#endif
|
||||||
|
private:
|
||||||
|
std::shared_ptr<std::wstring> s_;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline fmt::basic_string_view<wchar_t> to_string_view(
|
||||||
|
const QString &s) FMT_NOEXCEPT {
|
||||||
|
return {s.utf16(),
|
||||||
|
static_cast<std::size_t>(s.size())};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
class IsStringTest : public testing::Test {};
|
||||||
|
|
||||||
|
typedef ::testing::Types<char, wchar_t, char16_t, char32_t> StringCharTypes;
|
||||||
|
TYPED_TEST_CASE(IsStringTest, StringCharTypes);
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
template <typename Char>
|
||||||
|
struct derived_from_string_view : fmt::basic_string_view<Char> {};
|
||||||
|
}
|
||||||
|
|
||||||
|
TYPED_TEST(IsStringTest, IsString) {
|
||||||
|
EXPECT_TRUE((fmt::internal::is_string<TypeParam *>::value));
|
||||||
|
EXPECT_TRUE((fmt::internal::is_string<const TypeParam *>::value));
|
||||||
|
EXPECT_TRUE((fmt::internal::is_string<TypeParam[2]>::value));
|
||||||
|
EXPECT_TRUE((fmt::internal::is_string<const TypeParam[2]>::value));
|
||||||
|
EXPECT_TRUE((fmt::internal::is_string<std::basic_string<TypeParam>>::value));
|
||||||
|
EXPECT_TRUE(
|
||||||
|
(fmt::internal::is_string<fmt::basic_string_view<TypeParam>>::value));
|
||||||
|
EXPECT_TRUE(
|
||||||
|
(fmt::internal::is_string<derived_from_string_view<TypeParam>>::value));
|
||||||
|
#ifdef FMT_STRING_VIEW
|
||||||
|
EXPECT_TRUE((fmt::internal::is_string<FMT_STRING_VIEW<TypeParam>>::value));
|
||||||
|
#endif
|
||||||
|
EXPECT_TRUE((fmt::internal::is_string<my_ns::my_string<TypeParam>>::value));
|
||||||
|
EXPECT_FALSE((fmt::internal::is_string<my_ns::non_string>::value));
|
||||||
|
EXPECT_TRUE((fmt::internal::is_string<FakeQt::QString>::value));
|
||||||
|
}
|
||||||
|
|
||||||
TEST(CoreTest, Format) {
|
TEST(CoreTest, Format) {
|
||||||
// This should work without including fmt/format.h.
|
// This should work without including fmt/format.h.
|
||||||
#ifdef FMT_FORMAT_H_
|
#ifdef FMT_FORMAT_H_
|
||||||
|
@ -458,3 +533,81 @@ TEST(CoreTest, Format) {
|
||||||
#endif
|
#endif
|
||||||
EXPECT_EQ(fmt::format("{}", 42), "42");
|
EXPECT_EQ(fmt::format("{}", 42), "42");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(CoreTest, FormatTo) {
|
||||||
|
// This should work without including fmt/format.h.
|
||||||
|
#ifdef FMT_FORMAT_H_
|
||||||
|
# error fmt/format.h must not be included in the core test
|
||||||
|
#endif
|
||||||
|
std::string s;
|
||||||
|
fmt::format_to(std::back_inserter(s), "{}", 42);
|
||||||
|
EXPECT_EQ(s, "42");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(CoreTest, ToStringViewForeignStrings) {
|
||||||
|
using namespace my_ns;
|
||||||
|
using namespace FakeQt;
|
||||||
|
EXPECT_EQ(to_string_view(my_string<char>("42")), "42");
|
||||||
|
EXPECT_EQ(to_string_view(my_string<wchar_t>(L"42")), L"42");
|
||||||
|
EXPECT_EQ(to_string_view(QString(L"42")), L"42");
|
||||||
|
fmt::internal::type type =
|
||||||
|
fmt::internal::get_type<fmt::format_context, my_string<char>>::value;
|
||||||
|
EXPECT_EQ(type, fmt::internal::string_type);
|
||||||
|
type =
|
||||||
|
fmt::internal::get_type<fmt::wformat_context, my_string<wchar_t>>::value;
|
||||||
|
EXPECT_EQ(type, fmt::internal::string_type);
|
||||||
|
type = fmt::internal::get_type<fmt::wformat_context, QString>::value;
|
||||||
|
EXPECT_EQ(type, fmt::internal::string_type);
|
||||||
|
// Does not compile: only wide format contexts are compatible with QString!
|
||||||
|
// type = fmt::internal::get_type<fmt::format_context, QString>::value;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(CoreTest, FormatForeignStrings) {
|
||||||
|
using namespace my_ns;
|
||||||
|
using namespace FakeQt;
|
||||||
|
EXPECT_EQ(fmt::format(my_string<char>("{}"), 42), "42");
|
||||||
|
EXPECT_EQ(fmt::format(my_string<wchar_t>(L"{}"), 42), L"42");
|
||||||
|
EXPECT_EQ(fmt::format(QString(L"{}"), 42), L"42");
|
||||||
|
EXPECT_EQ(fmt::format(QString(L"{}"), my_string<wchar_t>(L"42")), L"42");
|
||||||
|
EXPECT_EQ(fmt::format(my_string<wchar_t>(L"{}"), QString(L"42")), L"42");
|
||||||
|
}
|
||||||
|
|
||||||
|
struct implicitly_convertible_to_string_view {
|
||||||
|
operator fmt::string_view() const { return "foo"; }
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST(FormatterTest, FormatImplicitlyConvertibleToStringView) {
|
||||||
|
EXPECT_EQ("foo", fmt::format("{}", implicitly_convertible_to_string_view()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// std::is_constructible is broken in MSVC until version 2015.
|
||||||
|
#if FMT_USE_EXPLICIT && (!FMT_MSC_VER || FMT_MSC_VER >= 1900)
|
||||||
|
struct explicitly_convertible_to_string_view {
|
||||||
|
explicit operator fmt::string_view() const { return "foo"; }
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST(FormatterTest, FormatExplicitlyConvertibleToStringView) {
|
||||||
|
EXPECT_EQ("foo", fmt::format("{}", explicitly_convertible_to_string_view()));
|
||||||
|
}
|
||||||
|
|
||||||
|
struct explicitly_convertible_to_wstring_view {
|
||||||
|
explicit operator fmt::wstring_view() const { return L"foo"; }
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST(FormatterTest, FormatExplicitlyConvertibleToWStringView) {
|
||||||
|
EXPECT_EQ(L"foo",
|
||||||
|
fmt::format(L"{}", explicitly_convertible_to_wstring_view()));
|
||||||
|
}
|
||||||
|
|
||||||
|
struct explicitly_convertible_to_string_like {
|
||||||
|
template <
|
||||||
|
typename String,
|
||||||
|
typename = typename std::enable_if<
|
||||||
|
std::is_constructible<String, const char*, std::size_t>::value>::type>
|
||||||
|
FMT_EXPLICIT operator String() const { return String("foo", 3u); }
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST(FormatterTest, FormatExplicitlyConvertibleToStringLike) {
|
||||||
|
EXPECT_EQ("foo", fmt::format("{}", explicitly_convertible_to_string_like()));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
4
externals/fmt/test/custom-formatter-test.cc
vendored
4
externals/fmt/test/custom-formatter-test.cc
vendored
|
@ -26,8 +26,8 @@ class custom_arg_formatter :
|
||||||
using base::operator();
|
using base::operator();
|
||||||
|
|
||||||
iterator operator()(double value) {
|
iterator operator()(double value) {
|
||||||
// Comparing a float to 0.0 is safe
|
// Comparing a float to 0.0 is safe.
|
||||||
if (round(value * pow(10, spec()->precision())) == 0.0)
|
if (round(value * pow(10, spec()->precision)) == 0.0)
|
||||||
value = 0;
|
value = 0;
|
||||||
return base::operator()(value);
|
return base::operator()(value);
|
||||||
}
|
}
|
||||||
|
|
56
externals/fmt/test/format-impl-test.cc
vendored
56
externals/fmt/test/format-impl-test.cc
vendored
|
@ -24,6 +24,12 @@
|
||||||
#undef min
|
#undef min
|
||||||
#undef max
|
#undef max
|
||||||
|
|
||||||
|
#if FMT_HAS_CPP_ATTRIBUTE(noreturn)
|
||||||
|
# define FMT_NORETURN [[noreturn]]
|
||||||
|
#else
|
||||||
|
# define FMT_NORETURN
|
||||||
|
#endif
|
||||||
|
|
||||||
using fmt::internal::fp;
|
using fmt::internal::fp;
|
||||||
|
|
||||||
template <bool is_iec559>
|
template <bool is_iec559>
|
||||||
|
@ -96,6 +102,11 @@ TEST(FPTest, GetCachedPower) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(FPTest, Grisu2FormatCompilesWithNonIEEEDouble) {
|
||||||
|
fmt::memory_buffer buf;
|
||||||
|
grisu2_format(4.2f, buf, fmt::core_format_specs());
|
||||||
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct ValueExtractor: fmt::internal::function<T> {
|
struct ValueExtractor: fmt::internal::function<T> {
|
||||||
T operator()(T value) {
|
T operator()(T value) {
|
||||||
|
@ -118,16 +129,17 @@ TEST(FormatTest, ArgConverter) {
|
||||||
|
|
||||||
TEST(FormatTest, FormatNegativeNaN) {
|
TEST(FormatTest, FormatNegativeNaN) {
|
||||||
double nan = std::numeric_limits<double>::quiet_NaN();
|
double nan = std::numeric_limits<double>::quiet_NaN();
|
||||||
if (fmt::internal::fputil::isnegative(-nan))
|
if (std::signbit(-nan))
|
||||||
EXPECT_EQ("-nan", fmt::format("{}", -nan));
|
EXPECT_EQ("-nan", fmt::format("{}", -nan));
|
||||||
else
|
else
|
||||||
fmt::print("Warning: compiler doesn't handle negative NaN correctly");
|
fmt::print("Warning: compiler doesn't handle negative NaN correctly");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(FormatTest, StrError) {
|
TEST(FormatTest, StrError) {
|
||||||
char *message = nullptr;
|
char *message = FMT_NULL;
|
||||||
char buffer[BUFFER_SIZE];
|
char buffer[BUFFER_SIZE];
|
||||||
EXPECT_ASSERT(fmt::safe_strerror(EDOM, message = nullptr, 0), "invalid buffer");
|
EXPECT_ASSERT(fmt::safe_strerror(EDOM, message = FMT_NULL, 0),
|
||||||
|
"invalid buffer");
|
||||||
EXPECT_ASSERT(fmt::safe_strerror(EDOM, message = buffer, 0),
|
EXPECT_ASSERT(fmt::safe_strerror(EDOM, message = buffer, 0),
|
||||||
"invalid buffer");
|
"invalid buffer");
|
||||||
buffer[0] = 'x';
|
buffer[0] = 'x';
|
||||||
|
@ -140,7 +152,7 @@ TEST(FormatTest, StrError) {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int result = fmt::safe_strerror(error_code, message = buffer, BUFFER_SIZE);
|
int result = fmt::safe_strerror(error_code, message = buffer, BUFFER_SIZE);
|
||||||
EXPECT_EQ(0, result);
|
EXPECT_EQ(result, 0);
|
||||||
std::size_t message_size = std::strlen(message);
|
std::size_t message_size = std::strlen(message);
|
||||||
EXPECT_GE(BUFFER_SIZE - 1u, message_size);
|
EXPECT_GE(BUFFER_SIZE - 1u, message_size);
|
||||||
EXPECT_EQ(get_system_error(error_code), message);
|
EXPECT_EQ(get_system_error(error_code), message);
|
||||||
|
@ -195,8 +207,40 @@ TEST(FormatTest, CountCodePoints) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(ColorsTest, Colors) {
|
TEST(ColorsTest, Colors) {
|
||||||
EXPECT_WRITE(stdout, fmt::print(fmt::rgb(255,20,30), "rgb(255,20,30)"),
|
EXPECT_WRITE(stdout, fmt::print(fg(fmt::rgb(255, 20, 30)), "rgb(255,20,30)"),
|
||||||
"\x1b[38;2;255;020;030mrgb(255,20,30)\x1b[0m");
|
"\x1b[38;2;255;020;030mrgb(255,20,30)\x1b[0m");
|
||||||
EXPECT_WRITE(stdout, fmt::print(fmt::color::blue, "blue"),
|
EXPECT_WRITE(stdout, fmt::print(fg(fmt::color::blue), "blue"),
|
||||||
"\x1b[38;2;000;000;255mblue\x1b[0m");
|
"\x1b[38;2;000;000;255mblue\x1b[0m");
|
||||||
|
EXPECT_WRITE(
|
||||||
|
stdout,
|
||||||
|
fmt::print(fg(fmt::color::blue) | bg(fmt::color::red), "two color"),
|
||||||
|
"\x1b[38;2;000;000;255m\x1b[48;2;255;000;000mtwo color\x1b[0m");
|
||||||
|
EXPECT_WRITE(stdout, fmt::print(fmt::emphasis::bold, "bold"),
|
||||||
|
"\x1b[1mbold\x1b[0m");
|
||||||
|
EXPECT_WRITE(stdout, fmt::print(fmt::emphasis::italic, "italic"),
|
||||||
|
"\x1b[3mitalic\x1b[0m");
|
||||||
|
EXPECT_WRITE(stdout, fmt::print(fmt::emphasis::underline, "underline"),
|
||||||
|
"\x1b[4munderline\x1b[0m");
|
||||||
|
EXPECT_WRITE(stdout,
|
||||||
|
fmt::print(fmt::emphasis::strikethrough, "strikethrough"),
|
||||||
|
"\x1b[9mstrikethrough\x1b[0m");
|
||||||
|
EXPECT_WRITE(
|
||||||
|
stdout,
|
||||||
|
fmt::print(fg(fmt::color::blue) | fmt::emphasis::bold, "blue/bold"),
|
||||||
|
"\x1b[1m\x1b[38;2;000;000;255mblue/bold\x1b[0m");
|
||||||
|
EXPECT_WRITE(stderr, fmt::print(stderr, fmt::emphasis::bold, "bold error"),
|
||||||
|
"\x1b[1mbold error\x1b[0m");
|
||||||
|
EXPECT_WRITE(stderr, fmt::print(stderr, fg(fmt::color::blue), "blue log"),
|
||||||
|
"\x1b[38;2;000;000;255mblue log\x1b[0m");
|
||||||
|
EXPECT_WRITE(stdout, fmt::print(fmt::text_style(), "hi"), "hi");
|
||||||
|
EXPECT_WRITE(stdout, fmt::print(fg(fmt::terminal_color::red), "tred"),
|
||||||
|
"\x1b[31mtred\x1b[0m");
|
||||||
|
EXPECT_WRITE(stdout, fmt::print(bg(fmt::terminal_color::cyan), "tcyan"),
|
||||||
|
"\x1b[46mtcyan\x1b[0m");
|
||||||
|
EXPECT_WRITE(stdout,
|
||||||
|
fmt::print(fg(fmt::terminal_color::bright_green), "tbgreen"),
|
||||||
|
"\x1b[92mtbgreen\x1b[0m");
|
||||||
|
EXPECT_WRITE(stdout,
|
||||||
|
fmt::print(bg(fmt::terminal_color::bright_magenta), "tbmagenta"),
|
||||||
|
"\x1b[105mtbmagenta\x1b[0m");
|
||||||
}
|
}
|
||||||
|
|
322
externals/fmt/test/format-test.cc
vendored
322
externals/fmt/test/format-test.cc
vendored
|
@ -12,6 +12,7 @@
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
// Check if fmt/format.h compiles with windows.h included before it.
|
// Check if fmt/format.h compiles with windows.h included before it.
|
||||||
|
@ -44,6 +45,38 @@ using testing::StrictMock;
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
#if !FMT_GCC_VERSION || FMT_GCC_VERSION >= 408
|
||||||
|
template <typename Char, typename T>
|
||||||
|
bool check_enabled_formatter() {
|
||||||
|
static_assert(
|
||||||
|
std::is_default_constructible<fmt::formatter<T, Char>>::value, "");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Char, typename... T>
|
||||||
|
void check_enabled_formatters() {
|
||||||
|
auto dummy = {check_enabled_formatter<Char, T>()...};
|
||||||
|
(void)dummy;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(FormatterTest, TestFormattersEnabled) {
|
||||||
|
check_enabled_formatters<char,
|
||||||
|
bool, char, signed char, unsigned char, short, unsigned short,
|
||||||
|
int, unsigned, long, unsigned long, long long, unsigned long long,
|
||||||
|
float, double, long double, void*, const void*,
|
||||||
|
char*, const char*, std::string>();
|
||||||
|
check_enabled_formatters<wchar_t,
|
||||||
|
bool, wchar_t, signed char, unsigned char, short, unsigned short,
|
||||||
|
int, unsigned, long, unsigned long, long long, unsigned long long,
|
||||||
|
float, double, long double, void*, const void*,
|
||||||
|
wchar_t*, const wchar_t*, std::wstring>();
|
||||||
|
#if FMT_USE_NULLPTR
|
||||||
|
check_enabled_formatters<char, std::nullptr_t>();
|
||||||
|
check_enabled_formatters<wchar_t, std::nullptr_t>();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// Format value using the standard library.
|
// Format value using the standard library.
|
||||||
template <typename Char, typename T>
|
template <typename Char, typename T>
|
||||||
void std_format(const T &value, std::basic_string<Char> &result) {
|
void std_format(const T &value, std::basic_string<Char> &result) {
|
||||||
|
@ -160,13 +193,16 @@ TEST(UtilTest, ParseNonnegativeInt) {
|
||||||
fmt::print("Skipping parse_nonnegative_int test\n");
|
fmt::print("Skipping parse_nonnegative_int test\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const char *s = "10000000000";
|
fmt::string_view s = "10000000000";
|
||||||
|
auto begin = s.begin(), end = s.end();
|
||||||
EXPECT_THROW_MSG(
|
EXPECT_THROW_MSG(
|
||||||
parse_nonnegative_int(s, fmt::internal::error_handler()),
|
parse_nonnegative_int(begin, end, fmt::internal::error_handler()),
|
||||||
fmt::format_error, "number is too big");
|
fmt::format_error, "number is too big");
|
||||||
s = "2147483649";
|
s = "2147483649";
|
||||||
|
begin = s.begin();
|
||||||
|
end = s.end();
|
||||||
EXPECT_THROW_MSG(
|
EXPECT_THROW_MSG(
|
||||||
parse_nonnegative_int(s, fmt::internal::error_handler()),
|
parse_nonnegative_int(begin, end, fmt::internal::error_handler()),
|
||||||
fmt::format_error, "number is too big");
|
fmt::format_error, "number is too big");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -185,6 +221,35 @@ TEST(IteratorTest, TruncatingIterator) {
|
||||||
EXPECT_EQ(it.base(), p + 1);
|
EXPECT_EQ(it.base(), p + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(IteratorTest, TruncatingBackInserter) {
|
||||||
|
std::string buffer;
|
||||||
|
auto bi = std::back_inserter(buffer);
|
||||||
|
fmt::internal::truncating_iterator<decltype(bi)> it(bi, 2);
|
||||||
|
*it++ = '4';
|
||||||
|
*it++ = '2';
|
||||||
|
*it++ = '1';
|
||||||
|
EXPECT_EQ(buffer.size(), 2);
|
||||||
|
EXPECT_EQ(buffer, "42");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(IteratorTest, IsOutputIterator) {
|
||||||
|
EXPECT_TRUE(fmt::internal::is_output_iterator<char*>::value);
|
||||||
|
EXPECT_FALSE(fmt::internal::is_output_iterator<const char*>::value);
|
||||||
|
EXPECT_FALSE(fmt::internal::is_output_iterator<std::string>::value);
|
||||||
|
EXPECT_TRUE(fmt::internal::is_output_iterator<
|
||||||
|
std::back_insert_iterator<std::string>>::value);
|
||||||
|
EXPECT_TRUE(fmt::internal::is_output_iterator<
|
||||||
|
std::string::iterator>::value);
|
||||||
|
EXPECT_FALSE(fmt::internal::is_output_iterator<
|
||||||
|
std::string::const_iterator>::value);
|
||||||
|
EXPECT_FALSE(fmt::internal::is_output_iterator<std::list<char>>::value);
|
||||||
|
EXPECT_TRUE(fmt::internal::is_output_iterator<
|
||||||
|
std::list<char>::iterator>::value);
|
||||||
|
EXPECT_FALSE(fmt::internal::is_output_iterator<
|
||||||
|
std::list<char>::const_iterator>::value);
|
||||||
|
EXPECT_FALSE(fmt::internal::is_output_iterator<uint32_pair>::value);
|
||||||
|
}
|
||||||
|
|
||||||
TEST(MemoryBufferTest, Ctor) {
|
TEST(MemoryBufferTest, Ctor) {
|
||||||
basic_memory_buffer<char, 123> buffer;
|
basic_memory_buffer<char, 123> buffer;
|
||||||
EXPECT_EQ(static_cast<size_t>(0), buffer.size());
|
EXPECT_EQ(static_cast<size_t>(0), buffer.size());
|
||||||
|
@ -212,7 +277,7 @@ TEST(AllocatorTest, allocator_ref) {
|
||||||
test_allocator_ref ref2(ref);
|
test_allocator_ref ref2(ref);
|
||||||
check_forwarding(alloc, ref2);
|
check_forwarding(alloc, ref2);
|
||||||
test_allocator_ref ref3;
|
test_allocator_ref ref3;
|
||||||
EXPECT_EQ(nullptr, ref3.get());
|
EXPECT_EQ(FMT_NULL, ref3.get());
|
||||||
ref3 = ref;
|
ref3 = ref;
|
||||||
check_forwarding(alloc, ref3);
|
check_forwarding(alloc, ref3);
|
||||||
}
|
}
|
||||||
|
@ -228,7 +293,7 @@ static void check_move_buffer(const char *str,
|
||||||
EXPECT_EQ(str, std::string(&buffer2[0], buffer2.size()));
|
EXPECT_EQ(str, std::string(&buffer2[0], buffer2.size()));
|
||||||
EXPECT_EQ(5u, buffer2.capacity());
|
EXPECT_EQ(5u, buffer2.capacity());
|
||||||
// Move should transfer allocator.
|
// Move should transfer allocator.
|
||||||
EXPECT_EQ(nullptr, buffer.get_allocator().get());
|
EXPECT_EQ(FMT_NULL, buffer.get_allocator().get());
|
||||||
EXPECT_EQ(alloc, buffer2.get_allocator().get());
|
EXPECT_EQ(alloc, buffer2.get_allocator().get());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -313,7 +378,7 @@ TEST(MemoryBufferTest, Grow) {
|
||||||
TEST(MemoryBufferTest, Allocator) {
|
TEST(MemoryBufferTest, Allocator) {
|
||||||
typedef allocator_ref< mock_allocator<char> > TestAllocator;
|
typedef allocator_ref< mock_allocator<char> > TestAllocator;
|
||||||
basic_memory_buffer<char, 10, TestAllocator> buffer;
|
basic_memory_buffer<char, 10, TestAllocator> buffer;
|
||||||
EXPECT_EQ(nullptr, buffer.get_allocator().get());
|
EXPECT_EQ(FMT_NULL, buffer.get_allocator().get());
|
||||||
StrictMock< mock_allocator<char> > alloc;
|
StrictMock< mock_allocator<char> > alloc;
|
||||||
char mem;
|
char mem;
|
||||||
{
|
{
|
||||||
|
@ -351,29 +416,6 @@ TEST(MemoryBufferTest, ExceptionInDeallocate) {
|
||||||
EXPECT_CALL(alloc, deallocate(&mem2[0], 2 * size));
|
EXPECT_CALL(alloc, deallocate(&mem2[0], 2 * size));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(FixedBufferTest, Ctor) {
|
|
||||||
char array[10] = "garbage";
|
|
||||||
fmt::basic_fixed_buffer<char> buffer(array, sizeof(array));
|
|
||||||
EXPECT_EQ(static_cast<size_t>(0), buffer.size());
|
|
||||||
EXPECT_EQ(10u, buffer.capacity());
|
|
||||||
EXPECT_EQ(array, buffer.data());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(FixedBufferTest, CompileTimeSizeCtor) {
|
|
||||||
char array[10] = "garbage";
|
|
||||||
fmt::basic_fixed_buffer<char> buffer(array);
|
|
||||||
EXPECT_EQ(static_cast<size_t>(0), buffer.size());
|
|
||||||
EXPECT_EQ(10u, buffer.capacity());
|
|
||||||
EXPECT_EQ(array, buffer.data());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(FixedBufferTest, BufferOverflow) {
|
|
||||||
char array[10];
|
|
||||||
fmt::basic_fixed_buffer<char> buffer(array);
|
|
||||||
buffer.resize(10);
|
|
||||||
EXPECT_THROW_MSG(buffer.resize(11), std::runtime_error, "buffer overflow");
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
TEST(UtilTest, UTF16ToUTF8) {
|
TEST(UtilTest, UTF16ToUTF8) {
|
||||||
std::string s = "ёжик";
|
std::string s = "ёжик";
|
||||||
|
@ -476,7 +518,7 @@ TEST(UtilTest, FormatSystemError) {
|
||||||
fmt::print("warning: std::allocator allocates {} chars", max_size);
|
fmt::print("warning: std::allocator allocates {} chars", max_size);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
fmt::format_system_error(message, EDOM, fmt::string_view(nullptr, max_size));
|
fmt::format_system_error(message, EDOM, fmt::string_view(FMT_NULL, max_size));
|
||||||
EXPECT_EQ(fmt::format("error {}", EDOM), to_string(message));
|
EXPECT_EQ(fmt::format("error {}", EDOM), to_string(message));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -564,17 +606,6 @@ TEST(StringViewTest, Ctor) {
|
||||||
EXPECT_EQ(4u, string_view(std::string("defg")).size());
|
EXPECT_EQ(4u, string_view(std::string("defg")).size());
|
||||||
}
|
}
|
||||||
|
|
||||||
// GCC 4.6 doesn't have std::is_copy_*.
|
|
||||||
#if FMT_GCC_VERSION && FMT_GCC_VERSION >= 407
|
|
||||||
TEST(WriterTest, NotCopyConstructible) {
|
|
||||||
EXPECT_FALSE(std::is_copy_constructible<fmt::writer>::value);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(WriterTest, NotCopyAssignable) {
|
|
||||||
EXPECT_FALSE(std::is_copy_assignable<fmt::writer>::value);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
TEST(WriterTest, Data) {
|
TEST(WriterTest, Data) {
|
||||||
memory_buffer buf;
|
memory_buffer buf;
|
||||||
fmt::writer w(buf);
|
fmt::writer w(buf);
|
||||||
|
@ -682,9 +713,15 @@ TEST(FormatToTest, Format) {
|
||||||
EXPECT_EQ("part1part2", s);
|
EXPECT_EQ("part1part2", s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(FormatToTest, WideString) {
|
||||||
|
std::vector<wchar_t> buf;
|
||||||
|
fmt::format_to(std::back_inserter(buf), L"{}{}", 42, L'\0');
|
||||||
|
EXPECT_STREQ(buf.data(), L"42");
|
||||||
|
}
|
||||||
|
|
||||||
TEST(FormatToTest, FormatToNonbackInsertIteratorWithSignAndNumericAlignment) {
|
TEST(FormatToTest, FormatToNonbackInsertIteratorWithSignAndNumericAlignment) {
|
||||||
char buffer[16] = {};
|
char buffer[16] = {};
|
||||||
fmt::format_to(buffer, "{: =+}", 42.0);
|
fmt::format_to(fmt::internal::make_checked(buffer, 16), "{: =+}", 42.0);
|
||||||
EXPECT_STREQ("+42", buffer);
|
EXPECT_STREQ("+42", buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -737,6 +774,7 @@ TEST(FormatterTest, ArgErrors) {
|
||||||
EXPECT_THROW_MSG(format("{?}"), format_error, "invalid format string");
|
EXPECT_THROW_MSG(format("{?}"), format_error, "invalid format string");
|
||||||
EXPECT_THROW_MSG(format("{0"), format_error, "invalid format string");
|
EXPECT_THROW_MSG(format("{0"), format_error, "invalid format string");
|
||||||
EXPECT_THROW_MSG(format("{0}"), format_error, "argument index out of range");
|
EXPECT_THROW_MSG(format("{0}"), format_error, "argument index out of range");
|
||||||
|
EXPECT_THROW_MSG(format("{00}", 42), format_error, "invalid format string");
|
||||||
|
|
||||||
char format_str[BUFFER_SIZE];
|
char format_str[BUFFER_SIZE];
|
||||||
safe_sprintf(format_str, "{%u", INT_MAX);
|
safe_sprintf(format_str, "{%u", INT_MAX);
|
||||||
|
@ -754,7 +792,7 @@ TEST(FormatterTest, ArgErrors) {
|
||||||
template <int N>
|
template <int N>
|
||||||
struct TestFormat {
|
struct TestFormat {
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
static std::string format(fmt::string_view format_str, const Args & ... args) {
|
static std::string format(fmt::string_view format_str, const Args &... args) {
|
||||||
return TestFormat<N - 1>::format(format_str, N - 1, args...);
|
return TestFormat<N - 1>::format(format_str, N - 1, args...);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -762,7 +800,7 @@ struct TestFormat {
|
||||||
template <>
|
template <>
|
||||||
struct TestFormat<0> {
|
struct TestFormat<0> {
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
static std::string format(fmt::string_view format_str, const Args & ... args) {
|
static std::string format(fmt::string_view format_str, const Args &... args) {
|
||||||
return fmt::format(format_str, args...);
|
return fmt::format(format_str, args...);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -906,6 +944,7 @@ TEST(FormatterTest, Fill) {
|
||||||
EXPECT_EQ("abc**", format("{0:*<5}", "abc"));
|
EXPECT_EQ("abc**", format("{0:*<5}", "abc"));
|
||||||
EXPECT_EQ("**0xface", format("{0:*>8}", reinterpret_cast<void*>(0xface)));
|
EXPECT_EQ("**0xface", format("{0:*>8}", reinterpret_cast<void*>(0xface)));
|
||||||
EXPECT_EQ("foo=", format("{:}=", "foo"));
|
EXPECT_EQ("foo=", format("{:}=", "foo"));
|
||||||
|
EXPECT_EQ(std::string("\0\0\0*", 4), format(string_view("{:\0>4}", 6), '*'));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(FormatterTest, PlusSign) {
|
TEST(FormatterTest, PlusSign) {
|
||||||
|
@ -1013,7 +1052,7 @@ TEST(FormatterTest, HashFlag) {
|
||||||
EXPECT_EQ("0x42", format("{0:#x}", 0x42ull));
|
EXPECT_EQ("0x42", format("{0:#x}", 0x42ull));
|
||||||
EXPECT_EQ("042", format("{0:#o}", 042ull));
|
EXPECT_EQ("042", format("{0:#o}", 042ull));
|
||||||
|
|
||||||
if (fmt::internal::use_grisu())
|
if (FMT_USE_GRISU)
|
||||||
EXPECT_EQ("-42.0", format("{0:#}", -42.0));
|
EXPECT_EQ("-42.0", format("{0:#}", -42.0));
|
||||||
else
|
else
|
||||||
EXPECT_EQ("-42.0000", format("{0:#}", -42.0));
|
EXPECT_EQ("-42.0000", format("{0:#}", -42.0));
|
||||||
|
@ -1395,6 +1434,8 @@ TEST(FormatterTest, FormatIntLocale) {
|
||||||
EXPECT_EQ("123", format("{:n}", 123));
|
EXPECT_EQ("123", format("{:n}", 123));
|
||||||
EXPECT_EQ("1,234", format("{:n}", 1234));
|
EXPECT_EQ("1,234", format("{:n}", 1234));
|
||||||
EXPECT_EQ("1,234,567", format("{:n}", 1234567));
|
EXPECT_EQ("1,234,567", format("{:n}", 1234567));
|
||||||
|
EXPECT_EQ("4,294,967,295",
|
||||||
|
format("{:n}", std::numeric_limits<uint32_t>::max()));
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ConvertibleToLongLong {
|
struct ConvertibleToLongLong {
|
||||||
|
@ -1411,13 +1452,14 @@ TEST(FormatterTest, FormatFloat) {
|
||||||
|
|
||||||
TEST(FormatterTest, FormatDouble) {
|
TEST(FormatterTest, FormatDouble) {
|
||||||
check_unknown_types(1.2, "eEfFgGaA", "double");
|
check_unknown_types(1.2, "eEfFgGaA", "double");
|
||||||
EXPECT_EQ("0", format("{0:}", 0.0));
|
EXPECT_EQ("0", format("{:}", 0.0));
|
||||||
EXPECT_EQ("0.000000", format("{0:f}", 0.0));
|
EXPECT_EQ("0.000000", format("{:f}", 0.0));
|
||||||
EXPECT_EQ("392.65", format("{0:}", 392.65));
|
EXPECT_EQ("0", format("{:g}", 0.0));
|
||||||
EXPECT_EQ("392.65", format("{0:g}", 392.65));
|
EXPECT_EQ("392.65", format("{:}", 392.65));
|
||||||
EXPECT_EQ("392.65", format("{0:G}", 392.65));
|
EXPECT_EQ("392.65", format("{:g}", 392.65));
|
||||||
EXPECT_EQ("392.650000", format("{0:f}", 392.65));
|
EXPECT_EQ("392.65", format("{:G}", 392.65));
|
||||||
EXPECT_EQ("392.650000", format("{0:F}", 392.65));
|
EXPECT_EQ("392.650000", format("{:f}", 392.65));
|
||||||
|
EXPECT_EQ("392.650000", format("{:F}", 392.65));
|
||||||
char buffer[BUFFER_SIZE];
|
char buffer[BUFFER_SIZE];
|
||||||
safe_sprintf(buffer, "%e", 392.65);
|
safe_sprintf(buffer, "%e", 392.65);
|
||||||
EXPECT_EQ(buffer, format("{0:e}", 392.65));
|
EXPECT_EQ(buffer, format("{0:e}", 392.65));
|
||||||
|
@ -1430,6 +1472,12 @@ TEST(FormatterTest, FormatDouble) {
|
||||||
EXPECT_EQ(buffer, format("{:A}", -42.0));
|
EXPECT_EQ(buffer, format("{:A}", -42.0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(FormatterTest, FormatDoubleBigPrecision) {
|
||||||
|
// sprintf with big precision is broken in MSVC2013, so only test on Grisu.
|
||||||
|
if (FMT_USE_GRISU)
|
||||||
|
EXPECT_EQ(format("0.{:0<1000}", ""), format("{:.1000f}", 0.0));
|
||||||
|
}
|
||||||
|
|
||||||
TEST(FormatterTest, FormatNaN) {
|
TEST(FormatterTest, FormatNaN) {
|
||||||
double nan = std::numeric_limits<double>::quiet_NaN();
|
double nan = std::numeric_limits<double>::quiet_NaN();
|
||||||
EXPECT_EQ("nan", format("{}", nan));
|
EXPECT_EQ("nan", format("{}", nan));
|
||||||
|
@ -1498,7 +1546,7 @@ TEST(FormatterTest, FormatCString) {
|
||||||
EXPECT_EQ("test", format("{0:s}", "test"));
|
EXPECT_EQ("test", format("{0:s}", "test"));
|
||||||
char nonconst[] = "nonconst";
|
char nonconst[] = "nonconst";
|
||||||
EXPECT_EQ("nonconst", format("{0}", nonconst));
|
EXPECT_EQ("nonconst", format("{0}", nonconst));
|
||||||
EXPECT_THROW_MSG(format("{0}", static_cast<const char*>(nullptr)),
|
EXPECT_THROW_MSG(format("{0}", static_cast<const char*>(FMT_NULL)),
|
||||||
format_error, "string pointer is null");
|
format_error, "string pointer is null");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1520,7 +1568,7 @@ TEST(FormatterTest, FormatUCharString) {
|
||||||
|
|
||||||
TEST(FormatterTest, FormatPointer) {
|
TEST(FormatterTest, FormatPointer) {
|
||||||
check_unknown_types(reinterpret_cast<void*>(0x1234), "p", "pointer");
|
check_unknown_types(reinterpret_cast<void*>(0x1234), "p", "pointer");
|
||||||
EXPECT_EQ("0x0", format("{0}", static_cast<void*>(nullptr)));
|
EXPECT_EQ("0x0", format("{0}", static_cast<void*>(FMT_NULL)));
|
||||||
EXPECT_EQ("0x1234", format("{0}", reinterpret_cast<void*>(0x1234)));
|
EXPECT_EQ("0x1234", format("{0}", reinterpret_cast<void*>(0x1234)));
|
||||||
EXPECT_EQ("0x1234", format("{0:p}", reinterpret_cast<void*>(0x1234)));
|
EXPECT_EQ("0x1234", format("{0:p}", reinterpret_cast<void*>(0x1234)));
|
||||||
EXPECT_EQ("0x" + std::string(sizeof(void*) * CHAR_BIT / 4, 'f'),
|
EXPECT_EQ("0x" + std::string(sizeof(void*) * CHAR_BIT / 4, 'f'),
|
||||||
|
@ -1546,45 +1594,6 @@ TEST(FormatterTest, FormatStdStringView) {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct implicitly_convertible_to_string_view {
|
|
||||||
operator fmt::string_view() const { return "foo"; }
|
|
||||||
};
|
|
||||||
|
|
||||||
TEST(FormatterTest, FormatImplicitlyConvertibleToStringView) {
|
|
||||||
EXPECT_EQ("foo", format("{}", implicitly_convertible_to_string_view()));
|
|
||||||
}
|
|
||||||
|
|
||||||
// std::is_constructible is broken in MSVC until version 2015.
|
|
||||||
#if !FMT_MSC_VER || FMT_MSC_VER >= 1900
|
|
||||||
struct explicitly_convertible_to_string_view {
|
|
||||||
explicit operator fmt::string_view() const { return "foo"; }
|
|
||||||
};
|
|
||||||
|
|
||||||
TEST(FormatterTest, FormatExplicitlyConvertibleToStringView) {
|
|
||||||
EXPECT_EQ("foo", format("{}", explicitly_convertible_to_string_view()));
|
|
||||||
}
|
|
||||||
|
|
||||||
struct explicitly_convertible_to_wstring_view {
|
|
||||||
explicit operator fmt::wstring_view() const { return L"foo"; }
|
|
||||||
};
|
|
||||||
|
|
||||||
TEST(FormatterTest, FormatExplicitlyConvertibleToWStringView) {
|
|
||||||
EXPECT_EQ(L"foo", format(L"{}", explicitly_convertible_to_wstring_view()));
|
|
||||||
}
|
|
||||||
|
|
||||||
struct explicitly_convertible_to_string_like {
|
|
||||||
template <
|
|
||||||
typename String,
|
|
||||||
typename = typename std::enable_if<
|
|
||||||
std::is_constructible<String, const char*, std::size_t>::value>::type>
|
|
||||||
explicit operator String() const { return String("foo", 3u); }
|
|
||||||
};
|
|
||||||
|
|
||||||
TEST(FormatterTest, FormatExplicitlyConvertibleToStringLike) {
|
|
||||||
EXPECT_EQ("foo", format("{}", explicitly_convertible_to_string_like()));
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
FMT_BEGIN_NAMESPACE
|
FMT_BEGIN_NAMESPACE
|
||||||
template <>
|
template <>
|
||||||
struct formatter<Date> {
|
struct formatter<Date> {
|
||||||
|
@ -1628,7 +1637,8 @@ TEST(FormatterTest, CustomFormat) {
|
||||||
|
|
||||||
TEST(FormatterTest, CustomFormatTo) {
|
TEST(FormatterTest, CustomFormatTo) {
|
||||||
char buf[10] = {};
|
char buf[10] = {};
|
||||||
auto end = fmt::format_to(buf, "{}", Answer());
|
auto end = &*fmt::format_to(
|
||||||
|
fmt::internal::make_checked(buf, 10), "{}", Answer());
|
||||||
EXPECT_EQ(end, buf + 2);
|
EXPECT_EQ(end, buf + 2);
|
||||||
EXPECT_STREQ(buf, "42");
|
EXPECT_STREQ(buf, "42");
|
||||||
}
|
}
|
||||||
|
@ -1661,7 +1671,7 @@ TEST(FormatterTest, FormatExamples) {
|
||||||
FILE *ftest = safe_fopen(filename, "r");
|
FILE *ftest = safe_fopen(filename, "r");
|
||||||
if (ftest) fclose(ftest);
|
if (ftest) fclose(ftest);
|
||||||
int error_code = errno;
|
int error_code = errno;
|
||||||
EXPECT_TRUE(ftest == nullptr);
|
EXPECT_TRUE(ftest == FMT_NULL);
|
||||||
EXPECT_SYSTEM_ERROR({
|
EXPECT_SYSTEM_ERROR({
|
||||||
FILE *f = safe_fopen(filename, "r");
|
FILE *f = safe_fopen(filename, "r");
|
||||||
if (!f)
|
if (!f)
|
||||||
|
@ -1778,7 +1788,7 @@ TEST(FormatTest, Variadic) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(FormatTest, Dynamic) {
|
TEST(FormatTest, Dynamic) {
|
||||||
using ctx = fmt::format_context;
|
typedef fmt::format_context ctx;
|
||||||
std::vector<fmt::basic_format_arg<ctx>> args;
|
std::vector<fmt::basic_format_arg<ctx>> args;
|
||||||
args.emplace_back(fmt::internal::make_arg<ctx>(42));
|
args.emplace_back(fmt::internal::make_arg<ctx>(42));
|
||||||
args.emplace_back(fmt::internal::make_arg<ctx>("abc1"));
|
args.emplace_back(fmt::internal::make_arg<ctx>("abc1"));
|
||||||
|
@ -1830,7 +1840,7 @@ TEST(StrTest, Convert) {
|
||||||
EXPECT_EQ("2012-12-9", s);
|
EXPECT_EQ("2012-12-9", s);
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string vformat_message(int id, const char *format, fmt::format_args args) {
|
std::string vformat_message(int id, const char *format, fmt::format_args args) {
|
||||||
fmt::memory_buffer buffer;
|
fmt::memory_buffer buffer;
|
||||||
format_to(buffer, "[{}] ", id);
|
format_to(buffer, "[{}] ", id);
|
||||||
vformat_to(buffer, format, args);
|
vformat_to(buffer, format, args);
|
||||||
|
@ -1895,6 +1905,7 @@ TEST(FormatTest, UdlTemplate) {
|
||||||
EXPECT_EQ("foo", "foo"_format());
|
EXPECT_EQ("foo", "foo"_format());
|
||||||
EXPECT_EQ(" 42", "{0:10}"_format(42));
|
EXPECT_EQ(" 42", "{0:10}"_format(42));
|
||||||
EXPECT_EQ("42", fmt::format(FMT_STRING("{}"), 42));
|
EXPECT_EQ("42", fmt::format(FMT_STRING("{}"), 42));
|
||||||
|
EXPECT_EQ(L"42", fmt::format(FMT_STRING(L"{}"), 42));
|
||||||
}
|
}
|
||||||
#endif // FMT_USE_USER_DEFINED_LITERALS
|
#endif // FMT_USE_USER_DEFINED_LITERALS
|
||||||
|
|
||||||
|
@ -1906,6 +1917,7 @@ TEST(FormatTest, Enum) {
|
||||||
|
|
||||||
TEST(FormatTest, EnumFormatterUnambiguous) {
|
TEST(FormatTest, EnumFormatterUnambiguous) {
|
||||||
fmt::formatter<TestEnum> f;
|
fmt::formatter<TestEnum> f;
|
||||||
|
ASSERT_GE(sizeof(f), 0); // use f to avoid compiler warning
|
||||||
}
|
}
|
||||||
|
|
||||||
#if FMT_HAS_FEATURE(cxx_strong_enums)
|
#if FMT_HAS_FEATURE(cxx_strong_enums)
|
||||||
|
@ -1930,7 +1942,7 @@ class mock_arg_formatter:
|
||||||
typedef buffer_range range;
|
typedef buffer_range range;
|
||||||
|
|
||||||
mock_arg_formatter(fmt::format_context &ctx, fmt::format_specs *s = FMT_NULL)
|
mock_arg_formatter(fmt::format_context &ctx, fmt::format_specs *s = FMT_NULL)
|
||||||
: base(fmt::internal::get_container(ctx.out()), s) {
|
: base(fmt::internal::get_container(ctx.out()), s, ctx.locale()) {
|
||||||
EXPECT_CALL(*this, call(42));
|
EXPECT_CALL(*this, call(42));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2080,9 +2092,10 @@ struct test_arg_id_handler {
|
||||||
FMT_CONSTEXPR void on_error(const char *) { res = ERROR; }
|
FMT_CONSTEXPR void on_error(const char *) { res = ERROR; }
|
||||||
};
|
};
|
||||||
|
|
||||||
FMT_CONSTEXPR test_arg_id_handler parse_arg_id(const char* s) {
|
template <size_t N>
|
||||||
|
FMT_CONSTEXPR test_arg_id_handler parse_arg_id(const char (&s)[N]) {
|
||||||
test_arg_id_handler h;
|
test_arg_id_handler h;
|
||||||
fmt::internal::parse_arg_id(s, h);
|
fmt::internal::parse_arg_id(s, s + N, h);
|
||||||
return h;
|
return h;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2142,9 +2155,10 @@ struct test_format_specs_handler {
|
||||||
FMT_CONSTEXPR void on_error(const char *) { res = ERROR; }
|
FMT_CONSTEXPR void on_error(const char *) { res = ERROR; }
|
||||||
};
|
};
|
||||||
|
|
||||||
FMT_CONSTEXPR test_format_specs_handler parse_test_specs(const char *s) {
|
template <size_t N>
|
||||||
|
FMT_CONSTEXPR test_format_specs_handler parse_test_specs(const char (&s)[N]) {
|
||||||
test_format_specs_handler h;
|
test_format_specs_handler h;
|
||||||
fmt::internal::parse_format_specs(s, h);
|
fmt::internal::parse_format_specs(s, s + N, h);
|
||||||
return h;
|
return h;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2188,61 +2202,64 @@ struct test_context {
|
||||||
FMT_CONSTEXPR test_context error_handler() { return *this; }
|
FMT_CONSTEXPR test_context error_handler() { return *this; }
|
||||||
};
|
};
|
||||||
|
|
||||||
FMT_CONSTEXPR fmt::format_specs parse_specs(const char *s) {
|
template <size_t N>
|
||||||
|
FMT_CONSTEXPR fmt::format_specs parse_specs(const char (&s)[N]) {
|
||||||
fmt::format_specs specs;
|
fmt::format_specs specs;
|
||||||
test_context ctx{};
|
test_context ctx{};
|
||||||
fmt::internal::specs_handler<test_context> h(specs, ctx);
|
fmt::internal::specs_handler<test_context> h(specs, ctx);
|
||||||
parse_format_specs(s, h);
|
parse_format_specs(s, s + N, h);
|
||||||
return specs;
|
return specs;
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(FormatTest, ConstexprSpecsHandler) {
|
TEST(FormatTest, ConstexprSpecsHandler) {
|
||||||
static_assert(parse_specs("<").align() == fmt::ALIGN_LEFT, "");
|
static_assert(parse_specs("<").align() == fmt::ALIGN_LEFT, "");
|
||||||
static_assert(parse_specs("*^").fill() == '*', "");
|
static_assert(parse_specs("*^").fill() == '*', "");
|
||||||
static_assert(parse_specs("+").flag(fmt::PLUS_FLAG), "");
|
static_assert(parse_specs("+").has(fmt::PLUS_FLAG), "");
|
||||||
static_assert(parse_specs("-").flag(fmt::MINUS_FLAG), "");
|
static_assert(parse_specs("-").has(fmt::MINUS_FLAG), "");
|
||||||
static_assert(parse_specs(" ").flag(fmt::SIGN_FLAG), "");
|
static_assert(parse_specs(" ").has(fmt::SIGN_FLAG), "");
|
||||||
static_assert(parse_specs("#").flag(fmt::HASH_FLAG), "");
|
static_assert(parse_specs("#").has(fmt::HASH_FLAG), "");
|
||||||
static_assert(parse_specs("0").align() == fmt::ALIGN_NUMERIC, "");
|
static_assert(parse_specs("0").align() == fmt::ALIGN_NUMERIC, "");
|
||||||
static_assert(parse_specs("42").width() == 42, "");
|
static_assert(parse_specs("42").width() == 42, "");
|
||||||
static_assert(parse_specs("{}").width() == 11, "");
|
static_assert(parse_specs("{}").width() == 11, "");
|
||||||
static_assert(parse_specs("{0}").width() == 22, "");
|
static_assert(parse_specs("{0}").width() == 22, "");
|
||||||
static_assert(parse_specs(".42").precision() == 42, "");
|
static_assert(parse_specs(".42").precision == 42, "");
|
||||||
static_assert(parse_specs(".{}").precision() == 11, "");
|
static_assert(parse_specs(".{}").precision == 11, "");
|
||||||
static_assert(parse_specs(".{0}").precision() == 22, "");
|
static_assert(parse_specs(".{0}").precision == 22, "");
|
||||||
static_assert(parse_specs("d").type() == 'd', "");
|
static_assert(parse_specs("d").type == 'd', "");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <size_t N>
|
||||||
FMT_CONSTEXPR fmt::internal::dynamic_format_specs<char>
|
FMT_CONSTEXPR fmt::internal::dynamic_format_specs<char>
|
||||||
parse_dynamic_specs(const char *s) {
|
parse_dynamic_specs(const char (&s)[N]) {
|
||||||
fmt::internal::dynamic_format_specs<char> specs;
|
fmt::internal::dynamic_format_specs<char> specs;
|
||||||
test_context ctx{};
|
test_context ctx{};
|
||||||
fmt::internal::dynamic_specs_handler<test_context> h(specs, ctx);
|
fmt::internal::dynamic_specs_handler<test_context> h(specs, ctx);
|
||||||
parse_format_specs(s, h);
|
parse_format_specs(s, s + N, h);
|
||||||
return specs;
|
return specs;
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(FormatTest, ConstexprDynamicSpecsHandler) {
|
TEST(FormatTest, ConstexprDynamicSpecsHandler) {
|
||||||
static_assert(parse_dynamic_specs("<").align() == fmt::ALIGN_LEFT, "");
|
static_assert(parse_dynamic_specs("<").align() == fmt::ALIGN_LEFT, "");
|
||||||
static_assert(parse_dynamic_specs("*^").fill() == '*', "");
|
static_assert(parse_dynamic_specs("*^").fill() == '*', "");
|
||||||
static_assert(parse_dynamic_specs("+").flag(fmt::PLUS_FLAG), "");
|
static_assert(parse_dynamic_specs("+").has(fmt::PLUS_FLAG), "");
|
||||||
static_assert(parse_dynamic_specs("-").flag(fmt::MINUS_FLAG), "");
|
static_assert(parse_dynamic_specs("-").has(fmt::MINUS_FLAG), "");
|
||||||
static_assert(parse_dynamic_specs(" ").flag(fmt::SIGN_FLAG), "");
|
static_assert(parse_dynamic_specs(" ").has(fmt::SIGN_FLAG), "");
|
||||||
static_assert(parse_dynamic_specs("#").flag(fmt::HASH_FLAG), "");
|
static_assert(parse_dynamic_specs("#").has(fmt::HASH_FLAG), "");
|
||||||
static_assert(parse_dynamic_specs("0").align() == fmt::ALIGN_NUMERIC, "");
|
static_assert(parse_dynamic_specs("0").align() == fmt::ALIGN_NUMERIC, "");
|
||||||
static_assert(parse_dynamic_specs("42").width() == 42, "");
|
static_assert(parse_dynamic_specs("42").width() == 42, "");
|
||||||
static_assert(parse_dynamic_specs("{}").width_ref.index == 33, "");
|
static_assert(parse_dynamic_specs("{}").width_ref.index == 33, "");
|
||||||
static_assert(parse_dynamic_specs("{42}").width_ref.index == 42, "");
|
static_assert(parse_dynamic_specs("{42}").width_ref.index == 42, "");
|
||||||
static_assert(parse_dynamic_specs(".42").precision() == 42, "");
|
static_assert(parse_dynamic_specs(".42").precision == 42, "");
|
||||||
static_assert(parse_dynamic_specs(".{}").precision_ref.index == 33, "");
|
static_assert(parse_dynamic_specs(".{}").precision_ref.index == 33, "");
|
||||||
static_assert(parse_dynamic_specs(".{42}").precision_ref.index == 42, "");
|
static_assert(parse_dynamic_specs(".{42}").precision_ref.index == 42, "");
|
||||||
static_assert(parse_dynamic_specs("d").type() == 'd', "");
|
static_assert(parse_dynamic_specs("d").type == 'd', "");
|
||||||
}
|
}
|
||||||
|
|
||||||
FMT_CONSTEXPR test_format_specs_handler check_specs(const char *s) {
|
template <size_t N>
|
||||||
|
FMT_CONSTEXPR test_format_specs_handler check_specs(const char (&s)[N]) {
|
||||||
fmt::internal::specs_checker<test_format_specs_handler>
|
fmt::internal::specs_checker<test_format_specs_handler>
|
||||||
checker(test_format_specs_handler(), fmt::internal::double_type);
|
checker(test_format_specs_handler(), fmt::internal::double_type);
|
||||||
parse_format_specs(s, checker);
|
parse_format_specs(s, s + N, checker);
|
||||||
return checker;
|
return checker;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2271,20 +2288,21 @@ struct test_format_string_handler {
|
||||||
template <typename T>
|
template <typename T>
|
||||||
FMT_CONSTEXPR void on_arg_id(T) {}
|
FMT_CONSTEXPR void on_arg_id(T) {}
|
||||||
|
|
||||||
template <typename Iterator>
|
FMT_CONSTEXPR void on_replacement_field(const char *) {}
|
||||||
FMT_CONSTEXPR void on_replacement_field(Iterator) {}
|
|
||||||
|
|
||||||
template <typename Iterator>
|
FMT_CONSTEXPR const char *on_format_specs(const char *begin, const char*) {
|
||||||
FMT_CONSTEXPR Iterator on_format_specs(Iterator it) { return it; }
|
return begin;
|
||||||
|
}
|
||||||
|
|
||||||
FMT_CONSTEXPR void on_error(const char *) { error = true; }
|
FMT_CONSTEXPR void on_error(const char *) { error = true; }
|
||||||
|
|
||||||
bool error = false;
|
bool error = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
FMT_CONSTEXPR bool parse_string(fmt::string_view s) {
|
template <size_t N>
|
||||||
|
FMT_CONSTEXPR bool parse_string(const char (&s)[N]) {
|
||||||
test_format_string_handler h;
|
test_format_string_handler h;
|
||||||
fmt::internal::parse_format_string<true>(s, h);
|
fmt::internal::parse_format_string<true>(fmt::string_view(s, N - 1), h);
|
||||||
return !h.error;
|
return !h.error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2330,8 +2348,8 @@ FMT_CONSTEXPR bool equal(const char *s1, const char *s2) {
|
||||||
|
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
FMT_CONSTEXPR bool test_error(const char *fmt, const char *expected_error) {
|
FMT_CONSTEXPR bool test_error(const char *fmt, const char *expected_error) {
|
||||||
const char *actual_error = nullptr;
|
const char *actual_error = FMT_NULL;
|
||||||
fmt::internal::check_format_string<char, test_error_handler, Args...>(
|
fmt::internal::do_check_format_string<char, test_error_handler, Args...>(
|
||||||
string_view(fmt, len(fmt)), test_error_handler(actual_error));
|
string_view(fmt, len(fmt)), test_error_handler(actual_error));
|
||||||
return equal(actual_error, expected_error);
|
return equal(actual_error, expected_error);
|
||||||
}
|
}
|
||||||
|
@ -2342,7 +2360,7 @@ FMT_CONSTEXPR bool test_error(const char *fmt, const char *expected_error) {
|
||||||
static_assert(test_error<__VA_ARGS__>(fmt, error), "")
|
static_assert(test_error<__VA_ARGS__>(fmt, error), "")
|
||||||
|
|
||||||
TEST(FormatTest, FormatStringErrors) {
|
TEST(FormatTest, FormatStringErrors) {
|
||||||
EXPECT_ERROR_NOARGS("foo", nullptr);
|
EXPECT_ERROR_NOARGS("foo", FMT_NULL);
|
||||||
EXPECT_ERROR_NOARGS("}", "unmatched '}' in format string");
|
EXPECT_ERROR_NOARGS("}", "unmatched '}' in format string");
|
||||||
EXPECT_ERROR("{0:s", "unknown format specifier", Date);
|
EXPECT_ERROR("{0:s", "unknown format specifier", Date);
|
||||||
#ifndef _MSC_VER
|
#ifndef _MSC_VER
|
||||||
|
@ -2395,23 +2413,46 @@ TEST(FormatTest, FormatStringErrors) {
|
||||||
"cannot switch from automatic to manual argument indexing",
|
"cannot switch from automatic to manual argument indexing",
|
||||||
int, int);
|
int, int);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(FormatTest, VFormatTo) {
|
||||||
|
typedef fmt::format_context context;
|
||||||
|
fmt::basic_format_arg<context> arg = fmt::internal::make_arg<context>(42);
|
||||||
|
fmt::basic_format_args<context> args(&arg, 1);
|
||||||
|
std::string s;
|
||||||
|
fmt::vformat_to(std::back_inserter(s), "{}", args);
|
||||||
|
EXPECT_EQ("42", s);
|
||||||
|
s.clear();
|
||||||
|
fmt::vformat_to(std::back_inserter(s), FMT_STRING("{}"), args);
|
||||||
|
EXPECT_EQ("42", s);
|
||||||
|
|
||||||
|
typedef fmt::wformat_context wcontext;
|
||||||
|
fmt::basic_format_arg<wcontext> warg = fmt::internal::make_arg<wcontext>(42);
|
||||||
|
fmt::basic_format_args<wcontext> wargs(&warg, 1);
|
||||||
|
std::wstring w;
|
||||||
|
fmt::vformat_to(std::back_inserter(w), L"{}", wargs);
|
||||||
|
EXPECT_EQ(L"42", w);
|
||||||
|
w.clear();
|
||||||
|
fmt::vformat_to(std::back_inserter(w), FMT_STRING(L"{}"), wargs);
|
||||||
|
EXPECT_EQ(L"42", w);
|
||||||
|
}
|
||||||
|
|
||||||
#endif // FMT_USE_CONSTEXPR
|
#endif // FMT_USE_CONSTEXPR
|
||||||
|
|
||||||
TEST(FormatTest, ConstructU8StringViewFromCString) {
|
TEST(FormatTest, ConstructU8StringViewFromCString) {
|
||||||
fmt::u8string_view s("ab");
|
fmt::u8string_view s("ab");
|
||||||
EXPECT_EQ(s.size(), 2u);
|
EXPECT_EQ(s.size(), 2u);
|
||||||
const fmt::char8_t *data = s.data();
|
const fmt::char8_t *data = s.data();
|
||||||
EXPECT_EQ(data[0].value, 'a');
|
EXPECT_EQ(data[0], 'a');
|
||||||
EXPECT_EQ(data[1].value, 'b');
|
EXPECT_EQ(data[1], 'b');
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(FormatTest, ConstructU8StringViewFromDataAndSize) {
|
TEST(FormatTest, ConstructU8StringViewFromDataAndSize) {
|
||||||
fmt::u8string_view s("foobar", 3);
|
fmt::u8string_view s("foobar", 3);
|
||||||
EXPECT_EQ(s.size(), 3u);
|
EXPECT_EQ(s.size(), 3u);
|
||||||
const fmt::char8_t *data = s.data();
|
const fmt::char8_t *data = s.data();
|
||||||
EXPECT_EQ(data[0].value, 'f');
|
EXPECT_EQ(data[0], 'f');
|
||||||
EXPECT_EQ(data[1].value, 'o');
|
EXPECT_EQ(data[1], 'o');
|
||||||
EXPECT_EQ(data[2].value, 'o');
|
EXPECT_EQ(data[2], 'o');
|
||||||
}
|
}
|
||||||
|
|
||||||
#if FMT_USE_USER_DEFINED_LITERALS
|
#if FMT_USE_USER_DEFINED_LITERALS
|
||||||
|
@ -2420,7 +2461,12 @@ TEST(FormatTest, U8StringViewLiteral) {
|
||||||
fmt::u8string_view s = "ab"_u;
|
fmt::u8string_view s = "ab"_u;
|
||||||
EXPECT_EQ(s.size(), 2u);
|
EXPECT_EQ(s.size(), 2u);
|
||||||
const fmt::char8_t *data = s.data();
|
const fmt::char8_t *data = s.data();
|
||||||
EXPECT_EQ(data[0].value, 'a');
|
EXPECT_EQ(data[0], 'a');
|
||||||
EXPECT_EQ(data[1].value, 'b');
|
EXPECT_EQ(data[1], 'b');
|
||||||
|
EXPECT_EQ(format("{:*^5}"_u, "🤡"_u), "**🤡**"_u);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
TEST(FormatTest, FormatU8String) {
|
||||||
|
EXPECT_EQ(format(fmt::u8string_view("{}"), 42), fmt::u8string_view("42"));
|
||||||
|
}
|
||||||
|
|
12
externals/fmt/test/gtest-extra-test.cc
vendored
12
externals/fmt/test/gtest-extra-test.cc
vendored
|
@ -311,8 +311,8 @@ using fmt::error_code;
|
||||||
using fmt::file;
|
using fmt::file;
|
||||||
|
|
||||||
TEST(ErrorCodeTest, Ctor) {
|
TEST(ErrorCodeTest, Ctor) {
|
||||||
EXPECT_EQ(0, error_code().get());
|
EXPECT_EQ(error_code().get(), 0);
|
||||||
EXPECT_EQ(42, error_code(42).get());
|
EXPECT_EQ(error_code(42).get(), 42);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(OutputRedirectTest, ScopedRedirect) {
|
TEST(OutputRedirectTest, ScopedRedirect) {
|
||||||
|
@ -340,10 +340,10 @@ TEST(OutputRedirectTest, FlushErrorInCtor) {
|
||||||
// Put a character in a file buffer.
|
// Put a character in a file buffer.
|
||||||
EXPECT_EQ('x', fputc('x', f.get()));
|
EXPECT_EQ('x', fputc('x', f.get()));
|
||||||
FMT_POSIX(close(write_fd));
|
FMT_POSIX(close(write_fd));
|
||||||
scoped_ptr<OutputRedirect> redir{nullptr};
|
scoped_ptr<OutputRedirect> redir{FMT_NULL};
|
||||||
EXPECT_SYSTEM_ERROR_NOASSERT(redir.reset(new OutputRedirect(f.get())),
|
EXPECT_SYSTEM_ERROR_NOASSERT(redir.reset(new OutputRedirect(f.get())),
|
||||||
EBADF, "cannot flush stream");
|
EBADF, "cannot flush stream");
|
||||||
redir.reset(nullptr);
|
redir.reset(FMT_NULL);
|
||||||
write_copy.dup2(write_fd); // "undo" close or dtor will fail
|
write_copy.dup2(write_fd); // "undo" close or dtor will fail
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -352,7 +352,7 @@ TEST(OutputRedirectTest, DupErrorInCtor) {
|
||||||
int fd = (f.fileno)();
|
int fd = (f.fileno)();
|
||||||
file copy = file::dup(fd);
|
file copy = file::dup(fd);
|
||||||
FMT_POSIX(close(fd));
|
FMT_POSIX(close(fd));
|
||||||
scoped_ptr<OutputRedirect> redir{nullptr};
|
scoped_ptr<OutputRedirect> redir{FMT_NULL};
|
||||||
EXPECT_SYSTEM_ERROR_NOASSERT(redir.reset(new OutputRedirect(f.get())),
|
EXPECT_SYSTEM_ERROR_NOASSERT(redir.reset(new OutputRedirect(f.get())),
|
||||||
EBADF, fmt::format("cannot duplicate file descriptor {}", fd));
|
EBADF, fmt::format("cannot duplicate file descriptor {}", fd));
|
||||||
copy.dup2(fd); // "undo" close or dtor will fail
|
copy.dup2(fd); // "undo" close or dtor will fail
|
||||||
|
@ -403,7 +403,7 @@ TEST(OutputRedirectTest, ErrorInDtor) {
|
||||||
// output in EXPECT_STDERR and the second close will break output
|
// output in EXPECT_STDERR and the second close will break output
|
||||||
// redirection.
|
// redirection.
|
||||||
FMT_POSIX(close(write_fd));
|
FMT_POSIX(close(write_fd));
|
||||||
SUPPRESS_ASSERT(redir.reset(nullptr));
|
SUPPRESS_ASSERT(redir.reset(FMT_NULL));
|
||||||
}, format_system_error(EBADF, "cannot flush stream"));
|
}, format_system_error(EBADF, "cannot flush stream"));
|
||||||
write_copy.dup2(write_fd); // "undo" close or dtor of buffered_file will fail
|
write_copy.dup2(write_fd); // "undo" close or dtor of buffered_file will fail
|
||||||
}
|
}
|
||||||
|
|
2
externals/fmt/test/gtest-extra.h
vendored
2
externals/fmt/test/gtest-extra.h
vendored
|
@ -155,7 +155,7 @@ std::string read(fmt::file &f, std::size_t count);
|
||||||
template <typename Mock>
|
template <typename Mock>
|
||||||
struct ScopedMock : testing::StrictMock<Mock> {
|
struct ScopedMock : testing::StrictMock<Mock> {
|
||||||
ScopedMock() { Mock::instance = this; }
|
ScopedMock() { Mock::instance = this; }
|
||||||
~ScopedMock() { Mock::instance = nullptr; }
|
~ScopedMock() { Mock::instance = FMT_NULL; }
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // FMT_GTEST_EXTRA_H_
|
#endif // FMT_GTEST_EXTRA_H_
|
||||||
|
|
34
externals/fmt/test/locale-test.cc
vendored
Normal file
34
externals/fmt/test/locale-test.cc
vendored
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
// Formatting library for C++ - locale tests
|
||||||
|
//
|
||||||
|
// Copyright (c) 2012 - present, Victor Zverovich
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// For the license information refer to format.h.
|
||||||
|
|
||||||
|
#include "fmt/locale.h"
|
||||||
|
#include "gmock.h"
|
||||||
|
|
||||||
|
template <typename Char>
|
||||||
|
struct numpunct : std::numpunct<Char> {
|
||||||
|
protected:
|
||||||
|
Char do_thousands_sep() const FMT_OVERRIDE { return '~'; }
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST(LocaleTest, Format) {
|
||||||
|
std::locale loc(std::locale(), new numpunct<char>());
|
||||||
|
EXPECT_EQ("1,234,567", fmt::format(std::locale(), "{:n}", 1234567));
|
||||||
|
EXPECT_EQ("1~234~567", fmt::format(loc, "{:n}", 1234567));
|
||||||
|
fmt::format_arg_store<fmt::format_context, int> as{1234567};
|
||||||
|
EXPECT_EQ("1~234~567", fmt::vformat(loc, "{:n}", fmt::format_args(as)));
|
||||||
|
std::string s;
|
||||||
|
fmt::format_to(std::back_inserter(s), loc, "{:n}", 1234567);
|
||||||
|
EXPECT_EQ("1~234~567", s);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(LocaleTest, WFormat) {
|
||||||
|
std::locale loc(std::locale(), new numpunct<wchar_t>());
|
||||||
|
EXPECT_EQ(L"1,234,567", fmt::format(std::locale(), L"{:n}", 1234567));
|
||||||
|
EXPECT_EQ(L"1~234~567", fmt::format(loc, L"{:n}", 1234567));
|
||||||
|
fmt::format_arg_store<fmt::wformat_context, int> as{1234567};
|
||||||
|
EXPECT_EQ(L"1~234~567", fmt::vformat(loc, L"{:n}", fmt::wformat_args(as)));
|
||||||
|
}
|
4
externals/fmt/test/mock-allocator.h
vendored
4
externals/fmt/test/mock-allocator.h
vendored
|
@ -28,13 +28,13 @@ class allocator_ref {
|
||||||
|
|
||||||
void move(allocator_ref &other) {
|
void move(allocator_ref &other) {
|
||||||
alloc_ = other.alloc_;
|
alloc_ = other.alloc_;
|
||||||
other.alloc_ = nullptr;
|
other.alloc_ = FMT_NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
typedef typename Allocator::value_type value_type;
|
typedef typename Allocator::value_type value_type;
|
||||||
|
|
||||||
explicit allocator_ref(Allocator *alloc = nullptr) : alloc_(alloc) {}
|
explicit allocator_ref(Allocator *alloc = FMT_NULL) : alloc_(alloc) {}
|
||||||
|
|
||||||
allocator_ref(const allocator_ref &other) : alloc_(other.alloc_) {}
|
allocator_ref(const allocator_ref &other) : alloc_(other.alloc_) {}
|
||||||
allocator_ref(allocator_ref &&other) { move(other); }
|
allocator_ref(allocator_ref &&other) { move(other); }
|
||||||
|
|
9
externals/fmt/test/ostream-test.cc
vendored
9
externals/fmt/test/ostream-test.cc
vendored
|
@ -146,12 +146,11 @@ TEST(OStreamTest, WriteToOStreamMaxSize) {
|
||||||
} os(streambuf);
|
} os(streambuf);
|
||||||
|
|
||||||
testing::InSequence sequence;
|
testing::InSequence sequence;
|
||||||
const char *data = nullptr;
|
const char *data = FMT_NULL;
|
||||||
std::size_t size = max_size;
|
typedef std::make_unsigned<std::streamsize>::type ustreamsize;
|
||||||
|
ustreamsize size = max_size;
|
||||||
do {
|
do {
|
||||||
typedef std::make_unsigned<std::streamsize>::type ustreamsize;
|
auto n = std::min(size, fmt::internal::to_unsigned(max_streamsize));
|
||||||
ustreamsize n = std::min<ustreamsize>(
|
|
||||||
size, fmt::internal::to_unsigned(max_streamsize));
|
|
||||||
EXPECT_CALL(streambuf, xsputn(data, static_cast<std::streamsize>(n)))
|
EXPECT_CALL(streambuf, xsputn(data, static_cast<std::streamsize>(n)))
|
||||||
.WillOnce(testing::Return(max_streamsize));
|
.WillOnce(testing::Return(max_streamsize));
|
||||||
data += n;
|
data += n;
|
||||||
|
|
16
externals/fmt/test/posix-mock-test.cc
vendored
16
externals/fmt/test/posix-mock-test.cc
vendored
|
@ -133,7 +133,7 @@ int test::dup2(int fildes, int fildes2) {
|
||||||
}
|
}
|
||||||
|
|
||||||
FILE *test::fdopen(int fildes, const char *mode) {
|
FILE *test::fdopen(int fildes, const char *mode) {
|
||||||
EMULATE_EINTR(fdopen, nullptr);
|
EMULATE_EINTR(fdopen, FMT_NULL);
|
||||||
return ::FMT_POSIX(fdopen(fildes, mode));
|
return ::FMT_POSIX(fdopen(fildes, mode));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -162,7 +162,7 @@ int test::pipe(int *pfds, unsigned psize, int textmode) {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
FILE *test::fopen(const char *filename, const char *mode) {
|
FILE *test::fopen(const char *filename, const char *mode) {
|
||||||
EMULATE_EINTR(fopen, nullptr);
|
EMULATE_EINTR(fopen, FMT_NULL);
|
||||||
return ::fopen(filename, mode);
|
return ::fopen(filename, mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -216,7 +216,7 @@ TEST(UtilTest, GetPageSize) {
|
||||||
|
|
||||||
TEST(FileTest, OpenRetry) {
|
TEST(FileTest, OpenRetry) {
|
||||||
write_file("test", "there must be something here");
|
write_file("test", "there must be something here");
|
||||||
scoped_ptr<file> f{nullptr};
|
scoped_ptr<file> f{FMT_NULL};
|
||||||
EXPECT_RETRY(f.reset(new file("test", file::RDONLY)),
|
EXPECT_RETRY(f.reset(new file("test", file::RDONLY)),
|
||||||
open, "cannot open file test");
|
open, "cannot open file test");
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
|
@ -232,7 +232,7 @@ TEST(FileTest, CloseNoRetryInDtor) {
|
||||||
int saved_close_count = 0;
|
int saved_close_count = 0;
|
||||||
EXPECT_WRITE(stderr, {
|
EXPECT_WRITE(stderr, {
|
||||||
close_count = 1;
|
close_count = 1;
|
||||||
f.reset(nullptr);
|
f.reset(FMT_NULL);
|
||||||
saved_close_count = close_count;
|
saved_close_count = close_count;
|
||||||
close_count = 0;
|
close_count = 0;
|
||||||
}, format_system_error(EINTR, "cannot close file") + "\n");
|
}, format_system_error(EINTR, "cannot close file") + "\n");
|
||||||
|
@ -385,7 +385,7 @@ TEST(FileTest, FdopenNoRetry) {
|
||||||
|
|
||||||
TEST(BufferedFileTest, OpenRetry) {
|
TEST(BufferedFileTest, OpenRetry) {
|
||||||
write_file("test", "there must be something here");
|
write_file("test", "there must be something here");
|
||||||
scoped_ptr<buffered_file> f{nullptr};
|
scoped_ptr<buffered_file> f{FMT_NULL};
|
||||||
EXPECT_RETRY(f.reset(new buffered_file("test", "r")),
|
EXPECT_RETRY(f.reset(new buffered_file("test", "r")),
|
||||||
fopen, "cannot open file test");
|
fopen, "cannot open file test");
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
|
@ -402,7 +402,7 @@ TEST(BufferedFileTest, CloseNoRetryInDtor) {
|
||||||
int saved_fclose_count = 0;
|
int saved_fclose_count = 0;
|
||||||
EXPECT_WRITE(stderr, {
|
EXPECT_WRITE(stderr, {
|
||||||
fclose_count = 1;
|
fclose_count = 1;
|
||||||
f.reset(nullptr);
|
f.reset(FMT_NULL);
|
||||||
saved_fclose_count = fclose_count;
|
saved_fclose_count = fclose_count;
|
||||||
fclose_count = 0;
|
fclose_count = 0;
|
||||||
}, format_system_error(EINTR, "cannot close file") + "\n");
|
}, format_system_error(EINTR, "cannot close file") + "\n");
|
||||||
|
@ -440,7 +440,7 @@ TEST(ScopedMock, Scope) {
|
||||||
TestMock © = mock;
|
TestMock © = mock;
|
||||||
static_cast<void>(copy);
|
static_cast<void>(copy);
|
||||||
}
|
}
|
||||||
EXPECT_EQ(nullptr, TestMock::instance);
|
EXPECT_EQ(FMT_NULL, TestMock::instance);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef FMT_LOCALE
|
#ifdef FMT_LOCALE
|
||||||
|
@ -515,7 +515,7 @@ TEST(LocaleTest, Locale) {
|
||||||
#endif
|
#endif
|
||||||
ScopedMock<LocaleMock> mock;
|
ScopedMock<LocaleMock> mock;
|
||||||
LocaleType impl = reinterpret_cast<LocaleType>(42);
|
LocaleType impl = reinterpret_cast<LocaleType>(42);
|
||||||
EXPECT_CALL(mock, newlocale(LC_NUMERIC_MASK, StrEq("C"), nullptr))
|
EXPECT_CALL(mock, newlocale(LC_NUMERIC_MASK, StrEq("C"), FMT_NULL))
|
||||||
.WillOnce(Return(impl));
|
.WillOnce(Return(impl));
|
||||||
EXPECT_CALL(mock, freelocale(impl));
|
EXPECT_CALL(mock, freelocale(impl));
|
||||||
fmt::Locale locale;
|
fmt::Locale locale;
|
||||||
|
|
24
externals/fmt/test/posix-test.cc
vendored
24
externals/fmt/test/posix-test.cc
vendored
|
@ -59,26 +59,26 @@ static void write(file &f, fmt::string_view s) {
|
||||||
|
|
||||||
TEST(BufferedFileTest, DefaultCtor) {
|
TEST(BufferedFileTest, DefaultCtor) {
|
||||||
buffered_file f;
|
buffered_file f;
|
||||||
EXPECT_TRUE(f.get() == nullptr);
|
EXPECT_TRUE(f.get() == FMT_NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(BufferedFileTest, MoveCtor) {
|
TEST(BufferedFileTest, MoveCtor) {
|
||||||
buffered_file bf = open_buffered_file();
|
buffered_file bf = open_buffered_file();
|
||||||
FILE *fp = bf.get();
|
FILE *fp = bf.get();
|
||||||
EXPECT_TRUE(fp != nullptr);
|
EXPECT_TRUE(fp != FMT_NULL);
|
||||||
buffered_file bf2(std::move(bf));
|
buffered_file bf2(std::move(bf));
|
||||||
EXPECT_EQ(fp, bf2.get());
|
EXPECT_EQ(fp, bf2.get());
|
||||||
EXPECT_TRUE(bf.get() == nullptr);
|
EXPECT_TRUE(bf.get() == FMT_NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(BufferedFileTest, MoveAssignment) {
|
TEST(BufferedFileTest, MoveAssignment) {
|
||||||
buffered_file bf = open_buffered_file();
|
buffered_file bf = open_buffered_file();
|
||||||
FILE *fp = bf.get();
|
FILE *fp = bf.get();
|
||||||
EXPECT_TRUE(fp != nullptr);
|
EXPECT_TRUE(fp != FMT_NULL);
|
||||||
buffered_file bf2;
|
buffered_file bf2;
|
||||||
bf2 = std::move(bf);
|
bf2 = std::move(bf);
|
||||||
EXPECT_EQ(fp, bf2.get());
|
EXPECT_EQ(fp, bf2.get());
|
||||||
EXPECT_TRUE(bf.get() == nullptr);
|
EXPECT_TRUE(bf.get() == FMT_NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(BufferedFileTest, MoveAssignmentClosesFile) {
|
TEST(BufferedFileTest, MoveAssignmentClosesFile) {
|
||||||
|
@ -90,13 +90,13 @@ TEST(BufferedFileTest, MoveAssignmentClosesFile) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(BufferedFileTest, MoveFromTemporaryInCtor) {
|
TEST(BufferedFileTest, MoveFromTemporaryInCtor) {
|
||||||
FILE *fp = nullptr;
|
FILE *fp = FMT_NULL;
|
||||||
buffered_file f(open_buffered_file(&fp));
|
buffered_file f(open_buffered_file(&fp));
|
||||||
EXPECT_EQ(fp, f.get());
|
EXPECT_EQ(fp, f.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(BufferedFileTest, MoveFromTemporaryInAssignment) {
|
TEST(BufferedFileTest, MoveFromTemporaryInAssignment) {
|
||||||
FILE *fp = nullptr;
|
FILE *fp = FMT_NULL;
|
||||||
buffered_file f;
|
buffered_file f;
|
||||||
f = open_buffered_file(&fp);
|
f = open_buffered_file(&fp);
|
||||||
EXPECT_EQ(fp, f.get());
|
EXPECT_EQ(fp, f.get());
|
||||||
|
@ -126,7 +126,7 @@ TEST(BufferedFileTest, CloseErrorInDtor) {
|
||||||
// output in EXPECT_STDERR and the second close will break output
|
// output in EXPECT_STDERR and the second close will break output
|
||||||
// redirection.
|
// redirection.
|
||||||
FMT_POSIX(close(f->fileno()));
|
FMT_POSIX(close(f->fileno()));
|
||||||
SUPPRESS_ASSERT(f.reset(nullptr));
|
SUPPRESS_ASSERT(f.reset(FMT_NULL));
|
||||||
}, format_system_error(EBADF, "cannot close file") + "\n");
|
}, format_system_error(EBADF, "cannot close file") + "\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -134,7 +134,7 @@ TEST(BufferedFileTest, Close) {
|
||||||
buffered_file f = open_buffered_file();
|
buffered_file f = open_buffered_file();
|
||||||
int fd = f.fileno();
|
int fd = f.fileno();
|
||||||
f.close();
|
f.close();
|
||||||
EXPECT_TRUE(f.get() == nullptr);
|
EXPECT_TRUE(f.get() == FMT_NULL);
|
||||||
EXPECT_TRUE(isclosed(fd));
|
EXPECT_TRUE(isclosed(fd));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -142,7 +142,7 @@ TEST(BufferedFileTest, CloseError) {
|
||||||
buffered_file f = open_buffered_file();
|
buffered_file f = open_buffered_file();
|
||||||
FMT_POSIX(close(f.fileno()));
|
FMT_POSIX(close(f.fileno()));
|
||||||
EXPECT_SYSTEM_ERROR_NOASSERT(f.close(), EBADF, "cannot close file");
|
EXPECT_SYSTEM_ERROR_NOASSERT(f.close(), EBADF, "cannot close file");
|
||||||
EXPECT_TRUE(f.get() == nullptr);
|
EXPECT_TRUE(f.get() == FMT_NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(BufferedFileTest, Fileno) {
|
TEST(BufferedFileTest, Fileno) {
|
||||||
|
@ -253,7 +253,7 @@ TEST(FileTest, CloseErrorInDtor) {
|
||||||
// output in EXPECT_STDERR and the second close will break output
|
// output in EXPECT_STDERR and the second close will break output
|
||||||
// redirection.
|
// redirection.
|
||||||
FMT_POSIX(close(f->descriptor()));
|
FMT_POSIX(close(f->descriptor()));
|
||||||
SUPPRESS_ASSERT(f.reset(nullptr));
|
SUPPRESS_ASSERT(f.reset(FMT_NULL));
|
||||||
}, format_system_error(EBADF, "cannot close file") + "\n");
|
}, format_system_error(EBADF, "cannot close file") + "\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -334,7 +334,7 @@ TEST(FileTest, Dup2NoExcept) {
|
||||||
file copy = open_file();
|
file copy = open_file();
|
||||||
error_code ec;
|
error_code ec;
|
||||||
f.dup2(copy.descriptor(), ec);
|
f.dup2(copy.descriptor(), ec);
|
||||||
EXPECT_EQ(0, ec.get());
|
EXPECT_EQ(ec.get(), 0);
|
||||||
EXPECT_NE(f.descriptor(), copy.descriptor());
|
EXPECT_NE(f.descriptor(), copy.descriptor());
|
||||||
EXPECT_READ(copy, FILE_CONTENT);
|
EXPECT_READ(copy, FILE_CONTENT);
|
||||||
}
|
}
|
||||||
|
|
179
externals/fmt/test/printf-test.cc
vendored
179
externals/fmt/test/printf-test.cc
vendored
|
@ -32,22 +32,33 @@ static std::wstring make_positional(fmt::wstring_view format) {
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// A wrapper around fmt::sprintf to workaround bogus warnings about invalid
|
||||||
|
// format strings in MSVC.
|
||||||
|
template <typename... Args>
|
||||||
|
std::string test_sprintf(fmt::string_view format, const Args &... args) {
|
||||||
|
return fmt::sprintf(format, args...);
|
||||||
|
}
|
||||||
|
template <typename... Args>
|
||||||
|
std::wstring test_sprintf(fmt::wstring_view format, const Args &... args) {
|
||||||
|
return fmt::sprintf(format, args...);
|
||||||
|
}
|
||||||
|
|
||||||
#define EXPECT_PRINTF(expected_output, format, arg) \
|
#define EXPECT_PRINTF(expected_output, format, arg) \
|
||||||
EXPECT_EQ(expected_output, fmt::sprintf(format, arg)) \
|
EXPECT_EQ(expected_output, test_sprintf(format, arg)) \
|
||||||
<< "format: " << format; \
|
<< "format: " << format; \
|
||||||
EXPECT_EQ(expected_output, fmt::sprintf(make_positional(format), arg))
|
EXPECT_EQ(expected_output, fmt::sprintf(make_positional(format), arg))
|
||||||
|
|
||||||
TEST(PrintfTest, NoArgs) {
|
TEST(PrintfTest, NoArgs) {
|
||||||
EXPECT_EQ("test", fmt::sprintf("test"));
|
EXPECT_EQ("test", test_sprintf("test"));
|
||||||
EXPECT_EQ(L"test", fmt::sprintf(L"test"));
|
EXPECT_EQ(L"test", fmt::sprintf(L"test"));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(PrintfTest, Escape) {
|
TEST(PrintfTest, Escape) {
|
||||||
EXPECT_EQ("%", fmt::sprintf("%%"));
|
EXPECT_EQ("%", test_sprintf("%%"));
|
||||||
EXPECT_EQ("before %", fmt::sprintf("before %%"));
|
EXPECT_EQ("before %", test_sprintf("before %%"));
|
||||||
EXPECT_EQ("% after", fmt::sprintf("%% after"));
|
EXPECT_EQ("% after", test_sprintf("%% after"));
|
||||||
EXPECT_EQ("before % after", fmt::sprintf("before %% after"));
|
EXPECT_EQ("before % after", test_sprintf("before %% after"));
|
||||||
EXPECT_EQ("%s", fmt::sprintf("%%s"));
|
EXPECT_EQ("%s", test_sprintf("%%s"));
|
||||||
EXPECT_EQ(L"%", fmt::sprintf(L"%%"));
|
EXPECT_EQ(L"%", fmt::sprintf(L"%%"));
|
||||||
EXPECT_EQ(L"before %", fmt::sprintf(L"before %%"));
|
EXPECT_EQ(L"before %", fmt::sprintf(L"before %%"));
|
||||||
EXPECT_EQ(L"% after", fmt::sprintf(L"%% after"));
|
EXPECT_EQ(L"% after", fmt::sprintf(L"%% after"));
|
||||||
|
@ -56,60 +67,60 @@ TEST(PrintfTest, Escape) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(PrintfTest, PositionalArgs) {
|
TEST(PrintfTest, PositionalArgs) {
|
||||||
EXPECT_EQ("42", fmt::sprintf("%1$d", 42));
|
EXPECT_EQ("42", test_sprintf("%1$d", 42));
|
||||||
EXPECT_EQ("before 42", fmt::sprintf("before %1$d", 42));
|
EXPECT_EQ("before 42", test_sprintf("before %1$d", 42));
|
||||||
EXPECT_EQ("42 after", fmt::sprintf("%1$d after",42));
|
EXPECT_EQ("42 after", test_sprintf("%1$d after",42));
|
||||||
EXPECT_EQ("before 42 after", fmt::sprintf("before %1$d after", 42));
|
EXPECT_EQ("before 42 after", test_sprintf("before %1$d after", 42));
|
||||||
EXPECT_EQ("answer = 42", fmt::sprintf("%1$s = %2$d", "answer", 42));
|
EXPECT_EQ("answer = 42", test_sprintf("%1$s = %2$d", "answer", 42));
|
||||||
EXPECT_EQ("42 is the answer",
|
EXPECT_EQ("42 is the answer",
|
||||||
fmt::sprintf("%2$d is the %1$s", "answer", 42));
|
test_sprintf("%2$d is the %1$s", "answer", 42));
|
||||||
EXPECT_EQ("abracadabra", fmt::sprintf("%1$s%2$s%1$s", "abra", "cad"));
|
EXPECT_EQ("abracadabra", test_sprintf("%1$s%2$s%1$s", "abra", "cad"));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(PrintfTest, AutomaticArgIndexing) {
|
TEST(PrintfTest, AutomaticArgIndexing) {
|
||||||
EXPECT_EQ("abc", fmt::sprintf("%c%c%c", 'a', 'b', 'c'));
|
EXPECT_EQ("abc", test_sprintf("%c%c%c", 'a', 'b', 'c'));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(PrintfTest, NumberIsTooBigInArgIndex) {
|
TEST(PrintfTest, NumberIsTooBigInArgIndex) {
|
||||||
EXPECT_THROW_MSG(fmt::sprintf(format("%{}$", BIG_NUM)),
|
EXPECT_THROW_MSG(test_sprintf(format("%{}$", BIG_NUM)),
|
||||||
format_error, "number is too big");
|
format_error, "number is too big");
|
||||||
EXPECT_THROW_MSG(fmt::sprintf(format("%{}$d", BIG_NUM)),
|
EXPECT_THROW_MSG(test_sprintf(format("%{}$d", BIG_NUM)),
|
||||||
format_error, "number is too big");
|
format_error, "number is too big");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(PrintfTest, SwitchArgIndexing) {
|
TEST(PrintfTest, SwitchArgIndexing) {
|
||||||
EXPECT_THROW_MSG(fmt::sprintf("%1$d%", 1, 2),
|
EXPECT_THROW_MSG(test_sprintf("%1$d%", 1, 2),
|
||||||
format_error, "cannot switch from manual to automatic argument indexing");
|
format_error, "cannot switch from manual to automatic argument indexing");
|
||||||
EXPECT_THROW_MSG(fmt::sprintf(format("%1$d%{}d", BIG_NUM), 1, 2),
|
EXPECT_THROW_MSG(test_sprintf(format("%1$d%{}d", BIG_NUM), 1, 2),
|
||||||
format_error, "number is too big");
|
format_error, "number is too big");
|
||||||
EXPECT_THROW_MSG(fmt::sprintf("%1$d%d", 1, 2),
|
EXPECT_THROW_MSG(test_sprintf("%1$d%d", 1, 2),
|
||||||
format_error, "cannot switch from manual to automatic argument indexing");
|
format_error, "cannot switch from manual to automatic argument indexing");
|
||||||
|
|
||||||
EXPECT_THROW_MSG(fmt::sprintf("%d%1$", 1, 2),
|
EXPECT_THROW_MSG(test_sprintf("%d%1$", 1, 2),
|
||||||
format_error, "cannot switch from automatic to manual argument indexing");
|
format_error, "cannot switch from automatic to manual argument indexing");
|
||||||
EXPECT_THROW_MSG(fmt::sprintf(format("%d%{}$d", BIG_NUM), 1, 2),
|
EXPECT_THROW_MSG(test_sprintf(format("%d%{}$d", BIG_NUM), 1, 2),
|
||||||
format_error, "number is too big");
|
format_error, "number is too big");
|
||||||
EXPECT_THROW_MSG(fmt::sprintf("%d%1$d", 1, 2),
|
EXPECT_THROW_MSG(test_sprintf("%d%1$d", 1, 2),
|
||||||
format_error, "cannot switch from automatic to manual argument indexing");
|
format_error, "cannot switch from automatic to manual argument indexing");
|
||||||
|
|
||||||
// Indexing errors override width errors.
|
// Indexing errors override width errors.
|
||||||
EXPECT_THROW_MSG(fmt::sprintf(format("%d%1${}d", BIG_NUM), 1, 2),
|
EXPECT_THROW_MSG(test_sprintf(format("%d%1${}d", BIG_NUM), 1, 2),
|
||||||
format_error, "number is too big");
|
format_error, "number is too big");
|
||||||
EXPECT_THROW_MSG(fmt::sprintf(format("%1$d%{}d", BIG_NUM), 1, 2),
|
EXPECT_THROW_MSG(test_sprintf(format("%1$d%{}d", BIG_NUM), 1, 2),
|
||||||
format_error, "number is too big");
|
format_error, "number is too big");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(PrintfTest, InvalidArgIndex) {
|
TEST(PrintfTest, InvalidArgIndex) {
|
||||||
EXPECT_THROW_MSG(fmt::sprintf("%0$d", 42), format_error,
|
EXPECT_THROW_MSG(test_sprintf("%0$d", 42), format_error,
|
||||||
"argument index out of range");
|
"argument index out of range");
|
||||||
EXPECT_THROW_MSG(fmt::sprintf("%2$d", 42), format_error,
|
EXPECT_THROW_MSG(test_sprintf("%2$d", 42), format_error,
|
||||||
"argument index out of range");
|
"argument index out of range");
|
||||||
EXPECT_THROW_MSG(fmt::sprintf(format("%{}$d", INT_MAX), 42),
|
EXPECT_THROW_MSG(test_sprintf(format("%{}$d", INT_MAX), 42),
|
||||||
format_error, "argument index out of range");
|
format_error, "argument index out of range");
|
||||||
|
|
||||||
EXPECT_THROW_MSG(fmt::sprintf("%2$", 42),
|
EXPECT_THROW_MSG(test_sprintf("%2$", 42),
|
||||||
format_error, "argument index out of range");
|
format_error, "argument index out of range");
|
||||||
EXPECT_THROW_MSG(fmt::sprintf(format("%{}$d", BIG_NUM), 42),
|
EXPECT_THROW_MSG(test_sprintf(format("%{}$d", BIG_NUM), 42),
|
||||||
format_error, "number is too big");
|
format_error, "number is too big");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -180,13 +191,8 @@ TEST(PrintfTest, HashFlag) {
|
||||||
safe_sprintf(buffer, "%#E", -42.0);
|
safe_sprintf(buffer, "%#E", -42.0);
|
||||||
EXPECT_PRINTF(buffer, "%#E", -42.0);
|
EXPECT_PRINTF(buffer, "%#E", -42.0);
|
||||||
|
|
||||||
if (fmt::internal::use_grisu()) {
|
EXPECT_PRINTF("-42.0000", "%#g", -42.0);
|
||||||
EXPECT_PRINTF("-42.0", "%#g", -42.0);
|
EXPECT_PRINTF("-42.0000", "%#G", -42.0);
|
||||||
EXPECT_PRINTF("-42.0", "%#G", -42.0);
|
|
||||||
} else {
|
|
||||||
EXPECT_PRINTF("-42.0000", "%#g", -42.0);
|
|
||||||
EXPECT_PRINTF("-42.0000", "%#G", -42.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
safe_sprintf(buffer, "%#a", 16.0);
|
safe_sprintf(buffer, "%#a", 16.0);
|
||||||
EXPECT_PRINTF(buffer, "%#a", 16.0);
|
EXPECT_PRINTF(buffer, "%#a", 16.0);
|
||||||
|
@ -201,23 +207,23 @@ TEST(PrintfTest, Width) {
|
||||||
EXPECT_PRINTF(" abc", "%5s", "abc");
|
EXPECT_PRINTF(" abc", "%5s", "abc");
|
||||||
|
|
||||||
// Width cannot be specified twice.
|
// Width cannot be specified twice.
|
||||||
EXPECT_THROW_MSG(fmt::sprintf("%5-5d", 42), format_error,
|
EXPECT_THROW_MSG(test_sprintf("%5-5d", 42), format_error,
|
||||||
"invalid type specifier");
|
"invalid type specifier");
|
||||||
|
|
||||||
EXPECT_THROW_MSG(fmt::sprintf(format("%{}d", BIG_NUM), 42),
|
EXPECT_THROW_MSG(test_sprintf(format("%{}d", BIG_NUM), 42),
|
||||||
format_error, "number is too big");
|
format_error, "number is too big");
|
||||||
EXPECT_THROW_MSG(fmt::sprintf(format("%1${}d", BIG_NUM), 42),
|
EXPECT_THROW_MSG(test_sprintf(format("%1${}d", BIG_NUM), 42),
|
||||||
format_error, "number is too big");
|
format_error, "number is too big");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(PrintfTest, DynamicWidth) {
|
TEST(PrintfTest, DynamicWidth) {
|
||||||
EXPECT_EQ(" 42", fmt::sprintf("%*d", 5, 42));
|
EXPECT_EQ(" 42", test_sprintf("%*d", 5, 42));
|
||||||
EXPECT_EQ("42 ", fmt::sprintf("%*d", -5, 42));
|
EXPECT_EQ("42 ", test_sprintf("%*d", -5, 42));
|
||||||
EXPECT_THROW_MSG(fmt::sprintf("%*d", 5.0, 42), format_error,
|
EXPECT_THROW_MSG(test_sprintf("%*d", 5.0, 42), format_error,
|
||||||
"width is not integer");
|
"width is not integer");
|
||||||
EXPECT_THROW_MSG(fmt::sprintf("%*d"), format_error,
|
EXPECT_THROW_MSG(test_sprintf("%*d"), format_error,
|
||||||
"argument index out of range");
|
"argument index out of range");
|
||||||
EXPECT_THROW_MSG(fmt::sprintf("%*d", BIG_NUM, 42), format_error,
|
EXPECT_THROW_MSG(test_sprintf("%*d", BIG_NUM, 42), format_error,
|
||||||
"number is too big");
|
"number is too big");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -258,17 +264,17 @@ TEST(PrintfTest, IgnorePrecisionForNonNumericArg) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(PrintfTest, DynamicPrecision) {
|
TEST(PrintfTest, DynamicPrecision) {
|
||||||
EXPECT_EQ("00042", fmt::sprintf("%.*d", 5, 42));
|
EXPECT_EQ("00042", test_sprintf("%.*d", 5, 42));
|
||||||
EXPECT_EQ("42", fmt::sprintf("%.*d", -5, 42));
|
EXPECT_EQ("42", test_sprintf("%.*d", -5, 42));
|
||||||
EXPECT_THROW_MSG(fmt::sprintf("%.*d", 5.0, 42), format_error,
|
EXPECT_THROW_MSG(test_sprintf("%.*d", 5.0, 42), format_error,
|
||||||
"precision is not integer");
|
"precision is not integer");
|
||||||
EXPECT_THROW_MSG(fmt::sprintf("%.*d"), format_error,
|
EXPECT_THROW_MSG(test_sprintf("%.*d"), format_error,
|
||||||
"argument index out of range");
|
"argument index out of range");
|
||||||
EXPECT_THROW_MSG(fmt::sprintf("%.*d", BIG_NUM, 42), format_error,
|
EXPECT_THROW_MSG(test_sprintf("%.*d", BIG_NUM, 42), format_error,
|
||||||
"number is too big");
|
"number is too big");
|
||||||
if (sizeof(long long) != sizeof(int)) {
|
if (sizeof(long long) != sizeof(int)) {
|
||||||
long long prec = static_cast<long long>(INT_MIN) - 1;
|
long long prec = static_cast<long long>(INT_MIN) - 1;
|
||||||
EXPECT_THROW_MSG(fmt::sprintf("%.*d", prec, 42), format_error,
|
EXPECT_THROW_MSG(test_sprintf("%.*d", prec, 42), format_error,
|
||||||
"number is too big");
|
"number is too big");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -431,11 +437,11 @@ TEST(PrintfTest, Char) {
|
||||||
|
|
||||||
TEST(PrintfTest, String) {
|
TEST(PrintfTest, String) {
|
||||||
EXPECT_PRINTF("abc", "%s", "abc");
|
EXPECT_PRINTF("abc", "%s", "abc");
|
||||||
const char *null_str = nullptr;
|
const char *null_str = FMT_NULL;
|
||||||
EXPECT_PRINTF("(null)", "%s", null_str);
|
EXPECT_PRINTF("(null)", "%s", null_str);
|
||||||
EXPECT_PRINTF(" (null)", "%10s", null_str);
|
EXPECT_PRINTF(" (null)", "%10s", null_str);
|
||||||
EXPECT_PRINTF(L"abc", L"%s", L"abc");
|
EXPECT_PRINTF(L"abc", L"%s", L"abc");
|
||||||
const wchar_t *null_wstr = nullptr;
|
const wchar_t *null_wstr = FMT_NULL;
|
||||||
EXPECT_PRINTF(L"(null)", L"%s", null_wstr);
|
EXPECT_PRINTF(L"(null)", L"%s", null_wstr);
|
||||||
EXPECT_PRINTF(L" (null)", L"%10s", null_wstr);
|
EXPECT_PRINTF(L" (null)", L"%10s", null_wstr);
|
||||||
}
|
}
|
||||||
|
@ -444,22 +450,22 @@ TEST(PrintfTest, Pointer) {
|
||||||
int n;
|
int n;
|
||||||
void *p = &n;
|
void *p = &n;
|
||||||
EXPECT_PRINTF(fmt::format("{}", p), "%p", p);
|
EXPECT_PRINTF(fmt::format("{}", p), "%p", p);
|
||||||
p = nullptr;
|
p = FMT_NULL;
|
||||||
EXPECT_PRINTF("(nil)", "%p", p);
|
EXPECT_PRINTF("(nil)", "%p", p);
|
||||||
EXPECT_PRINTF(" (nil)", "%10p", p);
|
EXPECT_PRINTF(" (nil)", "%10p", p);
|
||||||
const char *s = "test";
|
const char *s = "test";
|
||||||
EXPECT_PRINTF(fmt::format("{:p}", s), "%p", s);
|
EXPECT_PRINTF(fmt::format("{:p}", s), "%p", s);
|
||||||
const char *null_str = nullptr;
|
const char *null_str = FMT_NULL;
|
||||||
EXPECT_PRINTF("(nil)", "%p", null_str);
|
EXPECT_PRINTF("(nil)", "%p", null_str);
|
||||||
|
|
||||||
p = &n;
|
p = &n;
|
||||||
EXPECT_PRINTF(fmt::format(L"{}", p), L"%p", p);
|
EXPECT_PRINTF(fmt::format(L"{}", p), L"%p", p);
|
||||||
p = nullptr;
|
p = FMT_NULL;
|
||||||
EXPECT_PRINTF(L"(nil)", L"%p", p);
|
EXPECT_PRINTF(L"(nil)", L"%p", p);
|
||||||
EXPECT_PRINTF(L" (nil)", L"%10p", p);
|
EXPECT_PRINTF(L" (nil)", L"%10p", p);
|
||||||
const wchar_t *w = L"test";
|
const wchar_t *w = L"test";
|
||||||
EXPECT_PRINTF(fmt::format(L"{:p}", w), L"%p", w);
|
EXPECT_PRINTF(fmt::format(L"{:p}", w), L"%p", w);
|
||||||
const wchar_t *null_wstr = nullptr;
|
const wchar_t *null_wstr = FMT_NULL;
|
||||||
EXPECT_PRINTF(L"(nil)", L"%p", null_wstr);
|
EXPECT_PRINTF(L"(nil)", L"%p", null_wstr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -495,7 +501,7 @@ TEST(PrintfTest, WideString) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(PrintfTest, PrintfCustom) {
|
TEST(PrintfTest, PrintfCustom) {
|
||||||
EXPECT_EQ("abc", fmt::sprintf("%s", TestString("abc")));
|
EXPECT_EQ("abc", test_sprintf("%s", TestString("abc")));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(PrintfTest, OStream) {
|
TEST(PrintfTest, OStream) {
|
||||||
|
@ -504,3 +510,60 @@ TEST(PrintfTest, OStream) {
|
||||||
EXPECT_EQ("Don't panic!", os.str());
|
EXPECT_EQ("Don't panic!", os.str());
|
||||||
EXPECT_EQ(12, ret);
|
EXPECT_EQ(12, ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(PrintfTest, VPrintf) {
|
||||||
|
fmt::format_arg_store<fmt::printf_context, int> as{42};
|
||||||
|
fmt::basic_format_args<fmt::printf_context> args(as);
|
||||||
|
EXPECT_EQ(fmt::vsprintf("%d", args), "42");
|
||||||
|
EXPECT_WRITE(stdout, fmt::vprintf("%d", args), "42");
|
||||||
|
EXPECT_WRITE(stdout, fmt::vfprintf(stdout, "%d", args), "42");
|
||||||
|
EXPECT_WRITE(stdout, fmt::vfprintf(std::cout, "%d", args), "42");
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename... Args>
|
||||||
|
void check_format_string_regression(fmt::string_view s, const Args&... args) {
|
||||||
|
fmt::sprintf(s, args...);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(PrintfTest, CheckFormatStringRegression) {
|
||||||
|
check_format_string_regression("%c%s", 'x', "");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(PrintfTest, VSPrintfMakeArgsExample) {
|
||||||
|
fmt::format_arg_store<fmt::printf_context, int, const char *> as{
|
||||||
|
42, "something"};
|
||||||
|
fmt::basic_format_args<fmt::printf_context> args(as);
|
||||||
|
EXPECT_EQ(
|
||||||
|
"[42] something happened", fmt::vsprintf("[%d] %s happened", args));
|
||||||
|
auto as2 = fmt::make_printf_args(42, "something");
|
||||||
|
fmt::basic_format_args<fmt::printf_context> args2(as2);
|
||||||
|
EXPECT_EQ(
|
||||||
|
"[42] something happened", fmt::vsprintf("[%d] %s happened", args2));
|
||||||
|
//the older gcc versions can't cast the return value
|
||||||
|
#if !defined(__GNUC__) || (__GNUC__ > 4)
|
||||||
|
EXPECT_EQ(
|
||||||
|
"[42] something happened",
|
||||||
|
fmt::vsprintf(
|
||||||
|
"[%d] %s happened", fmt::make_printf_args(42, "something")));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(PrintfTest, VSPrintfMakeWArgsExample) {
|
||||||
|
fmt::format_arg_store<fmt::wprintf_context, int, const wchar_t *> as{
|
||||||
|
42, L"something"};
|
||||||
|
fmt::basic_format_args<fmt::wprintf_context> args(as);
|
||||||
|
EXPECT_EQ(
|
||||||
|
L"[42] something happened",
|
||||||
|
fmt::vsprintf(L"[%d] %s happened", args));
|
||||||
|
auto as2 = fmt::make_wprintf_args(42, L"something");
|
||||||
|
fmt::basic_format_args<fmt::wprintf_context> args2(as2);
|
||||||
|
EXPECT_EQ(
|
||||||
|
L"[42] something happened", fmt::vsprintf(L"[%d] %s happened", args2));
|
||||||
|
// the older gcc versions can't cast the return value
|
||||||
|
#if !defined(__GNUC__) || (__GNUC__ > 4)
|
||||||
|
EXPECT_EQ(
|
||||||
|
L"[42] something happened",
|
||||||
|
fmt::vsprintf(
|
||||||
|
L"[%d] %s happened", fmt::make_wprintf_args(42, L"something")));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
3
externals/fmt/test/ranges-test.cc
vendored
3
externals/fmt/test/ranges-test.cc
vendored
|
@ -9,12 +9,11 @@
|
||||||
// All Rights Reserved
|
// All Rights Reserved
|
||||||
// {fmt} support for ranges, containers and types tuple interface.
|
// {fmt} support for ranges, containers and types tuple interface.
|
||||||
|
|
||||||
#include "fmt/ranges.h"
|
|
||||||
|
|
||||||
/// Check if 'if constexpr' is supported.
|
/// Check if 'if constexpr' is supported.
|
||||||
#if (__cplusplus > 201402L) || \
|
#if (__cplusplus > 201402L) || \
|
||||||
(defined(_MSVC_LANG) && _MSVC_LANG > 201402L && _MSC_VER >= 1910)
|
(defined(_MSVC_LANG) && _MSVC_LANG > 201402L && _MSC_VER >= 1910)
|
||||||
|
|
||||||
|
#include "fmt/ranges.h"
|
||||||
#include "gtest.h"
|
#include "gtest.h"
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
15
externals/fmt/test/time-test.cc
vendored
15
externals/fmt/test/time-test.cc
vendored
|
@ -10,6 +10,7 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "gmock.h"
|
#include "gmock.h"
|
||||||
|
#include "fmt/locale.h"
|
||||||
#include "fmt/time.h"
|
#include "fmt/time.h"
|
||||||
|
|
||||||
TEST(TimeTest, Format) {
|
TEST(TimeTest, Format) {
|
||||||
|
@ -26,10 +27,18 @@ TEST(TimeTest, GrowBuffer) {
|
||||||
for (int i = 0; i < 30; ++i)
|
for (int i = 0; i < 30; ++i)
|
||||||
s += "%c";
|
s += "%c";
|
||||||
s += "}\n";
|
s += "}\n";
|
||||||
std::time_t t = std::time(nullptr);
|
std::time_t t = std::time(FMT_NULL);
|
||||||
fmt::format(s, *std::localtime(&t));
|
fmt::format(s, *std::localtime(&t));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(TimeTest, FormatToEmptyContainer) {
|
||||||
|
std::string s;
|
||||||
|
auto time = std::tm();
|
||||||
|
time.tm_sec = 42;
|
||||||
|
fmt::format_to(std::back_inserter(s), "{:%S}", time);
|
||||||
|
EXPECT_EQ(s, "42");
|
||||||
|
}
|
||||||
|
|
||||||
TEST(TimeTest, EmptyResult) {
|
TEST(TimeTest, EmptyResult) {
|
||||||
EXPECT_EQ("", fmt::format("{}", std::tm()));
|
EXPECT_EQ("", fmt::format("{}", std::tm()));
|
||||||
}
|
}
|
||||||
|
@ -47,13 +56,13 @@ static bool EqualTime(const std::tm &lhs, const std::tm &rhs) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(TimeTest, LocalTime) {
|
TEST(TimeTest, LocalTime) {
|
||||||
std::time_t t = std::time(nullptr);
|
std::time_t t = std::time(FMT_NULL);
|
||||||
std::tm tm = *std::localtime(&t);
|
std::tm tm = *std::localtime(&t);
|
||||||
EXPECT_TRUE(EqualTime(tm, fmt::localtime(t)));
|
EXPECT_TRUE(EqualTime(tm, fmt::localtime(t)));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(TimeTest, GMTime) {
|
TEST(TimeTest, GMTime) {
|
||||||
std::time_t t = std::time(nullptr);
|
std::time_t t = std::time(FMT_NULL);
|
||||||
std::tm tm = *std::gmtime(&t);
|
std::tm tm = *std::gmtime(&t);
|
||||||
EXPECT_TRUE(EqualTime(tm, fmt::gmtime(t)));
|
EXPECT_TRUE(EqualTime(tm, fmt::gmtime(t)));
|
||||||
}
|
}
|
||||||
|
|
2
externals/fmt/test/util.h
vendored
2
externals/fmt/test/util.h
vendored
|
@ -35,7 +35,7 @@ std::string get_system_error(int error_code);
|
||||||
extern const char *const FILE_CONTENT;
|
extern const char *const FILE_CONTENT;
|
||||||
|
|
||||||
// Opens a buffered file for reading.
|
// Opens a buffered file for reading.
|
||||||
fmt::buffered_file open_buffered_file(FILE **fp = nullptr);
|
fmt::buffered_file open_buffered_file(FILE **fp = FMT_NULL);
|
||||||
|
|
||||||
inline FILE *safe_fopen(const char *filename, const char *mode) {
|
inline FILE *safe_fopen(const char *filename, const char *mode) {
|
||||||
#if defined(_WIN32) && !defined(__MINGW32__)
|
#if defined(_WIN32) && !defined(__MINGW32__)
|
||||||
|
|
Loading…
Reference in a new issue