update spdlog
This commit is contained in:
parent
ba4cf75e0f
commit
c86fa8ad3b
87
third_party/spdlog/CMakeLists.txt
vendored
87
third_party/spdlog/CMakeLists.txt
vendored
@ -63,31 +63,43 @@ option(SPDLOG_SANITIZE_ADDRESS "Enable address sanitizer in tests" OFF)
|
|||||||
# install options
|
# install options
|
||||||
option(SPDLOG_INSTALL "Generate the install target" ${SPDLOG_MASTER_PROJECT})
|
option(SPDLOG_INSTALL "Generate the install target" ${SPDLOG_MASTER_PROJECT})
|
||||||
option(SPDLOG_FMT_EXTERNAL "Use external fmt library instead of bundled" OFF)
|
option(SPDLOG_FMT_EXTERNAL "Use external fmt library instead of bundled" OFF)
|
||||||
|
option(SPDLOG_FMT_EXTERNAL_HO "Use external fmt header-only library instead of bundled" OFF)
|
||||||
|
option(SPDLOG_NO_EXCEPTIONS "Compile with -fno-exceptions. Call abort() on any spdlog exceptions" OFF)
|
||||||
|
|
||||||
|
if (SPDLOG_FMT_EXTERNAL AND SPDLOG_FMT_EXTERNAL_HO)
|
||||||
|
message(FATAL_ERROR "SPDLOG_FMT_EXTERNAL and SPDLOG_FMT_EXTERNAL_HO are mutually exclusive")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# misc tweakme options
|
||||||
if(WIN32)
|
if(WIN32)
|
||||||
option(SPDLOG_WCHAR_SUPPORT "Support wchar api" OFF)
|
option(SPDLOG_WCHAR_SUPPORT "Support wchar api" OFF)
|
||||||
option(SPDLOG_WCHAR_FILENAMES "Support wchar filenames" OFF)
|
option(SPDLOG_WCHAR_FILENAMES "Support wchar filenames" OFF)
|
||||||
endif()
|
endif()
|
||||||
|
if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
|
||||||
|
option(SPDLOG_CLOCK_COARSE "Use the much faster (but much less accurate) CLOCK_REALTIME_COARSE instead of the regular clock," OFF)
|
||||||
|
endif()
|
||||||
|
|
||||||
option(SPDLOG_NO_EXCEPTIONS "Compile with -fno-exceptions. Call abort() on any spdlog exceptions" OFF)
|
option(SPDLOG_PREVENT_CHILD_FD "Prevent from child processes to inherit log file descriptors" OFF)
|
||||||
|
option(SPDLOG_NO_THREAD_ID "prevent spdlog from querying the thread id on each log call if thread id is not needed" OFF)
|
||||||
|
option(SPDLOG_NO_TLS "prevent spdlog from using thread local storage" OFF)
|
||||||
|
option(SPDLOG_NO_ATOMIC_LEVELS "prevent spdlog from using of std::atomic log levels (use only if your code never modifies log levels concurrently" OFF)
|
||||||
|
|
||||||
find_package(Threads REQUIRED)
|
find_package(Threads REQUIRED)
|
||||||
|
|
||||||
message(STATUS "Build type: " ${CMAKE_BUILD_TYPE})
|
message(STATUS "Build type: " ${CMAKE_BUILD_TYPE})
|
||||||
|
|
||||||
#---------------------------------------------------------------------------------------
|
#---------------------------------------------------------------------------------------
|
||||||
# Static/Shared library (shared not supported in windows yet)
|
# Static/Shared library (shared not supported in windows yet)
|
||||||
#---------------------------------------------------------------------------------------
|
#---------------------------------------------------------------------------------------
|
||||||
set(SPDLOG_SRCS
|
set(SPDLOG_SRCS
|
||||||
src/spdlog.cpp
|
src/spdlog.cpp
|
||||||
src/stdout_sinks.cpp
|
src/stdout_sinks.cpp
|
||||||
src/fmt.cpp
|
|
||||||
src/color_sinks.cpp
|
src/color_sinks.cpp
|
||||||
src/file_sinks.cpp
|
src/file_sinks.cpp
|
||||||
src/async.cpp)
|
src/async.cpp)
|
||||||
|
|
||||||
set(SPDLOG_CFLAGS "${PROJECT_NAME}")
|
|
||||||
|
if(NOT SPDLOG_FMT_EXTERNAL AND NOT SPDLOG_FMT_EXTERNAL_HO)
|
||||||
|
list(APPEND SPDLOG_SRCS src/fmt.cpp)
|
||||||
|
endif()
|
||||||
|
|
||||||
if (SPDLOG_BUILD_SHARED)
|
if (SPDLOG_BUILD_SHARED)
|
||||||
if(WIN32)
|
if(WIN32)
|
||||||
@ -123,22 +135,30 @@ target_link_libraries(spdlog_header_only INTERFACE Threads::Threads)
|
|||||||
|
|
||||||
|
|
||||||
#---------------------------------------------------------------------------------------
|
#---------------------------------------------------------------------------------------
|
||||||
# Use fmt package if using exertnal fmt
|
# Use fmt package if using external fmt
|
||||||
#---------------------------------------------------------------------------------------
|
#---------------------------------------------------------------------------------------
|
||||||
if(SPDLOG_FMT_EXTERNAL)
|
if(SPDLOG_FMT_EXTERNAL OR SPDLOG_FMT_EXTERNAL_HO)
|
||||||
if (NOT TARGET fmt::fmt)
|
if (NOT TARGET fmt::fmt)
|
||||||
find_package(fmt REQUIRED)
|
find_package(fmt REQUIRED)
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
set(SPDLOG_CFLAGS "${SPDLOG_CFLAGS} -DSPDLOG_FMT_EXTERNAL")
|
|
||||||
|
|
||||||
target_compile_definitions(spdlog PUBLIC SPDLOG_FMT_EXTERNAL)
|
target_compile_definitions(spdlog PUBLIC SPDLOG_FMT_EXTERNAL)
|
||||||
target_link_libraries(spdlog PUBLIC fmt::fmt)
|
|
||||||
|
|
||||||
target_compile_definitions(spdlog_header_only INTERFACE SPDLOG_FMT_EXTERNAL)
|
target_compile_definitions(spdlog_header_only INTERFACE SPDLOG_FMT_EXTERNAL)
|
||||||
|
|
||||||
|
# use external fmt-header-nly
|
||||||
|
if(SPDLOG_FMT_EXTERNAL_HO)
|
||||||
|
target_link_libraries(spdlog PUBLIC fmt::fmt-header-only)
|
||||||
|
target_link_libraries(spdlog_header_only INTERFACE fmt::fmt-header-only)
|
||||||
|
else() # use external compile fmt
|
||||||
|
target_link_libraries(spdlog PUBLIC fmt::fmt)
|
||||||
target_link_libraries(spdlog_header_only INTERFACE fmt::fmt)
|
target_link_libraries(spdlog_header_only INTERFACE fmt::fmt)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
set(PKG_CONFIG_REQUIRES fmt) # add dependency to pkg-config
|
||||||
|
endif()
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------------
|
||||||
|
# Misc definitions according to tweak options
|
||||||
|
#---------------------------------------------------------------------------------------
|
||||||
if(SPDLOG_WCHAR_SUPPORT)
|
if(SPDLOG_WCHAR_SUPPORT)
|
||||||
target_compile_definitions(spdlog PUBLIC SPDLOG_WCHAR_TO_UTF8_SUPPORT)
|
target_compile_definitions(spdlog PUBLIC SPDLOG_WCHAR_TO_UTF8_SUPPORT)
|
||||||
target_compile_definitions(spdlog_header_only INTERFACE SPDLOG_WCHAR_TO_UTF8_SUPPORT)
|
target_compile_definitions(spdlog_header_only INTERFACE SPDLOG_WCHAR_TO_UTF8_SUPPORT)
|
||||||
@ -159,6 +179,31 @@ if(SPDLOG_WCHAR_SUPPORT)
|
|||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(SPDLOG_CLOCK_COARSE)
|
||||||
|
target_compile_definitions(spdlog PRIVATE SPDLOG_CLOCK_COARSE)
|
||||||
|
target_compile_definitions(spdlog_header_only INTERFACE SPDLOG_CLOCK_COARSE)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(SPDLOG_PREVENT_CHILD_FD)
|
||||||
|
target_compile_definitions(spdlog PRIVATE SPDLOG_PREVENT_CHILD_FD)
|
||||||
|
target_compile_definitions(spdlog_header_only INTERFACE SPDLOG_PREVENT_CHILD_FD)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(SPDLOG_NO_THREAD_ID)
|
||||||
|
target_compile_definitions(spdlog PRIVATE SPDLOG_NO_THREAD_ID)
|
||||||
|
target_compile_definitions(spdlog_header_only INTERFACE SPDLOG_NO_THREAD_ID)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(SPDLOG_NO_TLS)
|
||||||
|
target_compile_definitions(spdlog PRIVATE SPDLOG_NO_TLS)
|
||||||
|
target_compile_definitions(spdlog_header_only INTERFACE SPDLOG_NO_TLS)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(SPDLOG_NO_ATOMIC_LEVELS)
|
||||||
|
target_compile_definitions(spdlog PUBLIC SPDLOG_NO_ATOMIC_LEVELS)
|
||||||
|
target_compile_definitions(spdlog_header_only INTERFACE SPDLOG_NO_ATOMIC_LEVELS)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
|
||||||
#---------------------------------------------------------------------------------------
|
#---------------------------------------------------------------------------------------
|
||||||
# Build binaries
|
# Build binaries
|
||||||
@ -188,7 +233,7 @@ if (SPDLOG_INSTALL)
|
|||||||
set(project_config_out "${CMAKE_CURRENT_BINARY_DIR}/spdlogConfig.cmake")
|
set(project_config_out "${CMAKE_CURRENT_BINARY_DIR}/spdlogConfig.cmake")
|
||||||
set(config_targets_file "spdlogConfigTargets.cmake")
|
set(config_targets_file "spdlogConfigTargets.cmake")
|
||||||
set(version_config_file "${CMAKE_CURRENT_BINARY_DIR}/spdlogConfigVersion.cmake")
|
set(version_config_file "${CMAKE_CURRENT_BINARY_DIR}/spdlogConfigVersion.cmake")
|
||||||
set(export_dest_dir "${CMAKE_INSTALL_LIBDIR}/spdlog/cmake")
|
set(export_dest_dir "${CMAKE_INSTALL_LIBDIR}/cmake/spdlog")
|
||||||
set(pkgconfig_install_dir "${CMAKE_INSTALL_LIBDIR}/pkgconfig")
|
set(pkgconfig_install_dir "${CMAKE_INSTALL_LIBDIR}/pkgconfig")
|
||||||
set(pkg_config "${CMAKE_BINARY_DIR}/${PROJECT_NAME}.pc")
|
set(pkg_config "${CMAKE_BINARY_DIR}/${PROJECT_NAME}.pc")
|
||||||
|
|
||||||
@ -196,19 +241,25 @@ if (SPDLOG_INSTALL)
|
|||||||
# Include files
|
# Include files
|
||||||
#---------------------------------------------------------------------------------------
|
#---------------------------------------------------------------------------------------
|
||||||
install(DIRECTORY include/ DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}" PATTERN "fmt/bundled" EXCLUDE)
|
install(DIRECTORY include/ DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}" PATTERN "fmt/bundled" EXCLUDE)
|
||||||
install(TARGETS spdlog spdlog_header_only EXPORT spdlog DESTINATION "${CMAKE_INSTALL_LIBDIR}/spdlog")
|
install(TARGETS spdlog spdlog_header_only EXPORT spdlog DESTINATION "${CMAKE_INSTALL_LIBDIR}")
|
||||||
|
|
||||||
if(NOT SPDLOG_FMT_EXTERNAL)
|
if(NOT SPDLOG_FMT_EXTERNAL AND NOT SPDLOG_FMT_EXTERNAL_HO)
|
||||||
install(DIRECTORY include/${PROJECT_NAME}/fmt/bundled/
|
install(DIRECTORY include/${PROJECT_NAME}/fmt/bundled/
|
||||||
DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME}/fmt/bundled/")
|
DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME}/fmt/bundled/")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
#---------------------------------------------------------------------------------------
|
#---------------------------------------------------------------------------------------
|
||||||
# Package and version files
|
# Install pkg-config file
|
||||||
#---------------------------------------------------------------------------------------
|
#---------------------------------------------------------------------------------------
|
||||||
|
get_target_property(PKG_CONFIG_DEFINES spdlog INTERFACE_COMPILE_DEFINITIONS)
|
||||||
|
string(REPLACE ";" " -D" PKG_CONFIG_DEFINES "${PKG_CONFIG_DEFINES}")
|
||||||
|
string(CONCAT PKG_CONFIG_DEFINES "-D" "${PKG_CONFIG_DEFINES}")
|
||||||
configure_file("cmake/${PROJECT_NAME}.pc.in" "${pkg_config}" @ONLY)
|
configure_file("cmake/${PROJECT_NAME}.pc.in" "${pkg_config}" @ONLY)
|
||||||
install(FILES "${pkg_config}" DESTINATION "${pkgconfig_install_dir}")
|
install(FILES "${pkg_config}" DESTINATION "${pkgconfig_install_dir}")
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------------
|
||||||
|
# Install CMake config files
|
||||||
|
#---------------------------------------------------------------------------------------
|
||||||
install(EXPORT spdlog
|
install(EXPORT spdlog
|
||||||
DESTINATION ${export_dest_dir}
|
DESTINATION ${export_dest_dir}
|
||||||
NAMESPACE spdlog::
|
NAMESPACE spdlog::
|
||||||
@ -216,6 +267,7 @@ if (SPDLOG_INSTALL)
|
|||||||
|
|
||||||
include(CMakePackageConfigHelpers)
|
include(CMakePackageConfigHelpers)
|
||||||
configure_file("${project_config_in}" "${project_config_out}" @ONLY)
|
configure_file("${project_config_in}" "${project_config_out}" @ONLY)
|
||||||
|
|
||||||
write_basic_package_version_file("${version_config_file}" COMPATIBILITY SameMajorVersion)
|
write_basic_package_version_file("${version_config_file}" COMPATIBILITY SameMajorVersion)
|
||||||
install(FILES
|
install(FILES
|
||||||
"${project_config_out}"
|
"${project_config_out}"
|
||||||
@ -227,3 +279,4 @@ if (SPDLOG_INSTALL)
|
|||||||
include(cmake/spdlogCPack.cmake)
|
include(cmake/spdlogCPack.cmake)
|
||||||
|
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
|
2
third_party/spdlog/README.md
vendored
2
third_party/spdlog/README.md
vendored
@ -30,6 +30,8 @@ $ cmake .. && make -j
|
|||||||
* Gentoo: `emerge dev-libs/spdlog`
|
* Gentoo: `emerge dev-libs/spdlog`
|
||||||
* Arch Linux: `yaourt -S spdlog-git`
|
* Arch Linux: `yaourt -S spdlog-git`
|
||||||
* vcpkg: `vcpkg install spdlog`
|
* vcpkg: `vcpkg install spdlog`
|
||||||
|
* conan: `spdlog/[>=1.4.1]@bincrafters/stable`
|
||||||
|
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
* Very fast (see [benchmarks](#benchmarks) below).
|
* Very fast (see [benchmarks](#benchmarks) below).
|
||||||
|
22
third_party/spdlog/appveyor.yml
vendored
22
third_party/spdlog/appveyor.yml
vendored
@ -1,19 +1,25 @@
|
|||||||
version: 1.0.{build}
|
version: 1.0.{build}
|
||||||
image: Visual Studio 2015
|
image: Visual Studio 2017
|
||||||
environment:
|
environment:
|
||||||
matrix:
|
matrix:
|
||||||
- GENERATOR: '"MinGW Makefiles"'
|
|
||||||
BUILD_TYPE: Debug
|
|
||||||
- GENERATOR: '"MinGW Makefiles"'
|
|
||||||
BUILD_TYPE: Release
|
|
||||||
- GENERATOR: '"Visual Studio 14 2015"'
|
- GENERATOR: '"Visual Studio 14 2015"'
|
||||||
BUILD_TYPE: Debug
|
BUILD_TYPE: Debug
|
||||||
|
WCHAR: 'OFF'
|
||||||
- GENERATOR: '"Visual Studio 14 2015"'
|
- GENERATOR: '"Visual Studio 14 2015"'
|
||||||
BUILD_TYPE: Release
|
BUILD_TYPE: Release
|
||||||
|
WCHAR: 'ON'
|
||||||
- GENERATOR: '"Visual Studio 14 2015 Win64"'
|
- GENERATOR: '"Visual Studio 14 2015 Win64"'
|
||||||
BUILD_TYPE: Debug
|
BUILD_TYPE: Debug
|
||||||
|
WCHAR: 'ON'
|
||||||
- GENERATOR: '"Visual Studio 14 2015 Win64"'
|
- GENERATOR: '"Visual Studio 14 2015 Win64"'
|
||||||
BUILD_TYPE: Release
|
BUILD_TYPE: Release
|
||||||
|
WCHAR: 'ON'
|
||||||
|
- GENERATOR: '"Visual Studio 15 2017 Win64"'
|
||||||
|
BUILD_TYPE: Debug
|
||||||
|
WCHAR: 'ON'
|
||||||
|
- GENERATOR: '"Visual Studio 15 2017 Win64"'
|
||||||
|
BUILD_TYPE: Release
|
||||||
|
WCHAR: 'OFf'
|
||||||
build_script:
|
build_script:
|
||||||
- cmd: >-
|
- cmd: >-
|
||||||
set
|
set
|
||||||
@ -22,11 +28,9 @@ build_script:
|
|||||||
|
|
||||||
cd build
|
cd build
|
||||||
|
|
||||||
set PATH=%PATH:C:\Program Files\Git\usr\bin;=%
|
set PATH=%PATH%:C:\Program Files\Git\usr\bin
|
||||||
|
|
||||||
set PATH=C:\mingw-w64\i686-5.3.0-posix-dwarf-rt_v4-rev0\mingw32\bin;%PATH%
|
cmake .. -G %GENERATOR% -DCMAKE_BUILD_TYPE=%BUILD_TYPE% -DSPDLOG_WCHAR_SUPPORT=%WCHAR% -DSPDLOG_BUILD_EXAMPLE=ON -DSPDLOG_BUILD_EXAMPLE_HO=ON -DSPDLOG_BUILD_TESTS=ON -DSPDLOG_BUILD_TESTS_HO=OFF
|
||||||
|
|
||||||
cmake .. -G %GENERATOR% -DCMAKE_BUILD_TYPE=%BUILD_TYPE% -DSPDLOG_WCHAR_SUPPORT=ON -DSPDLOG_BUILD_EXAMPLE=ON -DSPDLOG_BUILD_EXAMPLE_HO=ON -DSPDLOG_BUILD_TESTS=ON -DSPDLOG_BUILD_TESTS_HO=OFF
|
|
||||||
|
|
||||||
cmake --build . --config %BUILD_TYPE%
|
cmake --build . --config %BUILD_TYPE%
|
||||||
|
|
||||||
|
2
third_party/spdlog/bench/CMakeLists.txt
vendored
2
third_party/spdlog/bench/CMakeLists.txt
vendored
@ -24,5 +24,3 @@ target_link_libraries(latency PRIVATE benchmark::benchmark spdlog::spdlog)
|
|||||||
|
|
||||||
add_executable(formatter-bench formatter-bench.cpp)
|
add_executable(formatter-bench formatter-bench.cpp)
|
||||||
target_link_libraries(formatter-bench PRIVATE benchmark::benchmark spdlog::spdlog)
|
target_link_libraries(formatter-bench PRIVATE benchmark::benchmark spdlog::spdlog)
|
||||||
|
|
||||||
file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/logs")
|
|
||||||
|
22
third_party/spdlog/bench/latency.cpp
vendored
22
third_party/spdlog/bench/latency.cpp
vendored
@ -16,26 +16,6 @@
|
|||||||
#include "spdlog/sinks/null_sink.h"
|
#include "spdlog/sinks/null_sink.h"
|
||||||
#include "spdlog/sinks/rotating_file_sink.h"
|
#include "spdlog/sinks/rotating_file_sink.h"
|
||||||
|
|
||||||
void prepare_logdir()
|
|
||||||
{
|
|
||||||
spdlog::info("Preparing latency_logs directory..");
|
|
||||||
#ifdef _WIN32
|
|
||||||
system("if not exist logs mkdir latency_logs");
|
|
||||||
system("del /F /Q logs\\*");
|
|
||||||
#else
|
|
||||||
auto rv = system("mkdir -p latency_logs");
|
|
||||||
if (rv != 0)
|
|
||||||
{
|
|
||||||
throw std::runtime_error("Failed to mkdir -p latency_logs");
|
|
||||||
}
|
|
||||||
rv = system("rm -f latency_logs/*");
|
|
||||||
if (rv != 0)
|
|
||||||
{
|
|
||||||
throw std::runtime_error("Failed to rm -f latency_logs/*");
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void bench_c_string(benchmark::State &state, std::shared_ptr<spdlog::logger> logger)
|
void bench_c_string(benchmark::State &state, std::shared_ptr<spdlog::logger> logger)
|
||||||
{
|
{
|
||||||
const char *msg = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum pharetra metus cursus "
|
const char *msg = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum pharetra metus cursus "
|
||||||
@ -83,8 +63,6 @@ int main(int argc, char *argv[])
|
|||||||
size_t rotating_files = 5;
|
size_t rotating_files = 5;
|
||||||
int n_threads = benchmark::CPUInfo::Get().num_cpus;
|
int n_threads = benchmark::CPUInfo::Get().num_cpus;
|
||||||
|
|
||||||
prepare_logdir();
|
|
||||||
|
|
||||||
// disabled loggers
|
// disabled loggers
|
||||||
auto disabled_logger = std::make_shared<spdlog::logger>("bench", std::make_shared<null_sink_mt>());
|
auto disabled_logger = std::make_shared<spdlog::logger>("bench", std::make_shared<null_sink_mt>());
|
||||||
disabled_logger->set_level(spdlog::level::off);
|
disabled_logger->set_level(spdlog::level::off);
|
||||||
|
1
third_party/spdlog/bench/meson.build
vendored
1
third_party/spdlog/bench/meson.build
vendored
@ -12,4 +12,3 @@ foreach i : bench_matrix
|
|||||||
benchmark('bench_' + i[0], bench_exe, args: i[2])
|
benchmark('bench_' + i[0], bench_exe, args: i[2])
|
||||||
endforeach
|
endforeach
|
||||||
|
|
||||||
run_command(find_program('mkdir'), meson.current_build_dir() + '/logs')
|
|
||||||
|
6
third_party/spdlog/cmake/spdlog.pc.in
vendored
6
third_party/spdlog/cmake/spdlog.pc.in
vendored
@ -7,5 +7,7 @@ Name: lib@PROJECT_NAME@
|
|||||||
Description: Fast C++ logging library.
|
Description: Fast C++ logging library.
|
||||||
URL: https://github.com/gabime/@PROJECT_NAME@
|
URL: https://github.com/gabime/@PROJECT_NAME@
|
||||||
Version: @SPDLOG_VERSION@
|
Version: @SPDLOG_VERSION@
|
||||||
CFlags: -I${includedir}/@SPDLOG_CFLAGS@
|
CFlags: -I${includedir} @PKG_CONFIG_DEFINES@
|
||||||
Libs: -L${libdir}/@PROJECT_NAME@ -l@PROJECT_NAME@
|
Libs: -L${libdir} -lspdlog -pthread
|
||||||
|
Requires: @PKG_CONFIG_REQUIRES@
|
||||||
|
|
||||||
|
5
third_party/spdlog/cmake/utils.cmake
vendored
5
third_party/spdlog/cmake/utils.cmake
vendored
@ -29,7 +29,10 @@ function(spdlog_enable_warnings target_name)
|
|||||||
target_compile_options(${target_name} PRIVATE
|
target_compile_options(${target_name} PRIVATE
|
||||||
$<$<OR:$<CXX_COMPILER_ID:Clang>,$<CXX_COMPILER_ID:AppleClang>,$<CXX_COMPILER_ID:GNU>>:
|
$<$<OR:$<CXX_COMPILER_ID:Clang>,$<CXX_COMPILER_ID:AppleClang>,$<CXX_COMPILER_ID:GNU>>:
|
||||||
-Wall -Wextra -Wconversion -pedantic -Wfatal-errors>
|
-Wall -Wextra -Wconversion -pedantic -Wfatal-errors>
|
||||||
$<$<CXX_COMPILER_ID:MSVC>:/W4 /WX>)
|
$<$<CXX_COMPILER_ID:MSVC>:/W4>)
|
||||||
|
if(MSVC_VERSION GREATER_EQUAL 1910) #Allow non fatal security wanrnings for msvc 2015
|
||||||
|
target_compile_options(${target_name} PRIVATE /WX)
|
||||||
|
endif()
|
||||||
endfunction()
|
endfunction()
|
||||||
|
|
||||||
|
|
||||||
|
2
third_party/spdlog/example/CMakeLists.txt
vendored
2
third_party/spdlog/example/CMakeLists.txt
vendored
@ -25,5 +25,3 @@ if(SPDLOG_BUILD_EXAMPLE_HO)
|
|||||||
target_link_libraries(example_header_only PRIVATE spdlog::spdlog_header_only)
|
target_link_libraries(example_header_only PRIVATE spdlog::spdlog_header_only)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Create logs directory
|
|
||||||
file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/logs")
|
|
||||||
|
2
third_party/spdlog/example/example.cpp
vendored
2
third_party/spdlog/example/example.cpp
vendored
@ -143,7 +143,7 @@ void async_example()
|
|||||||
#include "spdlog/fmt/bin_to_hex.h"
|
#include "spdlog/fmt/bin_to_hex.h"
|
||||||
void binary_example()
|
void binary_example()
|
||||||
{
|
{
|
||||||
std::vector<char> buf;
|
std::vector<char> buf(80);
|
||||||
for (int i = 0; i < 80; i++)
|
for (int i = 0; i < 80; i++)
|
||||||
{
|
{
|
||||||
buf.push_back(static_cast<char>(i & 0xff));
|
buf.push_back(static_cast<char>(i & 0xff));
|
||||||
|
1
third_party/spdlog/example/meson.build
vendored
1
third_party/spdlog/example/meson.build
vendored
@ -1,5 +1,4 @@
|
|||||||
executable('example', 'example.cpp', dependencies: spdlog_dep)
|
executable('example', 'example.cpp', dependencies: spdlog_dep)
|
||||||
executable('example_header_only', 'example.cpp', dependencies: spdlog_headeronly_dep)
|
executable('example_header_only', 'example.cpp', dependencies: spdlog_headeronly_dep)
|
||||||
run_command(find_program('mkdir'), meson.current_build_dir() + '/logs')
|
|
||||||
|
|
||||||
|
|
||||||
|
8
third_party/spdlog/include/spdlog/async.h
vendored
8
third_party/spdlog/include/spdlog/async.h
vendored
@ -6,7 +6,7 @@
|
|||||||
//
|
//
|
||||||
// Async logging using global thread pool
|
// Async logging using global thread pool
|
||||||
// All loggers created here share same global thread pool.
|
// All loggers created here share same global thread pool.
|
||||||
// Each log message is pushed to a queue along withe a shared pointer to the
|
// Each log message is pushed to a queue along with a shared pointer to the
|
||||||
// logger.
|
// logger.
|
||||||
// If a logger deleted while having pending messages in the queue, it's actual
|
// If a logger deleted while having pending messages in the queue, it's actual
|
||||||
// destruction will defer
|
// destruction will defer
|
||||||
@ -14,9 +14,9 @@
|
|||||||
// This is because each message in the queue holds a shared_ptr to the
|
// This is because each message in the queue holds a shared_ptr to the
|
||||||
// originating logger.
|
// originating logger.
|
||||||
|
|
||||||
#include "spdlog/async_logger.h"
|
#include <spdlog/async_logger.h>
|
||||||
#include "spdlog/details/registry.h"
|
#include <spdlog/details/registry.h>
|
||||||
#include "spdlog/details/thread_pool.h"
|
#include <spdlog/details/thread_pool.h>
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
@ -4,11 +4,11 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#ifndef SPDLOG_HEADER_ONLY
|
#ifndef SPDLOG_HEADER_ONLY
|
||||||
#include "spdlog/async_logger.h"
|
#include <spdlog/async_logger.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "spdlog/sinks/sink.h"
|
#include <spdlog/sinks/sink.h>
|
||||||
#include "spdlog/details/thread_pool.h"
|
#include <spdlog/details/thread_pool.h>
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
// Upon destruction, logs all remaining messages in the queue before
|
// Upon destruction, logs all remaining messages in the queue before
|
||||||
// destructing..
|
// destructing..
|
||||||
|
|
||||||
#include "spdlog/logger.h"
|
#include <spdlog/logger.h>
|
||||||
|
|
||||||
namespace spdlog {
|
namespace spdlog {
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#ifndef SPDLOG_HEADER_ONLY
|
#ifndef SPDLOG_HEADER_ONLY
|
||||||
#include "spdlog/common.h"
|
#include <spdlog/common.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace spdlog {
|
namespace spdlog {
|
||||||
|
8
third_party/spdlog/include/spdlog/common.h
vendored
8
third_party/spdlog/include/spdlog/common.h
vendored
@ -3,8 +3,8 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "spdlog/tweakme.h"
|
#include <spdlog/tweakme.h>
|
||||||
#include "spdlog/details/null_mutex.h"
|
#include <spdlog/details/null_mutex.h>
|
||||||
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
@ -35,7 +35,7 @@
|
|||||||
#define SPDLOG_INLINE inline
|
#define SPDLOG_INLINE inline
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "spdlog/fmt/fmt.h"
|
#include <spdlog/fmt/fmt.h>
|
||||||
|
|
||||||
// visual studio upto 2013 does not support noexcept nor constexpr
|
// visual studio upto 2013 does not support noexcept nor constexpr
|
||||||
#if defined(_MSC_VER) && (_MSC_VER < 1900)
|
#if defined(_MSC_VER) && (_MSC_VER < 1900)
|
||||||
@ -62,7 +62,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef SPDLOG_FUNCTION
|
#ifndef SPDLOG_FUNCTION
|
||||||
#define SPDLOG_FUNCTION __FUNCTION__
|
#define SPDLOG_FUNCTION static_cast<const char *>(__FUNCTION__)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef SPDLOG_NO_EXCEPTIONS
|
#ifdef SPDLOG_NO_EXCEPTIONS
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#ifndef SPDLOG_HEADER_ONLY
|
#ifndef SPDLOG_HEADER_ONLY
|
||||||
#include "spdlog/details/backtracer.h"
|
#include <spdlog/details/backtracer.h>
|
||||||
#endif
|
#endif
|
||||||
namespace spdlog {
|
namespace spdlog {
|
||||||
namespace details {
|
namespace details {
|
||||||
@ -26,7 +26,7 @@ SPDLOG_INLINE backtracer &backtracer::operator=(backtracer other)
|
|||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(mutex_);
|
std::lock_guard<std::mutex> lock(mutex_);
|
||||||
enabled_ = other.enabled();
|
enabled_ = other.enabled();
|
||||||
messages_ = other.messages_;
|
messages_ = std::move(other.messages_);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -48,11 +48,6 @@ SPDLOG_INLINE bool backtracer::enabled() const
|
|||||||
return enabled_.load(std::memory_order_relaxed);
|
return enabled_.load(std::memory_order_relaxed);
|
||||||
}
|
}
|
||||||
|
|
||||||
SPDLOG_INLINE backtracer::operator bool() const
|
|
||||||
{
|
|
||||||
return enabled();
|
|
||||||
}
|
|
||||||
|
|
||||||
SPDLOG_INLINE void backtracer::push_back(const log_msg &msg)
|
SPDLOG_INLINE void backtracer::push_back(const log_msg &msg)
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock{mutex_};
|
std::lock_guard<std::mutex> lock{mutex_};
|
||||||
|
@ -3,8 +3,8 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "spdlog/details/log_msg_buffer.h"
|
#include <spdlog/details/log_msg_buffer.h>
|
||||||
#include "spdlog/details/circular_q.h"
|
#include <spdlog/details/circular_q.h>
|
||||||
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
@ -31,7 +31,6 @@ public:
|
|||||||
void enable(size_t size);
|
void enable(size_t size);
|
||||||
void disable();
|
void disable();
|
||||||
bool enabled() const;
|
bool enabled() const;
|
||||||
explicit operator bool() const;
|
|
||||||
void push_back(const log_msg &msg);
|
void push_back(const log_msg &msg);
|
||||||
|
|
||||||
// pop all items in the q and apply the given fun on each of them.
|
// pop all items in the q and apply the given fun on each of them.
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
|
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
|
||||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||||
|
|
||||||
// cirucal q view of std::vector.
|
// circular q view of std::vector.
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
namespace spdlog {
|
namespace spdlog {
|
||||||
namespace details {
|
namespace details {
|
||||||
@ -72,6 +73,27 @@ public:
|
|||||||
return v_[head_];
|
return v_[head_];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Return number of elements actually stored
|
||||||
|
size_t size() const
|
||||||
|
{
|
||||||
|
if (tail_ >= head_)
|
||||||
|
{
|
||||||
|
return tail_ - head_;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return max_items_ - (head_ - tail_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return const reference to item by index.
|
||||||
|
// If index is out of range 0…size()-1, the behavior is undefined.
|
||||||
|
const T &at(size_t i) const
|
||||||
|
{
|
||||||
|
assert(i < size());
|
||||||
|
return v_[(head_ + i) % max_items_];
|
||||||
|
}
|
||||||
|
|
||||||
// Pop item from front.
|
// Pop item from front.
|
||||||
// If there are no elements in the container, the behavior is undefined.
|
// If there are no elements in the container, the behavior is undefined.
|
||||||
void pop_front()
|
void pop_front()
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "spdlog/details/null_mutex.h"
|
#include <spdlog/details/null_mutex.h>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
|
||||||
namespace spdlog {
|
namespace spdlog {
|
||||||
|
@ -4,11 +4,11 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#ifndef SPDLOG_HEADER_ONLY
|
#ifndef SPDLOG_HEADER_ONLY
|
||||||
#include "spdlog/details/file_helper.h"
|
#include <spdlog/details/file_helper.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "spdlog/details/os.h"
|
#include <spdlog/details/os.h>
|
||||||
#include "spdlog/common.h"
|
#include <spdlog/common.h>
|
||||||
|
|
||||||
#include <cerrno>
|
#include <cerrno>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
@ -28,28 +28,31 @@ SPDLOG_INLINE file_helper::~file_helper()
|
|||||||
SPDLOG_INLINE void file_helper::open(const filename_t &fname, bool truncate)
|
SPDLOG_INLINE void file_helper::open(const filename_t &fname, bool truncate)
|
||||||
{
|
{
|
||||||
close();
|
close();
|
||||||
|
filename_ = fname;
|
||||||
auto *mode = truncate ? SPDLOG_FILENAME_T("wb") : SPDLOG_FILENAME_T("ab");
|
auto *mode = truncate ? SPDLOG_FILENAME_T("wb") : SPDLOG_FILENAME_T("ab");
|
||||||
_filename = fname;
|
|
||||||
for (int tries = 0; tries < open_tries; ++tries)
|
for (int tries = 0; tries < open_tries_; ++tries)
|
||||||
{
|
{
|
||||||
|
// create containing folder if not exists already.
|
||||||
|
os::create_dir(os::dir_name(fname));
|
||||||
if (!os::fopen_s(&fd_, fname, mode))
|
if (!os::fopen_s(&fd_, fname, mode))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
details::os::sleep_for_millis(open_interval);
|
details::os::sleep_for_millis(open_interval_);
|
||||||
}
|
}
|
||||||
|
|
||||||
SPDLOG_THROW(spdlog_ex("Failed opening file " + os::filename_to_str(_filename) + " for writing", errno));
|
SPDLOG_THROW(spdlog_ex("Failed opening file " + os::filename_to_str(filename_) + " for writing", errno));
|
||||||
}
|
}
|
||||||
|
|
||||||
SPDLOG_INLINE void file_helper::reopen(bool truncate)
|
SPDLOG_INLINE void file_helper::reopen(bool truncate)
|
||||||
{
|
{
|
||||||
if (_filename.empty())
|
if (filename_.empty())
|
||||||
{
|
{
|
||||||
SPDLOG_THROW(spdlog_ex("Failed re opening file - was not opened before"));
|
SPDLOG_THROW(spdlog_ex("Failed re opening file - was not opened before"));
|
||||||
}
|
}
|
||||||
open(_filename, truncate);
|
this->open(filename_, truncate);
|
||||||
}
|
}
|
||||||
|
|
||||||
SPDLOG_INLINE void file_helper::flush()
|
SPDLOG_INLINE void file_helper::flush()
|
||||||
@ -72,7 +75,7 @@ SPDLOG_INLINE void file_helper::write(const memory_buf_t &buf)
|
|||||||
auto data = buf.data();
|
auto data = buf.data();
|
||||||
if (std::fwrite(data, 1, msg_size, fd_) != msg_size)
|
if (std::fwrite(data, 1, msg_size, fd_) != msg_size)
|
||||||
{
|
{
|
||||||
SPDLOG_THROW(spdlog_ex("Failed writing to file " + os::filename_to_str(_filename), errno));
|
SPDLOG_THROW(spdlog_ex("Failed writing to file " + os::filename_to_str(filename_), errno));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -80,19 +83,14 @@ SPDLOG_INLINE size_t file_helper::size() const
|
|||||||
{
|
{
|
||||||
if (fd_ == nullptr)
|
if (fd_ == nullptr)
|
||||||
{
|
{
|
||||||
SPDLOG_THROW(spdlog_ex("Cannot use size() on closed file " + os::filename_to_str(_filename)));
|
SPDLOG_THROW(spdlog_ex("Cannot use size() on closed file " + os::filename_to_str(filename_)));
|
||||||
}
|
}
|
||||||
return os::filesize(fd_);
|
return os::filesize(fd_);
|
||||||
}
|
}
|
||||||
|
|
||||||
SPDLOG_INLINE const filename_t &file_helper::filename() const
|
SPDLOG_INLINE const filename_t &file_helper::filename() const
|
||||||
{
|
{
|
||||||
return _filename;
|
return filename_;
|
||||||
}
|
|
||||||
|
|
||||||
SPDLOG_INLINE bool file_helper::file_exists(const filename_t &fname)
|
|
||||||
{
|
|
||||||
return os::file_exists(fname);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
@ -119,7 +117,7 @@ SPDLOG_INLINE std::tuple<filename_t, filename_t> file_helper::split_by_extension
|
|||||||
return std::make_tuple(fname, filename_t());
|
return std::make_tuple(fname, filename_t());
|
||||||
}
|
}
|
||||||
|
|
||||||
// treat casese like "/etc/rc.d/somelogfile or "/abc/.hiddenfile"
|
// treat cases like "/etc/rc.d/somelogfile or "/abc/.hiddenfile"
|
||||||
auto folder_index = fname.rfind(details::os::folder_sep);
|
auto folder_index = fname.rfind(details::os::folder_sep);
|
||||||
if (folder_index != filename_t::npos && folder_index >= ext_index - 1)
|
if (folder_index != filename_t::npos && folder_index >= ext_index - 1)
|
||||||
{
|
{
|
||||||
@ -129,5 +127,6 @@ SPDLOG_INLINE std::tuple<filename_t, filename_t> file_helper::split_by_extension
|
|||||||
// finally - return a valid base and extension tuple
|
// finally - return a valid base and extension tuple
|
||||||
return std::make_tuple(fname.substr(0, ext_index), fname.substr(ext_index));
|
return std::make_tuple(fname.substr(0, ext_index), fname.substr(ext_index));
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace details
|
} // namespace details
|
||||||
} // namespace spdlog
|
} // namespace spdlog
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "spdlog/common.h"
|
#include <spdlog/common.h>
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
|
|
||||||
namespace spdlog {
|
namespace spdlog {
|
||||||
@ -29,7 +29,6 @@ public:
|
|||||||
void write(const memory_buf_t &buf);
|
void write(const memory_buf_t &buf);
|
||||||
size_t size() const;
|
size_t size() const;
|
||||||
const filename_t &filename() const;
|
const filename_t &filename() const;
|
||||||
static bool file_exists(const filename_t &fname);
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// return file path and its extension:
|
// return file path and its extension:
|
||||||
@ -47,10 +46,10 @@ public:
|
|||||||
static std::tuple<filename_t, filename_t> split_by_extension(const filename_t &fname);
|
static std::tuple<filename_t, filename_t> split_by_extension(const filename_t &fname);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const int open_tries = 5;
|
const int open_tries_ = 5;
|
||||||
const int open_interval = 10;
|
const int open_interval_ = 10;
|
||||||
std::FILE *fd_{nullptr};
|
std::FILE *fd_{nullptr};
|
||||||
filename_t _filename;
|
filename_t filename_;
|
||||||
};
|
};
|
||||||
} // namespace details
|
} // namespace details
|
||||||
} // namespace spdlog
|
} // namespace spdlog
|
||||||
|
@ -4,8 +4,8 @@
|
|||||||
|
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include "spdlog/fmt/fmt.h"
|
#include <spdlog/fmt/fmt.h>
|
||||||
#include "spdlog/common.h"
|
#include <spdlog/common.h>
|
||||||
|
|
||||||
// Some fmt helpers to efficiently format and pad ints and strings
|
// Some fmt helpers to efficiently format and pad ints and strings
|
||||||
namespace spdlog {
|
namespace spdlog {
|
||||||
|
@ -4,21 +4,19 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#ifndef SPDLOG_HEADER_ONLY
|
#ifndef SPDLOG_HEADER_ONLY
|
||||||
#include "spdlog/details/log_msg.h"
|
#include <spdlog/details/log_msg.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "spdlog/details/os.h"
|
#include <spdlog/details/os.h>
|
||||||
|
|
||||||
namespace spdlog {
|
namespace spdlog {
|
||||||
namespace details {
|
namespace details {
|
||||||
|
|
||||||
SPDLOG_INLINE log_msg::log_msg(spdlog::source_loc loc, string_view_t logger_name, spdlog::level::level_enum lvl, spdlog::string_view_t msg)
|
SPDLOG_INLINE log_msg::log_msg(
|
||||||
: logger_name(logger_name)
|
spdlog::source_loc loc, string_view_t a_logger_name, spdlog::level::level_enum lvl, spdlog::string_view_t msg)
|
||||||
|
: logger_name(a_logger_name)
|
||||||
, level(lvl)
|
, level(lvl)
|
||||||
#ifndef SPDLOG_NO_DATETIME
|
|
||||||
, time(os::now())
|
, time(os::now())
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef SPDLOG_NO_THREAD_ID
|
#ifndef SPDLOG_NO_THREAD_ID
|
||||||
, thread_id(os::thread_id())
|
, thread_id(os::thread_id())
|
||||||
#endif
|
#endif
|
||||||
@ -26,8 +24,8 @@ SPDLOG_INLINE log_msg::log_msg(spdlog::source_loc loc, string_view_t logger_name
|
|||||||
, payload(msg)
|
, payload(msg)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
SPDLOG_INLINE log_msg::log_msg(string_view_t logger_name, spdlog::level::level_enum lvl, spdlog::string_view_t msg)
|
SPDLOG_INLINE log_msg::log_msg(string_view_t a_logger_name, spdlog::level::level_enum lvl, spdlog::string_view_t msg)
|
||||||
: log_msg(source_loc{}, logger_name, lvl, msg)
|
: log_msg(source_loc{}, a_logger_name, lvl, msg)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
} // namespace details
|
} // namespace details
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "spdlog/common.h"
|
#include <spdlog/common.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
namespace spdlog {
|
namespace spdlog {
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#ifndef SPDLOG_HEADER_ONLY
|
#ifndef SPDLOG_HEADER_ONLY
|
||||||
#include "spdlog/details/log_msg_buffer.h"
|
#include <spdlog/details/log_msg_buffer.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace spdlog {
|
namespace spdlog {
|
||||||
@ -26,9 +26,7 @@ SPDLOG_INLINE log_msg_buffer::log_msg_buffer(const log_msg_buffer &other)
|
|||||||
update_string_views();
|
update_string_views();
|
||||||
}
|
}
|
||||||
|
|
||||||
SPDLOG_INLINE log_msg_buffer::log_msg_buffer(log_msg_buffer &&other)
|
SPDLOG_INLINE log_msg_buffer::log_msg_buffer(log_msg_buffer &&other) SPDLOG_NOEXCEPT : log_msg{other}, buffer{std::move(other.buffer)}
|
||||||
: log_msg{std::move(other)}
|
|
||||||
, buffer{std::move(other.buffer)}
|
|
||||||
{
|
{
|
||||||
update_string_views();
|
update_string_views();
|
||||||
}
|
}
|
||||||
@ -42,9 +40,9 @@ SPDLOG_INLINE log_msg_buffer &log_msg_buffer::operator=(const log_msg_buffer &ot
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
SPDLOG_INLINE log_msg_buffer &log_msg_buffer::operator=(log_msg_buffer &&other)
|
SPDLOG_INLINE log_msg_buffer &log_msg_buffer::operator=(log_msg_buffer &&other) SPDLOG_NOEXCEPT
|
||||||
{
|
{
|
||||||
log_msg::operator=(std::move(other));
|
log_msg::operator=(other);
|
||||||
buffer = std::move(other.buffer);
|
buffer = std::move(other.buffer);
|
||||||
update_string_views();
|
update_string_views();
|
||||||
return *this;
|
return *this;
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "spdlog/details/log_msg.h"
|
#include <spdlog/details/log_msg.h>
|
||||||
|
|
||||||
namespace spdlog {
|
namespace spdlog {
|
||||||
namespace details {
|
namespace details {
|
||||||
@ -20,9 +20,9 @@ public:
|
|||||||
log_msg_buffer() = default;
|
log_msg_buffer() = default;
|
||||||
explicit log_msg_buffer(const log_msg &orig_msg);
|
explicit log_msg_buffer(const log_msg &orig_msg);
|
||||||
log_msg_buffer(const log_msg_buffer &other);
|
log_msg_buffer(const log_msg_buffer &other);
|
||||||
log_msg_buffer(log_msg_buffer &&other);
|
log_msg_buffer(log_msg_buffer &&other) SPDLOG_NOEXCEPT;
|
||||||
log_msg_buffer &operator=(const log_msg_buffer &other);
|
log_msg_buffer &operator=(const log_msg_buffer &other);
|
||||||
log_msg_buffer &operator=(log_msg_buffer &&other);
|
log_msg_buffer &operator=(log_msg_buffer &&other) SPDLOG_NOEXCEPT;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace details
|
} // namespace details
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
// dequeue_for(..) - will block until the queue is not empty or timeout have
|
// dequeue_for(..) - will block until the queue is not empty or timeout have
|
||||||
// passed.
|
// passed.
|
||||||
|
|
||||||
#include "spdlog/details/circular_q.h"
|
#include <spdlog/details/circular_q.h>
|
||||||
|
|
||||||
#include <condition_variable>
|
#include <condition_variable>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
158
third_party/spdlog/include/spdlog/details/os-inl.h
vendored
158
third_party/spdlog/include/spdlog/details/os-inl.h
vendored
@ -4,10 +4,10 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#ifndef SPDLOG_HEADER_ONLY
|
#ifndef SPDLOG_HEADER_ONLY
|
||||||
#include "spdlog/details/os.h"
|
#include <spdlog/details/os.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "spdlog/common.h"
|
#include <spdlog/common.h>
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
@ -42,6 +42,8 @@
|
|||||||
#include <limits>
|
#include <limits>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <direct.h> // for _mkdir/_wmkdir
|
||||||
|
|
||||||
#else // unix
|
#else // unix
|
||||||
|
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
@ -91,17 +93,17 @@ SPDLOG_INLINE std::tm localtime(const std::time_t &time_tt) SPDLOG_NOEXCEPT
|
|||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
std::tm tm;
|
std::tm tm;
|
||||||
localtime_s(&tm, &time_tt);
|
::localtime_s(&tm, &time_tt);
|
||||||
#else
|
#else
|
||||||
std::tm tm;
|
std::tm tm;
|
||||||
localtime_r(&time_tt, &tm);
|
::localtime_r(&time_tt, &tm);
|
||||||
#endif
|
#endif
|
||||||
return tm;
|
return tm;
|
||||||
}
|
}
|
||||||
|
|
||||||
SPDLOG_INLINE std::tm localtime() SPDLOG_NOEXCEPT
|
SPDLOG_INLINE std::tm localtime() SPDLOG_NOEXCEPT
|
||||||
{
|
{
|
||||||
std::time_t now_t = time(nullptr);
|
std::time_t now_t = ::time(nullptr);
|
||||||
return localtime(now_t);
|
return localtime(now_t);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -110,52 +112,52 @@ SPDLOG_INLINE std::tm gmtime(const std::time_t &time_tt) SPDLOG_NOEXCEPT
|
|||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
std::tm tm;
|
std::tm tm;
|
||||||
gmtime_s(&tm, &time_tt);
|
::gmtime_s(&tm, &time_tt);
|
||||||
#else
|
#else
|
||||||
std::tm tm;
|
std::tm tm;
|
||||||
gmtime_r(&time_tt, &tm);
|
::gmtime_r(&time_tt, &tm);
|
||||||
#endif
|
#endif
|
||||||
return tm;
|
return tm;
|
||||||
}
|
}
|
||||||
|
|
||||||
SPDLOG_INLINE std::tm gmtime() SPDLOG_NOEXCEPT
|
SPDLOG_INLINE std::tm gmtime() SPDLOG_NOEXCEPT
|
||||||
{
|
{
|
||||||
std::time_t now_t = time(nullptr);
|
std::time_t now_t = ::time(nullptr);
|
||||||
return gmtime(now_t);
|
return gmtime(now_t);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef SPDLOG_PREVENT_CHILD_FD
|
||||||
SPDLOG_INLINE void prevent_child_fd(FILE *f)
|
SPDLOG_INLINE void prevent_child_fd(FILE *f)
|
||||||
{
|
{
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#if !defined(__cplusplus_winrt)
|
auto file_handle = reinterpret_cast<HANDLE>(_get_osfhandle(::_fileno(f)));
|
||||||
auto file_handle = reinterpret_cast<HANDLE>(_get_osfhandle(_fileno(f)));
|
|
||||||
if (!::SetHandleInformation(file_handle, HANDLE_FLAG_INHERIT, 0))
|
if (!::SetHandleInformation(file_handle, HANDLE_FLAG_INHERIT, 0))
|
||||||
SPDLOG_THROW(spdlog_ex("SetHandleInformation failed", errno));
|
SPDLOG_THROW(spdlog_ex("SetHandleInformation failed", errno));
|
||||||
#endif
|
|
||||||
#else
|
#else
|
||||||
auto fd = fileno(f);
|
auto fd = ::fileno(f);
|
||||||
if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1)
|
if (::fcntl(fd, F_SETFD, FD_CLOEXEC) == -1)
|
||||||
{
|
{
|
||||||
SPDLOG_THROW(spdlog_ex("fcntl with FD_CLOEXEC failed", errno));
|
SPDLOG_THROW(spdlog_ex("fcntl with FD_CLOEXEC failed", errno));
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
#endif // SPDLOG_PREVENT_CHILD_FD
|
||||||
|
|
||||||
// fopen_s on non windows for writing
|
// fopen_s on non windows for writing
|
||||||
SPDLOG_INLINE bool fopen_s(FILE **fp, const filename_t &filename, const filename_t &mode)
|
SPDLOG_INLINE bool fopen_s(FILE **fp, const filename_t &filename, const filename_t &mode)
|
||||||
{
|
{
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#ifdef SPDLOG_WCHAR_FILENAMES
|
#ifdef SPDLOG_WCHAR_FILENAMES
|
||||||
*fp = _wfsopen((filename.c_str()), mode.c_str(), _SH_DENYNO);
|
*fp = ::_wfsopen((filename.c_str()), mode.c_str(), _SH_DENYNO);
|
||||||
#else
|
#else
|
||||||
*fp = _fsopen((filename.c_str()), mode.c_str(), _SH_DENYNO);
|
*fp = ::_fsopen((filename.c_str()), mode.c_str(), _SH_DENYNO);
|
||||||
#endif
|
#endif
|
||||||
#else // unix
|
#else // unix
|
||||||
*fp = fopen((filename.c_str()), mode.c_str());
|
*fp = ::fopen((filename.c_str()), mode.c_str());
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef SPDLOG_PREVENT_CHILD_FD
|
#ifdef SPDLOG_PREVENT_CHILD_FD
|
||||||
|
// prevent child processes from inheriting log file descriptors
|
||||||
if (*fp != nullptr)
|
if (*fp != nullptr)
|
||||||
{
|
{
|
||||||
prevent_child_fd(*fp);
|
prevent_child_fd(*fp);
|
||||||
@ -167,7 +169,7 @@ SPDLOG_INLINE bool fopen_s(FILE **fp, const filename_t &filename, const filename
|
|||||||
SPDLOG_INLINE int remove(const filename_t &filename) SPDLOG_NOEXCEPT
|
SPDLOG_INLINE int remove(const filename_t &filename) SPDLOG_NOEXCEPT
|
||||||
{
|
{
|
||||||
#if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES)
|
#if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES)
|
||||||
return _wremove(filename.c_str());
|
return ::_wremove(filename.c_str());
|
||||||
#else
|
#else
|
||||||
return std::remove(filename.c_str());
|
return std::remove(filename.c_str());
|
||||||
#endif
|
#endif
|
||||||
@ -175,28 +177,28 @@ SPDLOG_INLINE int remove(const filename_t &filename) SPDLOG_NOEXCEPT
|
|||||||
|
|
||||||
SPDLOG_INLINE int remove_if_exists(const filename_t &filename) SPDLOG_NOEXCEPT
|
SPDLOG_INLINE int remove_if_exists(const filename_t &filename) SPDLOG_NOEXCEPT
|
||||||
{
|
{
|
||||||
return file_exists(filename) ? remove(filename) : 0;
|
return path_exists(filename) ? remove(filename) : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
SPDLOG_INLINE int rename(const filename_t &filename1, const filename_t &filename2) SPDLOG_NOEXCEPT
|
SPDLOG_INLINE int rename(const filename_t &filename1, const filename_t &filename2) SPDLOG_NOEXCEPT
|
||||||
{
|
{
|
||||||
#if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES)
|
#if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES)
|
||||||
return _wrename(filename1.c_str(), filename2.c_str());
|
return ::_wrename(filename1.c_str(), filename2.c_str());
|
||||||
#else
|
#else
|
||||||
return std::rename(filename1.c_str(), filename2.c_str());
|
return std::rename(filename1.c_str(), filename2.c_str());
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return true if file exists
|
// Return true if path exists (file or directory)
|
||||||
SPDLOG_INLINE bool file_exists(const filename_t &filename) SPDLOG_NOEXCEPT
|
SPDLOG_INLINE bool path_exists(const filename_t &filename) SPDLOG_NOEXCEPT
|
||||||
{
|
{
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#ifdef SPDLOG_WCHAR_FILENAMES
|
#ifdef SPDLOG_WCHAR_FILENAMES
|
||||||
auto attribs = GetFileAttributesW(filename.c_str());
|
auto attribs = ::GetFileAttributesW(filename.c_str());
|
||||||
#else
|
#else
|
||||||
auto attribs = GetFileAttributesA(filename.c_str());
|
auto attribs = ::GetFileAttributesA(filename.c_str());
|
||||||
#endif
|
#endif
|
||||||
return (attribs != INVALID_FILE_ATTRIBUTES && !(attribs & FILE_ATTRIBUTE_DIRECTORY));
|
return attribs != INVALID_FILE_ATTRIBUTES;
|
||||||
#else // common linux/unix all have the stat system call
|
#else // common linux/unix all have the stat system call
|
||||||
struct stat buffer;
|
struct stat buffer;
|
||||||
return (::stat(filename.c_str(), &buffer) == 0);
|
return (::stat(filename.c_str(), &buffer) == 0);
|
||||||
@ -211,16 +213,16 @@ SPDLOG_INLINE size_t filesize(FILE *f)
|
|||||||
SPDLOG_THROW(spdlog_ex("Failed getting file size. fd is null"));
|
SPDLOG_THROW(spdlog_ex("Failed getting file size. fd is null"));
|
||||||
}
|
}
|
||||||
#if defined(_WIN32) && !defined(__CYGWIN__)
|
#if defined(_WIN32) && !defined(__CYGWIN__)
|
||||||
int fd = _fileno(f);
|
int fd = ::_fileno(f);
|
||||||
#if _WIN64 // 64 bits
|
#if _WIN64 // 64 bits
|
||||||
__int64 ret = _filelengthi64(fd);
|
__int64 ret = ::_filelengthi64(fd);
|
||||||
if (ret >= 0)
|
if (ret >= 0)
|
||||||
{
|
{
|
||||||
return static_cast<size_t>(ret);
|
return static_cast<size_t>(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
#else // windows 32 bits
|
#else // windows 32 bits
|
||||||
long ret = _filelength(fd);
|
long ret = ::_filelength(fd);
|
||||||
if (ret >= 0)
|
if (ret >= 0)
|
||||||
{
|
{
|
||||||
return static_cast<size_t>(ret);
|
return static_cast<size_t>(ret);
|
||||||
@ -228,7 +230,12 @@ SPDLOG_INLINE size_t filesize(FILE *f)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#else // unix
|
#else // unix
|
||||||
|
// OpenBSD doesn't compile with :: before the fileno(..)
|
||||||
|
#if defined(__OpenBSD__)
|
||||||
int fd = fileno(f);
|
int fd = fileno(f);
|
||||||
|
#else
|
||||||
|
int fd = ::fileno(f);
|
||||||
|
#endif
|
||||||
// 64 bits(but not in osx or cygwin, where fstat64 is deprecated)
|
// 64 bits(but not in osx or cygwin, where fstat64 is deprecated)
|
||||||
#if (defined(__linux__) || defined(__sun) || defined(_AIX)) && (defined(__LP64__) || defined(_LP64))
|
#if (defined(__linux__) || defined(__sun) || defined(_AIX)) && (defined(__LP64__) || defined(_LP64))
|
||||||
struct stat64 st;
|
struct stat64 st;
|
||||||
@ -236,9 +243,8 @@ SPDLOG_INLINE size_t filesize(FILE *f)
|
|||||||
{
|
{
|
||||||
return static_cast<size_t>(st.st_size);
|
return static_cast<size_t>(st.st_size);
|
||||||
}
|
}
|
||||||
#else // unix 32 bits or cygwin
|
#else // other unix or linux 32 bits or cygwin
|
||||||
struct stat st;
|
struct stat st;
|
||||||
|
|
||||||
if (::fstat(fd, &st) == 0)
|
if (::fstat(fd, &st) == 0)
|
||||||
{
|
{
|
||||||
return static_cast<size_t>(st.st_size);
|
return static_cast<size_t>(st.st_size);
|
||||||
@ -255,10 +261,10 @@ SPDLOG_INLINE int utc_minutes_offset(const std::tm &tm)
|
|||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#if _WIN32_WINNT < _WIN32_WINNT_WS08
|
#if _WIN32_WINNT < _WIN32_WINNT_WS08
|
||||||
TIME_ZONE_INFORMATION tzinfo;
|
TIME_ZONE_INFORMATION tzinfo;
|
||||||
auto rv = GetTimeZoneInformation(&tzinfo);
|
auto rv = ::GetTimeZoneInformation(&tzinfo);
|
||||||
#else
|
#else
|
||||||
DYNAMIC_TIME_ZONE_INFORMATION tzinfo;
|
DYNAMIC_TIME_ZONE_INFORMATION tzinfo;
|
||||||
auto rv = GetDynamicTimeZoneInformation(&tzinfo);
|
auto rv = ::GetDynamicTimeZoneInformation(&tzinfo);
|
||||||
#endif
|
#endif
|
||||||
if (rv == TIME_ZONE_ID_INVALID)
|
if (rv == TIME_ZONE_ID_INVALID)
|
||||||
SPDLOG_THROW(spdlog::spdlog_ex("Failed getting timezone info. ", errno));
|
SPDLOG_THROW(spdlog::spdlog_ex("Failed getting timezone info. ", errno));
|
||||||
@ -275,7 +281,7 @@ SPDLOG_INLINE int utc_minutes_offset(const std::tm &tm)
|
|||||||
return offset;
|
return offset;
|
||||||
#else
|
#else
|
||||||
|
|
||||||
#if defined(sun) || defined(__sun) || defined(_AIX)
|
#if defined(sun) || defined(__sun) || defined(_AIX) || (!defined(_BSD_SOURCE) && !defined(_GNU_SOURCE))
|
||||||
// 'tm_gmtoff' field is BSD extension and it's missing on SunOS/Solaris
|
// 'tm_gmtoff' field is BSD extension and it's missing on SunOS/Solaris
|
||||||
struct helper
|
struct helper
|
||||||
{
|
{
|
||||||
@ -324,15 +330,15 @@ SPDLOG_INLINE size_t _thread_id() SPDLOG_NOEXCEPT
|
|||||||
#if defined(__ANDROID__) && defined(__ANDROID_API__) && (__ANDROID_API__ < 21)
|
#if defined(__ANDROID__) && defined(__ANDROID_API__) && (__ANDROID_API__ < 21)
|
||||||
#define SYS_gettid __NR_gettid
|
#define SYS_gettid __NR_gettid
|
||||||
#endif
|
#endif
|
||||||
return static_cast<size_t>(syscall(SYS_gettid));
|
return static_cast<size_t>(::syscall(SYS_gettid));
|
||||||
#elif defined(_AIX) || defined(__DragonFly__) || defined(__FreeBSD__)
|
#elif defined(_AIX) || defined(__DragonFly__) || defined(__FreeBSD__)
|
||||||
return static_cast<size_t>(pthread_getthreadid_np());
|
return static_cast<size_t>(::pthread_getthreadid_np());
|
||||||
#elif defined(__NetBSD__)
|
#elif defined(__NetBSD__)
|
||||||
return static_cast<size_t>(_lwp_self());
|
return static_cast<size_t>(::_lwp_self());
|
||||||
#elif defined(__OpenBSD__)
|
#elif defined(__OpenBSD__)
|
||||||
return static_cast<size_t>(getthrid());
|
return static_cast<size_t>(::getthrid());
|
||||||
#elif defined(__sun)
|
#elif defined(__sun)
|
||||||
return static_cast<size_t>(thr_self());
|
return static_cast<size_t>(::thr_self());
|
||||||
#elif __APPLE__
|
#elif __APPLE__
|
||||||
uint64_t tid;
|
uint64_t tid;
|
||||||
pthread_threadid_np(nullptr, &tid);
|
pthread_threadid_np(nullptr, &tid);
|
||||||
@ -417,16 +423,16 @@ SPDLOG_INLINE bool in_terminal(FILE *file) SPDLOG_NOEXCEPT
|
|||||||
{
|
{
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
return _isatty(_fileno(file)) != 0;
|
return ::_isatty(_fileno(file)) != 0;
|
||||||
#else
|
#else
|
||||||
return isatty(fileno(file)) != 0;
|
return ::isatty(fileno(file)) != 0;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#if (defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) || defined(SPDLOG_WCHAR_FILENAMES)) && defined(_WIN32)
|
#if (defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) || defined(SPDLOG_WCHAR_FILENAMES)) && defined(_WIN32)
|
||||||
SPDLOG_INLINE void wstr_to_utf8buf(wstring_view_t wstr, memory_buf_t &target)
|
SPDLOG_INLINE void wstr_to_utf8buf(wstring_view_t wstr, memory_buf_t &target)
|
||||||
{
|
{
|
||||||
if (wstr.size() > static_cast<size_t>(std::numeric_limits<int>::max()))
|
if (wstr.size() > static_cast<size_t>((std::numeric_limits<int>::max)()))
|
||||||
{
|
{
|
||||||
SPDLOG_THROW(spdlog::spdlog_ex("UTF-16 string is too big to be converted to UTF-8"));
|
SPDLOG_THROW(spdlog::spdlog_ex("UTF-16 string is too big to be converted to UTF-8"));
|
||||||
}
|
}
|
||||||
@ -460,6 +466,76 @@ SPDLOG_INLINE void wstr_to_utf8buf(wstring_view_t wstr, memory_buf_t &target)
|
|||||||
}
|
}
|
||||||
#endif // (defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) || defined(SPDLOG_WCHAR_FILENAMES)) && defined(_WIN32)
|
#endif // (defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) || defined(SPDLOG_WCHAR_FILENAMES)) && defined(_WIN32)
|
||||||
|
|
||||||
|
// return true on success
|
||||||
|
static SPDLOG_INLINE bool mkdir_(const filename_t &path)
|
||||||
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
|
#ifdef SPDLOG_WCHAR_FILENAMES
|
||||||
|
return ::_wmkdir(path.c_str()) == 0;
|
||||||
|
#else
|
||||||
|
return ::_mkdir(path.c_str()) == 0;
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
return ::mkdir(path.c_str(), mode_t(0755)) == 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// create the given directory - and all directories leading to it
|
||||||
|
// return true on success or if the directory already exists
|
||||||
|
SPDLOG_INLINE bool create_dir(filename_t path)
|
||||||
|
{
|
||||||
|
if (path_exists(path))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (path.empty())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
// support forward slash in windows
|
||||||
|
std::replace(path.begin(), path.end(), '/', folder_sep);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
size_t search_offset = 0;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
auto token_pos = path.find(folder_sep, search_offset);
|
||||||
|
// treat the entire path as a folder if no folder separator not found
|
||||||
|
if (token_pos == filename_t::npos)
|
||||||
|
{
|
||||||
|
token_pos = path.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto subdir = path.substr(0, token_pos);
|
||||||
|
|
||||||
|
if (!subdir.empty() && !path_exists(subdir) && !mkdir_(subdir))
|
||||||
|
{
|
||||||
|
return false; // return error if failed creating dir
|
||||||
|
}
|
||||||
|
search_offset = token_pos + 1;
|
||||||
|
} while (search_offset < path.size());
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return directory name from given path or empty string
|
||||||
|
// "abc/file" => "abc"
|
||||||
|
// "abc/" => "abc"
|
||||||
|
// "abc" => ""
|
||||||
|
// "abc///" => "abc//"
|
||||||
|
SPDLOG_INLINE filename_t dir_name(filename_t path)
|
||||||
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
|
// support forward slash in windows
|
||||||
|
std::replace(path.begin(), path.end(), '/', folder_sep);
|
||||||
|
#endif
|
||||||
|
auto pos = path.find_last_of(folder_sep);
|
||||||
|
return pos != filename_t::npos ? path.substr(0, pos) : filename_t{};
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace os
|
} // namespace os
|
||||||
} // namespace details
|
} // namespace details
|
||||||
} // namespace spdlog
|
} // namespace spdlog
|
||||||
|
21
third_party/spdlog/include/spdlog/details/os.h
vendored
21
third_party/spdlog/include/spdlog/details/os.h
vendored
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "spdlog/common.h"
|
#include <spdlog/common.h>
|
||||||
#include <ctime> // std::time_t
|
#include <ctime> // std::time_t
|
||||||
|
|
||||||
namespace spdlog {
|
namespace spdlog {
|
||||||
@ -33,12 +33,14 @@ SPDLOG_CONSTEXPR static const char *default_eol = SPDLOG_EOL;
|
|||||||
|
|
||||||
// folder separator
|
// folder separator
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
const char folder_sep = '\\';
|
static const char folder_sep = '\\';
|
||||||
#else
|
#else
|
||||||
SPDLOG_CONSTEXPR static const char folder_sep = '/';
|
SPDLOG_CONSTEXPR static const char folder_sep = '/';
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef SPDLOG_PREVENT_CHILD_FD
|
||||||
void prevent_child_fd(FILE *f);
|
void prevent_child_fd(FILE *f);
|
||||||
|
#endif
|
||||||
|
|
||||||
// fopen_s on non windows for writing
|
// fopen_s on non windows for writing
|
||||||
bool fopen_s(FILE **fp, const filename_t &filename, const filename_t &mode);
|
bool fopen_s(FILE **fp, const filename_t &filename, const filename_t &mode);
|
||||||
@ -53,7 +55,7 @@ int remove_if_exists(const filename_t &filename) SPDLOG_NOEXCEPT;
|
|||||||
int rename(const filename_t &filename1, const filename_t &filename2) SPDLOG_NOEXCEPT;
|
int rename(const filename_t &filename1, const filename_t &filename2) SPDLOG_NOEXCEPT;
|
||||||
|
|
||||||
// Return if file exists.
|
// Return if file exists.
|
||||||
bool file_exists(const filename_t &filename) SPDLOG_NOEXCEPT;
|
bool path_exists(const filename_t &filename) SPDLOG_NOEXCEPT;
|
||||||
|
|
||||||
// Return file size according to open FILE* object
|
// Return file size according to open FILE* object
|
||||||
size_t filesize(FILE *f);
|
size_t filesize(FILE *f);
|
||||||
@ -81,7 +83,7 @@ int pid() SPDLOG_NOEXCEPT;
|
|||||||
// Source: https://github.com/agauniyal/rang/
|
// Source: https://github.com/agauniyal/rang/
|
||||||
bool is_color_terminal() SPDLOG_NOEXCEPT;
|
bool is_color_terminal() SPDLOG_NOEXCEPT;
|
||||||
|
|
||||||
// Detrmine if the terminal attached
|
// Determine if the terminal attached
|
||||||
// Source: https://github.com/agauniyal/rang/
|
// Source: https://github.com/agauniyal/rang/
|
||||||
bool in_terminal(FILE *file) SPDLOG_NOEXCEPT;
|
bool in_terminal(FILE *file) SPDLOG_NOEXCEPT;
|
||||||
|
|
||||||
@ -89,6 +91,17 @@ bool in_terminal(FILE *file) SPDLOG_NOEXCEPT;
|
|||||||
void wstr_to_utf8buf(wstring_view_t wstr, memory_buf_t &target);
|
void wstr_to_utf8buf(wstring_view_t wstr, memory_buf_t &target);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Return directory name from given path or empty string
|
||||||
|
// "abc/file" => "abc"
|
||||||
|
// "abc/" => "abc"
|
||||||
|
// "abc" => ""
|
||||||
|
// "abc///" => "abc//"
|
||||||
|
filename_t dir_name(filename_t path);
|
||||||
|
|
||||||
|
// Create a dir from the given path.
|
||||||
|
// Return true if succeeded or if this dir already exists.
|
||||||
|
bool create_dir(filename_t path);
|
||||||
|
|
||||||
} // namespace os
|
} // namespace os
|
||||||
} // namespace details
|
} // namespace details
|
||||||
} // namespace spdlog
|
} // namespace spdlog
|
||||||
|
@ -4,14 +4,14 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#ifndef SPDLOG_HEADER_ONLY
|
#ifndef SPDLOG_HEADER_ONLY
|
||||||
#include "spdlog/details/pattern_formatter.h"
|
#include <spdlog/details/pattern_formatter.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "spdlog/details/fmt_helper.h"
|
#include <spdlog/details/fmt_helper.h>
|
||||||
#include "spdlog/details/log_msg.h"
|
#include <spdlog/details/log_msg.h>
|
||||||
#include "spdlog/details/os.h"
|
#include <spdlog/details/os.h>
|
||||||
#include "spdlog/fmt/fmt.h"
|
#include <spdlog/fmt/fmt.h>
|
||||||
#include "spdlog/formatter.h"
|
#include <spdlog/formatter.h>
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
@ -39,47 +39,48 @@ public:
|
|||||||
: padinfo_(padinfo)
|
: padinfo_(padinfo)
|
||||||
, dest_(dest)
|
, dest_(dest)
|
||||||
{
|
{
|
||||||
|
remaining_pad_ = static_cast<long>(padinfo.width_) - static_cast<long>(wrapped_size);
|
||||||
if (padinfo_.width_ <= wrapped_size)
|
if (remaining_pad_ <= 0)
|
||||||
{
|
{
|
||||||
total_pad_ = 0;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
total_pad_ = padinfo.width_ - wrapped_size;
|
|
||||||
if (padinfo_.side_ == padding_info::left)
|
if (padinfo_.side_ == padding_info::left)
|
||||||
{
|
{
|
||||||
pad_it(total_pad_);
|
pad_it(remaining_pad_);
|
||||||
total_pad_ = 0;
|
remaining_pad_ = 0;
|
||||||
}
|
}
|
||||||
else if (padinfo_.side_ == padding_info::center)
|
else if (padinfo_.side_ == padding_info::center)
|
||||||
{
|
{
|
||||||
auto half_pad = total_pad_ / 2;
|
auto half_pad = remaining_pad_ / 2;
|
||||||
auto reminder = total_pad_ & 1;
|
auto reminder = remaining_pad_ & 1;
|
||||||
pad_it(half_pad);
|
pad_it(half_pad);
|
||||||
total_pad_ = half_pad + reminder; // for the right side
|
remaining_pad_ = half_pad + reminder; // for the right side
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
~scoped_padder()
|
~scoped_padder()
|
||||||
{
|
{
|
||||||
if (total_pad_)
|
if (remaining_pad_ >= 0)
|
||||||
{
|
{
|
||||||
pad_it(total_pad_);
|
pad_it(remaining_pad_);
|
||||||
|
}
|
||||||
|
else if (padinfo_.truncate_)
|
||||||
|
{
|
||||||
|
long new_size = static_cast<long>(dest_.size()) + remaining_pad_;
|
||||||
|
dest_.resize(static_cast<size_t>(new_size));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void pad_it(size_t count)
|
void pad_it(long count)
|
||||||
{
|
{
|
||||||
// count = std::min(count, spaces_.size());
|
fmt_helper::append_string_view(string_view_t(spaces_.data(), static_cast<size_t>(count)), dest_);
|
||||||
assert(count <= spaces_.size());
|
|
||||||
fmt_helper::append_string_view(string_view_t(spaces_.data(), count), dest_);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const padding_info &padinfo_;
|
const padding_info &padinfo_;
|
||||||
memory_buf_t &dest_;
|
memory_buf_t &dest_;
|
||||||
size_t total_pad_;
|
long remaining_pad_;
|
||||||
string_view_t spaces_{" ", 64};
|
string_view_t spaces_{" ", 64};
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -593,14 +594,7 @@ public:
|
|||||||
const size_t field_size = 6;
|
const size_t field_size = 6;
|
||||||
ScopedPadder p(field_size, padinfo_, dest);
|
ScopedPadder p(field_size, padinfo_, dest);
|
||||||
|
|
||||||
#ifdef _WIN32
|
auto total_minutes = get_cached_offset(msg, tm_time);
|
||||||
int total_minutes = get_cached_offset(msg, tm_time);
|
|
||||||
#else
|
|
||||||
// No need to chache under gcc,
|
|
||||||
// it is very fast (already stored in tm.tm_gmtoff)
|
|
||||||
(void)(msg);
|
|
||||||
int total_minutes = os::utc_minutes_offset(tm_time);
|
|
||||||
#endif
|
|
||||||
bool is_negative = total_minutes < 0;
|
bool is_negative = total_minutes < 0;
|
||||||
if (is_negative)
|
if (is_negative)
|
||||||
{
|
{
|
||||||
@ -619,7 +613,6 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
log_clock::time_point last_update_{std::chrono::seconds(0)};
|
log_clock::time_point last_update_{std::chrono::seconds(0)};
|
||||||
#ifdef _WIN32
|
|
||||||
int offset_minutes_{0};
|
int offset_minutes_{0};
|
||||||
|
|
||||||
int get_cached_offset(const log_msg &msg, const std::tm &tm_time)
|
int get_cached_offset(const log_msg &msg, const std::tm &tm_time)
|
||||||
@ -632,7 +625,6 @@ private:
|
|||||||
}
|
}
|
||||||
return offset_minutes_;
|
return offset_minutes_;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Thread id
|
// Thread id
|
||||||
@ -881,11 +873,13 @@ public:
|
|||||||
auto delta = (std::max)(msg.time - last_message_time_, log_clock::duration::zero());
|
auto delta = (std::max)(msg.time - last_message_time_, log_clock::duration::zero());
|
||||||
auto delta_units = std::chrono::duration_cast<DurationUnits>(delta);
|
auto delta_units = std::chrono::duration_cast<DurationUnits>(delta);
|
||||||
last_message_time_ = msg.time;
|
last_message_time_ = msg.time;
|
||||||
ScopedPadder p(6, padinfo_, dest);
|
auto delta_count = static_cast<size_t>(delta_units.count());
|
||||||
fmt_helper::pad6(static_cast<size_t>(delta_units.count()), dest);
|
auto n_digits = static_cast<size_t>(fmt_helper::count_digits(delta_count));
|
||||||
|
ScopedPadder p(n_digits, padinfo_, dest);
|
||||||
|
fmt_helper::append_int(delta_count, dest);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
private:
|
||||||
log_clock::time_point last_message_time_;
|
log_clock::time_point last_message_time_;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -904,8 +898,6 @@ public:
|
|||||||
using std::chrono::milliseconds;
|
using std::chrono::milliseconds;
|
||||||
using std::chrono::seconds;
|
using std::chrono::seconds;
|
||||||
|
|
||||||
#ifndef SPDLOG_NO_DATETIME
|
|
||||||
|
|
||||||
// cache the date/time part for the next second.
|
// cache the date/time part for the next second.
|
||||||
auto duration = msg.time.time_since_epoch();
|
auto duration = msg.time.time_since_epoch();
|
||||||
auto secs = duration_cast<seconds>(duration);
|
auto secs = duration_cast<seconds>(duration);
|
||||||
@ -941,10 +933,6 @@ public:
|
|||||||
dest.push_back(']');
|
dest.push_back(']');
|
||||||
dest.push_back(' ');
|
dest.push_back(' ');
|
||||||
|
|
||||||
#else // no datetime needed
|
|
||||||
(void)tm_time;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef SPDLOG_NO_NAME
|
#ifndef SPDLOG_NO_NAME
|
||||||
if (msg.logger_name.size() > 0)
|
if (msg.logger_name.size() > 0)
|
||||||
{
|
{
|
||||||
@ -1014,14 +1002,13 @@ SPDLOG_INLINE std::unique_ptr<formatter> pattern_formatter::clone() const
|
|||||||
|
|
||||||
SPDLOG_INLINE void pattern_formatter::format(const details::log_msg &msg, memory_buf_t &dest)
|
SPDLOG_INLINE void pattern_formatter::format(const details::log_msg &msg, memory_buf_t &dest)
|
||||||
{
|
{
|
||||||
#ifndef SPDLOG_NO_DATETIME
|
|
||||||
auto secs = std::chrono::duration_cast<std::chrono::seconds>(msg.time.time_since_epoch());
|
auto secs = std::chrono::duration_cast<std::chrono::seconds>(msg.time.time_since_epoch());
|
||||||
if (secs != last_log_secs_)
|
if (secs != last_log_secs_)
|
||||||
{
|
{
|
||||||
cached_tm_ = get_time_(msg);
|
cached_tm_ = get_time_(msg);
|
||||||
last_log_secs_ = secs;
|
last_log_secs_ = secs;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
for (auto &f : formatters_)
|
for (auto &f : formatters_)
|
||||||
{
|
{
|
||||||
f->format(msg, cached_tm_, dest);
|
f->format(msg, cached_tm_, dest);
|
||||||
@ -1225,7 +1212,7 @@ SPDLOG_INLINE void pattern_formatter::handle_flag_(char flag, details::padding_i
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract given pad spec (e.g. %8X)
|
// Extract given pad spec (e.g. %8X, %=8X, %-8!X, %8!X, %=8!X, %-8!X, %+8!X)
|
||||||
// Advance the given it pass the end of the padding spec found (if any)
|
// Advance the given it pass the end of the padding spec found (if any)
|
||||||
// Return padding.
|
// Return padding.
|
||||||
SPDLOG_INLINE details::padding_info pattern_formatter::handle_padspec_(std::string::const_iterator &it, std::string::const_iterator end)
|
SPDLOG_INLINE details::padding_info pattern_formatter::handle_padspec_(std::string::const_iterator &it, std::string::const_iterator end)
|
||||||
@ -1256,7 +1243,7 @@ SPDLOG_INLINE details::padding_info pattern_formatter::handle_padspec_(std::stri
|
|||||||
|
|
||||||
if (it == end || !std::isdigit(static_cast<unsigned char>(*it)))
|
if (it == end || !std::isdigit(static_cast<unsigned char>(*it)))
|
||||||
{
|
{
|
||||||
return padding_info{0, side};
|
return padding_info{}; // no padding if no digit found here
|
||||||
}
|
}
|
||||||
|
|
||||||
auto width = static_cast<size_t>(*it) - '0';
|
auto width = static_cast<size_t>(*it) - '0';
|
||||||
@ -1265,7 +1252,20 @@ SPDLOG_INLINE details::padding_info pattern_formatter::handle_padspec_(std::stri
|
|||||||
auto digit = static_cast<size_t>(*it) - '0';
|
auto digit = static_cast<size_t>(*it) - '0';
|
||||||
width = width * 10 + digit;
|
width = width * 10 + digit;
|
||||||
}
|
}
|
||||||
return details::padding_info{std::min<size_t>(width, max_width), side};
|
|
||||||
|
// search for the optional truncate marker '!'
|
||||||
|
bool truncate;
|
||||||
|
if (it != end && *it == '!')
|
||||||
|
{
|
||||||
|
truncate = true;
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
truncate = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return details::padding_info{std::min<size_t>(width, max_width), side, truncate};
|
||||||
}
|
}
|
||||||
|
|
||||||
SPDLOG_INLINE void pattern_formatter::compile_pattern_(const std::string &pattern)
|
SPDLOG_INLINE void pattern_formatter::compile_pattern_(const std::string &pattern)
|
||||||
|
@ -3,10 +3,10 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "spdlog/common.h"
|
#include <spdlog/common.h>
|
||||||
#include "spdlog/details/log_msg.h"
|
#include <spdlog/details/log_msg.h>
|
||||||
#include "spdlog/details/os.h"
|
#include <spdlog/details/os.h>
|
||||||
#include "spdlog/formatter.h"
|
#include <spdlog/formatter.h>
|
||||||
|
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <ctime>
|
#include <ctime>
|
||||||
@ -29,17 +29,21 @@ struct padding_info
|
|||||||
};
|
};
|
||||||
|
|
||||||
padding_info() = default;
|
padding_info() = default;
|
||||||
padding_info(size_t width, padding_info::pad_side side)
|
padding_info(size_t width, padding_info::pad_side side, bool truncate)
|
||||||
: width_(width)
|
: width_(width)
|
||||||
, side_(side)
|
, side_(side)
|
||||||
|
, truncate_(truncate)
|
||||||
|
, enabled_(true)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
bool enabled() const
|
bool enabled() const
|
||||||
{
|
{
|
||||||
return width_ != 0;
|
return enabled_;
|
||||||
}
|
}
|
||||||
const size_t width_ = 0;
|
const size_t width_ = 0;
|
||||||
const pad_side side_ = left;
|
const pad_side side_ = left;
|
||||||
|
bool truncate_ = false;
|
||||||
|
bool enabled_ = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
class flag_formatter
|
class flag_formatter
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#ifndef SPDLOG_HEADER_ONLY
|
#ifndef SPDLOG_HEADER_ONLY
|
||||||
#include "spdlog/details/periodic_worker.h"
|
#include <spdlog/details/periodic_worker.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace spdlog {
|
namespace spdlog {
|
||||||
|
@ -4,20 +4,20 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#ifndef SPDLOG_HEADER_ONLY
|
#ifndef SPDLOG_HEADER_ONLY
|
||||||
#include "spdlog/details/registry.h"
|
#include <spdlog/details/registry.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "spdlog/common.h"
|
#include <spdlog/common.h>
|
||||||
#include "spdlog/details/periodic_worker.h"
|
#include <spdlog/details/periodic_worker.h>
|
||||||
#include "spdlog/logger.h"
|
#include <spdlog/logger.h>
|
||||||
#include "spdlog/details/pattern_formatter.h"
|
#include <spdlog/details/pattern_formatter.h>
|
||||||
|
|
||||||
#ifndef SPDLOG_DISABLE_DEFAULT_LOGGER
|
#ifndef SPDLOG_DISABLE_DEFAULT_LOGGER
|
||||||
// support for the default stdout color logger
|
// support for the default stdout color logger
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#include "spdlog/sinks/wincolor_sink.h"
|
#include <spdlog/sinks/wincolor_sink.h>
|
||||||
#else
|
#else
|
||||||
#include "spdlog/sinks/ansicolor_sink.h"
|
#include <spdlog/sinks/ansicolor_sink.h>
|
||||||
#endif
|
#endif
|
||||||
#endif // SPDLOG_DISABLE_DEFAULT_LOGGER
|
#endif // SPDLOG_DISABLE_DEFAULT_LOGGER
|
||||||
|
|
||||||
@ -254,10 +254,10 @@ SPDLOG_INLINE std::recursive_mutex ®istry::tp_mutex()
|
|||||||
return tp_mutex_;
|
return tp_mutex_;
|
||||||
}
|
}
|
||||||
|
|
||||||
SPDLOG_INLINE void registry::set_automatic_registration(bool automatic_regsistration)
|
SPDLOG_INLINE void registry::set_automatic_registration(bool automatic_registration)
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(logger_map_mutex_);
|
std::lock_guard<std::mutex> lock(logger_map_mutex_);
|
||||||
automatic_registration_ = automatic_regsistration;
|
automatic_registration_ = automatic_registration;
|
||||||
}
|
}
|
||||||
|
|
||||||
SPDLOG_INLINE registry ®istry::instance()
|
SPDLOG_INLINE registry ®istry::instance()
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
// If user requests a non existing logger, nullptr will be returned
|
// If user requests a non existing logger, nullptr will be returned
|
||||||
// This class is thread safe
|
// This class is thread safe
|
||||||
|
|
||||||
#include "spdlog/common.h"
|
#include <spdlog/common.h>
|
||||||
|
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
@ -77,7 +77,7 @@ public:
|
|||||||
|
|
||||||
std::recursive_mutex &tp_mutex();
|
std::recursive_mutex &tp_mutex();
|
||||||
|
|
||||||
void set_automatic_registration(bool automatic_regsistration);
|
void set_automatic_registration(bool automatic_registration);
|
||||||
|
|
||||||
static registry &instance();
|
static registry &instance();
|
||||||
|
|
||||||
|
@ -4,10 +4,11 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#ifndef SPDLOG_HEADER_ONLY
|
#ifndef SPDLOG_HEADER_ONLY
|
||||||
#include "spdlog/details/thread_pool.h"
|
#include <spdlog/details/thread_pool.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "spdlog/common.h"
|
#include <spdlog/common.h>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
namespace spdlog {
|
namespace spdlog {
|
||||||
namespace details {
|
namespace details {
|
||||||
@ -81,7 +82,7 @@ void SPDLOG_INLINE thread_pool::post_async_msg_(async_msg &&new_msg, async_overf
|
|||||||
|
|
||||||
void SPDLOG_INLINE thread_pool::worker_loop_()
|
void SPDLOG_INLINE thread_pool::worker_loop_()
|
||||||
{
|
{
|
||||||
while (process_next_msg_()) {};
|
while (process_next_msg_()) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
// process next message in the queue
|
// process next message in the queue
|
||||||
@ -98,24 +99,20 @@ bool SPDLOG_INLINE thread_pool::process_next_msg_()
|
|||||||
|
|
||||||
switch (incoming_async_msg.msg_type)
|
switch (incoming_async_msg.msg_type)
|
||||||
{
|
{
|
||||||
case async_msg_type::log:
|
case async_msg_type::log: {
|
||||||
{
|
|
||||||
incoming_async_msg.worker_ptr->backend_sink_it_(incoming_async_msg);
|
incoming_async_msg.worker_ptr->backend_sink_it_(incoming_async_msg);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case async_msg_type::flush:
|
case async_msg_type::flush: {
|
||||||
{
|
|
||||||
incoming_async_msg.worker_ptr->backend_flush_();
|
incoming_async_msg.worker_ptr->backend_flush_();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
case async_msg_type::terminate:
|
case async_msg_type::terminate: {
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default: {
|
||||||
{
|
|
||||||
assert(false && "Unexpected async_msg_type");
|
assert(false && "Unexpected async_msg_type");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,9 +3,9 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "spdlog/details/log_msg_buffer.h"
|
#include <spdlog/details/log_msg_buffer.h>
|
||||||
#include "spdlog/details/mpmc_blocking_q.h"
|
#include <spdlog/details/mpmc_blocking_q.h>
|
||||||
#include "spdlog/details/os.h"
|
#include <spdlog/details/os.h>
|
||||||
|
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
@ -27,7 +27,7 @@ enum class async_msg_type
|
|||||||
terminate
|
terminate
|
||||||
};
|
};
|
||||||
|
|
||||||
#include "spdlog/details/log_msg_buffer.h"
|
#include <spdlog/details/log_msg_buffer.h>
|
||||||
// Async msg to move to/from the queue
|
// Async msg to move to/from the queue
|
||||||
// Movable only. should never be copied
|
// Movable only. should never be copied
|
||||||
struct async_msg : log_msg_buffer
|
struct async_msg : log_msg_buffer
|
||||||
|
@ -16,16 +16,291 @@
|
|||||||
#include <locale>
|
#include <locale>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
// enable safe chrono durations, unless explicitly disabled
|
FMT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
|
// Enable safe chrono durations, unless explicitly disabled.
|
||||||
#ifndef FMT_SAFE_DURATION_CAST
|
#ifndef FMT_SAFE_DURATION_CAST
|
||||||
# define FMT_SAFE_DURATION_CAST 1
|
# define FMT_SAFE_DURATION_CAST 1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if FMT_SAFE_DURATION_CAST
|
#if FMT_SAFE_DURATION_CAST
|
||||||
# include "safe-duration-cast.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
FMT_BEGIN_NAMESPACE
|
// For conversion between std::chrono::durations without undefined
|
||||||
|
// behaviour or erroneous results.
|
||||||
|
// This is a stripped down version of duration_cast, for inclusion in fmt.
|
||||||
|
// See https://github.com/pauldreik/safe_duration_cast
|
||||||
|
//
|
||||||
|
// Copyright Paul Dreik 2019
|
||||||
|
namespace safe_duration_cast {
|
||||||
|
|
||||||
|
template <typename To, typename From,
|
||||||
|
FMT_ENABLE_IF(!std::is_same<From, To>::value &&
|
||||||
|
std::numeric_limits<From>::is_signed ==
|
||||||
|
std::numeric_limits<To>::is_signed)>
|
||||||
|
FMT_CONSTEXPR To lossless_integral_conversion(const From from, int& ec) {
|
||||||
|
ec = 0;
|
||||||
|
using F = std::numeric_limits<From>;
|
||||||
|
using T = std::numeric_limits<To>;
|
||||||
|
static_assert(F::is_integer, "From must be integral");
|
||||||
|
static_assert(T::is_integer, "To must be integral");
|
||||||
|
|
||||||
|
// A and B are both signed, or both unsigned.
|
||||||
|
if (F::digits <= T::digits) {
|
||||||
|
// From fits in To without any problem.
|
||||||
|
} else {
|
||||||
|
// From does not always fit in To, resort to a dynamic check.
|
||||||
|
if (from < T::min() || from > T::max()) {
|
||||||
|
// outside range.
|
||||||
|
ec = 1;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return static_cast<To>(from);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* converts From to To, without loss. If the dynamic value of from
|
||||||
|
* can't be converted to To without loss, ec is set.
|
||||||
|
*/
|
||||||
|
template <typename To, typename From,
|
||||||
|
FMT_ENABLE_IF(!std::is_same<From, To>::value &&
|
||||||
|
std::numeric_limits<From>::is_signed !=
|
||||||
|
std::numeric_limits<To>::is_signed)>
|
||||||
|
FMT_CONSTEXPR To lossless_integral_conversion(const From from, int& ec) {
|
||||||
|
ec = 0;
|
||||||
|
using F = std::numeric_limits<From>;
|
||||||
|
using T = std::numeric_limits<To>;
|
||||||
|
static_assert(F::is_integer, "From must be integral");
|
||||||
|
static_assert(T::is_integer, "To must be integral");
|
||||||
|
|
||||||
|
if (F::is_signed && !T::is_signed) {
|
||||||
|
// From may be negative, not allowed!
|
||||||
|
if (fmt::internal::is_negative(from)) {
|
||||||
|
ec = 1;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
// From is positive. Can it always fit in To?
|
||||||
|
if (F::digits <= T::digits) {
|
||||||
|
// yes, From always fits in To.
|
||||||
|
} else {
|
||||||
|
// from may not fit in To, we have to do a dynamic check
|
||||||
|
if (from > static_cast<From>(T::max())) {
|
||||||
|
ec = 1;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!F::is_signed && T::is_signed) {
|
||||||
|
// can from be held in To?
|
||||||
|
if (F::digits < T::digits) {
|
||||||
|
// yes, From always fits in To.
|
||||||
|
} else {
|
||||||
|
// from may not fit in To, we have to do a dynamic check
|
||||||
|
if (from > static_cast<From>(T::max())) {
|
||||||
|
// outside range.
|
||||||
|
ec = 1;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// reaching here means all is ok for lossless conversion.
|
||||||
|
return static_cast<To>(from);
|
||||||
|
|
||||||
|
} // function
|
||||||
|
|
||||||
|
template <typename To, typename From,
|
||||||
|
FMT_ENABLE_IF(std::is_same<From, To>::value)>
|
||||||
|
FMT_CONSTEXPR To lossless_integral_conversion(const From from, int& ec) {
|
||||||
|
ec = 0;
|
||||||
|
return from;
|
||||||
|
} // function
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
/**
|
||||||
|
* converts From to To if possible, otherwise ec is set.
|
||||||
|
*
|
||||||
|
* input | output
|
||||||
|
* ---------------------------------|---------------
|
||||||
|
* NaN | NaN
|
||||||
|
* Inf | Inf
|
||||||
|
* normal, fits in output | converted (possibly lossy)
|
||||||
|
* normal, does not fit in output | ec is set
|
||||||
|
* subnormal | best effort
|
||||||
|
* -Inf | -Inf
|
||||||
|
*/
|
||||||
|
// clang-format on
|
||||||
|
template <typename To, typename From,
|
||||||
|
FMT_ENABLE_IF(!std::is_same<From, To>::value)>
|
||||||
|
FMT_CONSTEXPR To safe_float_conversion(const From from, int& ec) {
|
||||||
|
ec = 0;
|
||||||
|
using T = std::numeric_limits<To>;
|
||||||
|
static_assert(std::is_floating_point<From>::value, "From must be floating");
|
||||||
|
static_assert(std::is_floating_point<To>::value, "To must be floating");
|
||||||
|
|
||||||
|
// catch the only happy case
|
||||||
|
if (std::isfinite(from)) {
|
||||||
|
if (from >= T::lowest() && from <= T::max()) {
|
||||||
|
return static_cast<To>(from);
|
||||||
|
}
|
||||||
|
// not within range.
|
||||||
|
ec = 1;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
// nan and inf will be preserved
|
||||||
|
return static_cast<To>(from);
|
||||||
|
} // function
|
||||||
|
|
||||||
|
template <typename To, typename From,
|
||||||
|
FMT_ENABLE_IF(std::is_same<From, To>::value)>
|
||||||
|
FMT_CONSTEXPR To safe_float_conversion(const From from, int& ec) {
|
||||||
|
ec = 0;
|
||||||
|
static_assert(std::is_floating_point<From>::value, "From must be floating");
|
||||||
|
return from;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* safe duration cast between integral durations
|
||||||
|
*/
|
||||||
|
template <typename To, typename FromRep, typename FromPeriod,
|
||||||
|
FMT_ENABLE_IF(std::is_integral<FromRep>::value),
|
||||||
|
FMT_ENABLE_IF(std::is_integral<typename To::rep>::value)>
|
||||||
|
To safe_duration_cast(std::chrono::duration<FromRep, FromPeriod> from,
|
||||||
|
int& ec) {
|
||||||
|
using From = std::chrono::duration<FromRep, FromPeriod>;
|
||||||
|
ec = 0;
|
||||||
|
// the basic idea is that we need to convert from count() in the from type
|
||||||
|
// to count() in the To type, by multiplying it with this:
|
||||||
|
struct Factor
|
||||||
|
: std::ratio_divide<typename From::period, typename To::period> {};
|
||||||
|
|
||||||
|
static_assert(Factor::num > 0, "num must be positive");
|
||||||
|
static_assert(Factor::den > 0, "den must be positive");
|
||||||
|
|
||||||
|
// the conversion is like this: multiply from.count() with Factor::num
|
||||||
|
// /Factor::den and convert it to To::rep, all this without
|
||||||
|
// overflow/underflow. let's start by finding a suitable type that can hold
|
||||||
|
// both To, From and Factor::num
|
||||||
|
using IntermediateRep =
|
||||||
|
typename std::common_type<typename From::rep, typename To::rep,
|
||||||
|
decltype(Factor::num)>::type;
|
||||||
|
|
||||||
|
// safe conversion to IntermediateRep
|
||||||
|
IntermediateRep count =
|
||||||
|
lossless_integral_conversion<IntermediateRep>(from.count(), ec);
|
||||||
|
if (ec) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
// multiply with Factor::num without overflow or underflow
|
||||||
|
if (Factor::num != 1) {
|
||||||
|
const auto max1 = internal::max_value<IntermediateRep>() / Factor::num;
|
||||||
|
if (count > max1) {
|
||||||
|
ec = 1;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
const auto min1 = std::numeric_limits<IntermediateRep>::min() / Factor::num;
|
||||||
|
if (count < min1) {
|
||||||
|
ec = 1;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
count *= Factor::num;
|
||||||
|
}
|
||||||
|
|
||||||
|
// this can't go wrong, right? den>0 is checked earlier.
|
||||||
|
if (Factor::den != 1) {
|
||||||
|
count /= Factor::den;
|
||||||
|
}
|
||||||
|
// convert to the to type, safely
|
||||||
|
using ToRep = typename To::rep;
|
||||||
|
const ToRep tocount = lossless_integral_conversion<ToRep>(count, ec);
|
||||||
|
if (ec) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
return To{tocount};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* safe duration_cast between floating point durations
|
||||||
|
*/
|
||||||
|
template <typename To, typename FromRep, typename FromPeriod,
|
||||||
|
FMT_ENABLE_IF(std::is_floating_point<FromRep>::value),
|
||||||
|
FMT_ENABLE_IF(std::is_floating_point<typename To::rep>::value)>
|
||||||
|
To safe_duration_cast(std::chrono::duration<FromRep, FromPeriod> from,
|
||||||
|
int& ec) {
|
||||||
|
using From = std::chrono::duration<FromRep, FromPeriod>;
|
||||||
|
ec = 0;
|
||||||
|
if (std::isnan(from.count())) {
|
||||||
|
// nan in, gives nan out. easy.
|
||||||
|
return To{std::numeric_limits<typename To::rep>::quiet_NaN()};
|
||||||
|
}
|
||||||
|
// maybe we should also check if from is denormal, and decide what to do about
|
||||||
|
// it.
|
||||||
|
|
||||||
|
// +-inf should be preserved.
|
||||||
|
if (std::isinf(from.count())) {
|
||||||
|
return To{from.count()};
|
||||||
|
}
|
||||||
|
|
||||||
|
// the basic idea is that we need to convert from count() in the from type
|
||||||
|
// to count() in the To type, by multiplying it with this:
|
||||||
|
struct Factor
|
||||||
|
: std::ratio_divide<typename From::period, typename To::period> {};
|
||||||
|
|
||||||
|
static_assert(Factor::num > 0, "num must be positive");
|
||||||
|
static_assert(Factor::den > 0, "den must be positive");
|
||||||
|
|
||||||
|
// the conversion is like this: multiply from.count() with Factor::num
|
||||||
|
// /Factor::den and convert it to To::rep, all this without
|
||||||
|
// overflow/underflow. let's start by finding a suitable type that can hold
|
||||||
|
// both To, From and Factor::num
|
||||||
|
using IntermediateRep =
|
||||||
|
typename std::common_type<typename From::rep, typename To::rep,
|
||||||
|
decltype(Factor::num)>::type;
|
||||||
|
|
||||||
|
// force conversion of From::rep -> IntermediateRep to be safe,
|
||||||
|
// even if it will never happen be narrowing in this context.
|
||||||
|
IntermediateRep count =
|
||||||
|
safe_float_conversion<IntermediateRep>(from.count(), ec);
|
||||||
|
if (ec) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
// multiply with Factor::num without overflow or underflow
|
||||||
|
if (Factor::num != 1) {
|
||||||
|
constexpr auto max1 = internal::max_value<IntermediateRep>() /
|
||||||
|
static_cast<IntermediateRep>(Factor::num);
|
||||||
|
if (count > max1) {
|
||||||
|
ec = 1;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
constexpr auto min1 = std::numeric_limits<IntermediateRep>::lowest() /
|
||||||
|
static_cast<IntermediateRep>(Factor::num);
|
||||||
|
if (count < min1) {
|
||||||
|
ec = 1;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
count *= static_cast<IntermediateRep>(Factor::num);
|
||||||
|
}
|
||||||
|
|
||||||
|
// this can't go wrong, right? den>0 is checked earlier.
|
||||||
|
if (Factor::den != 1) {
|
||||||
|
using common_t = typename std::common_type<IntermediateRep, intmax_t>::type;
|
||||||
|
count /= static_cast<common_t>(Factor::den);
|
||||||
|
}
|
||||||
|
|
||||||
|
// convert to the to type, safely
|
||||||
|
using ToRep = typename To::rep;
|
||||||
|
|
||||||
|
const ToRep tocount = safe_float_conversion<ToRep>(count, ec);
|
||||||
|
if (ec) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
return To{tocount};
|
||||||
|
}
|
||||||
|
} // namespace safe_duration_cast
|
||||||
|
#endif
|
||||||
|
|
||||||
// Prevents expansion of a preceding token as a function-style macro.
|
// Prevents expansion of a preceding token as a function-style macro.
|
||||||
// Usage: f FMT_NOMACRO()
|
// Usage: f FMT_NOMACRO()
|
||||||
@ -403,7 +678,7 @@ inline bool isfinite(T value) {
|
|||||||
return std::isfinite(value);
|
return std::isfinite(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convers value to int and checks that it's in the range [0, upper).
|
// Converts value to int and checks that it's in the range [0, upper).
|
||||||
template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
|
template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
|
||||||
inline int to_nonnegative_int(T value, int upper) {
|
inline int to_nonnegative_int(T value, int upper) {
|
||||||
FMT_ASSERT(value >= 0 && value <= upper, "invalid value");
|
FMT_ASSERT(value >= 0 && value <= upper, "invalid value");
|
||||||
@ -582,8 +857,8 @@ struct chrono_formatter {
|
|||||||
void write(Rep value, int width) {
|
void write(Rep value, int width) {
|
||||||
write_sign();
|
write_sign();
|
||||||
if (isnan(value)) return write_nan();
|
if (isnan(value)) return write_nan();
|
||||||
uint32_or_64_t<int> n = to_unsigned(
|
uint32_or_64_or_128_t<int> n =
|
||||||
to_nonnegative_int(value, (std::numeric_limits<int>::max)()));
|
to_unsigned(to_nonnegative_int(value, max_value<int>()));
|
||||||
int num_digits = internal::count_digits(n);
|
int num_digits = internal::count_digits(n);
|
||||||
if (width > num_digits) out = std::fill_n(out, width - num_digits, '0');
|
if (width > num_digits) out = std::fill_n(out, width - num_digits, '0');
|
||||||
out = format_decimal<char_type>(out, n, num_digits);
|
out = format_decimal<char_type>(out, n, num_digits);
|
||||||
@ -728,7 +1003,7 @@ struct formatter<std::chrono::duration<Rep, Period>, Char> {
|
|||||||
|
|
||||||
struct spec_handler {
|
struct spec_handler {
|
||||||
formatter& f;
|
formatter& f;
|
||||||
basic_parse_context<Char>& context;
|
basic_format_parse_context<Char>& context;
|
||||||
basic_string_view<Char> format_str;
|
basic_string_view<Char> format_str;
|
||||||
|
|
||||||
template <typename Id> FMT_CONSTEXPR arg_ref_type make_arg_ref(Id arg_id) {
|
template <typename Id> FMT_CONSTEXPR arg_ref_type make_arg_ref(Id arg_id) {
|
||||||
@ -738,8 +1013,7 @@ struct formatter<std::chrono::duration<Rep, Period>, Char> {
|
|||||||
|
|
||||||
FMT_CONSTEXPR arg_ref_type make_arg_ref(basic_string_view<Char> arg_id) {
|
FMT_CONSTEXPR arg_ref_type make_arg_ref(basic_string_view<Char> arg_id) {
|
||||||
context.check_arg_id(arg_id);
|
context.check_arg_id(arg_id);
|
||||||
const auto str_val = internal::string_view_metadata(format_str, arg_id);
|
return arg_ref_type(arg_id);
|
||||||
return arg_ref_type(str_val);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FMT_CONSTEXPR arg_ref_type make_arg_ref(internal::auto_id) {
|
FMT_CONSTEXPR arg_ref_type make_arg_ref(internal::auto_id) {
|
||||||
@ -750,7 +1024,7 @@ struct formatter<std::chrono::duration<Rep, Period>, Char> {
|
|||||||
void on_fill(Char fill) { f.specs.fill[0] = fill; }
|
void on_fill(Char fill) { f.specs.fill[0] = fill; }
|
||||||
void on_align(align_t align) { f.specs.align = align; }
|
void on_align(align_t align) { f.specs.align = align; }
|
||||||
void on_width(unsigned width) { f.specs.width = width; }
|
void on_width(unsigned width) { f.specs.width = width; }
|
||||||
void on_precision(unsigned precision) { f.precision = precision; }
|
void on_precision(unsigned _precision) { f.precision = _precision; }
|
||||||
void end_precision() {}
|
void end_precision() {}
|
||||||
|
|
||||||
template <typename Id> void on_dynamic_width(Id arg_id) {
|
template <typename Id> void on_dynamic_width(Id arg_id) {
|
||||||
@ -762,13 +1036,13 @@ struct formatter<std::chrono::duration<Rep, Period>, Char> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
using iterator = typename basic_parse_context<Char>::iterator;
|
using iterator = typename basic_format_parse_context<Char>::iterator;
|
||||||
struct parse_range {
|
struct parse_range {
|
||||||
iterator begin;
|
iterator begin;
|
||||||
iterator end;
|
iterator end;
|
||||||
};
|
};
|
||||||
|
|
||||||
FMT_CONSTEXPR parse_range do_parse(basic_parse_context<Char>& ctx) {
|
FMT_CONSTEXPR parse_range do_parse(basic_format_parse_context<Char>& ctx) {
|
||||||
auto begin = ctx.begin(), end = ctx.end();
|
auto begin = ctx.begin(), end = ctx.end();
|
||||||
if (begin == end || *begin == '}') return {begin, begin};
|
if (begin == end || *begin == '}') return {begin, begin};
|
||||||
spec_handler handler{*this, ctx, format_str};
|
spec_handler handler{*this, ctx, format_str};
|
||||||
@ -789,7 +1063,7 @@ struct formatter<std::chrono::duration<Rep, Period>, Char> {
|
|||||||
public:
|
public:
|
||||||
formatter() : precision(-1) {}
|
formatter() : precision(-1) {}
|
||||||
|
|
||||||
FMT_CONSTEXPR auto parse(basic_parse_context<Char>& ctx)
|
FMT_CONSTEXPR auto parse(basic_format_parse_context<Char>& ctx)
|
||||||
-> decltype(ctx.begin()) {
|
-> decltype(ctx.begin()) {
|
||||||
auto range = do_parse(ctx);
|
auto range = do_parse(ctx);
|
||||||
format_str = basic_string_view<Char>(
|
format_str = basic_string_view<Char>(
|
||||||
@ -806,10 +1080,10 @@ struct formatter<std::chrono::duration<Rep, Period>, Char> {
|
|||||||
auto out = std::back_inserter(buf);
|
auto out = std::back_inserter(buf);
|
||||||
using range = internal::output_range<decltype(ctx.out()), Char>;
|
using range = internal::output_range<decltype(ctx.out()), Char>;
|
||||||
internal::basic_writer<range> w(range(ctx.out()));
|
internal::basic_writer<range> w(range(ctx.out()));
|
||||||
internal::handle_dynamic_spec<internal::width_checker>(
|
internal::handle_dynamic_spec<internal::width_checker>(specs.width,
|
||||||
specs.width, width_ref, ctx, format_str.begin());
|
width_ref, ctx);
|
||||||
internal::handle_dynamic_spec<internal::precision_checker>(
|
internal::handle_dynamic_spec<internal::precision_checker>(
|
||||||
precision, precision_ref, ctx, format_str.begin());
|
precision, precision_ref, ctx);
|
||||||
if (begin == end || *begin == '}') {
|
if (begin == end || *begin == '}') {
|
||||||
out = internal::format_chrono_duration_value(out, d.count(), precision);
|
out = internal::format_chrono_duration_value(out, d.count(), precision);
|
||||||
internal::format_chrono_duration_unit<Period>(out);
|
internal::format_chrono_duration_unit<Period>(out);
|
||||||
|
@ -299,15 +299,15 @@ class text_style {
|
|||||||
return static_cast<uint8_t>(ems) != 0;
|
return static_cast<uint8_t>(ems) != 0;
|
||||||
}
|
}
|
||||||
FMT_CONSTEXPR internal::color_type get_foreground() const FMT_NOEXCEPT {
|
FMT_CONSTEXPR internal::color_type get_foreground() const FMT_NOEXCEPT {
|
||||||
assert(has_foreground() && "no foreground specified for this style");
|
FMT_ASSERT(has_foreground(), "no foreground specified for this style");
|
||||||
return foreground_color;
|
return foreground_color;
|
||||||
}
|
}
|
||||||
FMT_CONSTEXPR internal::color_type get_background() const FMT_NOEXCEPT {
|
FMT_CONSTEXPR internal::color_type get_background() const FMT_NOEXCEPT {
|
||||||
assert(has_background() && "no background specified for this style");
|
FMT_ASSERT(has_background(), "no background specified for this style");
|
||||||
return background_color;
|
return background_color;
|
||||||
}
|
}
|
||||||
FMT_CONSTEXPR emphasis get_emphasis() const FMT_NOEXCEPT {
|
FMT_CONSTEXPR emphasis get_emphasis() const FMT_NOEXCEPT {
|
||||||
assert(has_emphasis() && "no emphasis specified for this style");
|
FMT_ASSERT(has_emphasis(), "no emphasis specified for this style");
|
||||||
return ems;
|
return ems;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -470,58 +470,41 @@ inline void reset_color(basic_memory_buffer<Char>& buffer) FMT_NOEXCEPT {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename Char>
|
template <typename Char>
|
||||||
std::basic_string<Char> vformat(const text_style& ts,
|
void vformat_to(basic_memory_buffer<Char>& buf, const text_style& ts,
|
||||||
basic_string_view<Char> format_str,
|
basic_string_view<Char> format_str,
|
||||||
basic_format_args<buffer_context<Char>> args) {
|
basic_format_args<buffer_context<Char>> args) {
|
||||||
basic_memory_buffer<Char> buffer;
|
|
||||||
bool has_style = false;
|
bool has_style = false;
|
||||||
if (ts.has_emphasis()) {
|
if (ts.has_emphasis()) {
|
||||||
has_style = true;
|
has_style = true;
|
||||||
ansi_color_escape<Char> escape = make_emphasis<Char>(ts.get_emphasis());
|
auto emphasis = internal::make_emphasis<Char>(ts.get_emphasis());
|
||||||
buffer.append(escape.begin(), escape.end());
|
buf.append(emphasis.begin(), emphasis.end());
|
||||||
}
|
}
|
||||||
if (ts.has_foreground()) {
|
if (ts.has_foreground()) {
|
||||||
has_style = true;
|
has_style = true;
|
||||||
ansi_color_escape<Char> escape =
|
auto foreground =
|
||||||
make_foreground_color<Char>(ts.get_foreground());
|
internal::make_foreground_color<Char>(ts.get_foreground());
|
||||||
buffer.append(escape.begin(), escape.end());
|
buf.append(foreground.begin(), foreground.end());
|
||||||
}
|
}
|
||||||
if (ts.has_background()) {
|
if (ts.has_background()) {
|
||||||
has_style = true;
|
has_style = true;
|
||||||
ansi_color_escape<Char> escape =
|
auto background =
|
||||||
make_background_color<Char>(ts.get_background());
|
internal::make_background_color<Char>(ts.get_background());
|
||||||
buffer.append(escape.begin(), escape.end());
|
buf.append(background.begin(), background.end());
|
||||||
}
|
}
|
||||||
internal::vformat_to(buffer, format_str, args);
|
vformat_to(buf, format_str, args);
|
||||||
if (has_style) {
|
if (has_style) {
|
||||||
reset_color<Char>(buffer);
|
internal::reset_color<Char>(buf);
|
||||||
}
|
}
|
||||||
return fmt::to_string(buffer);
|
|
||||||
}
|
}
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
|
|
||||||
template <typename S, typename Char = char_t<S>>
|
template <typename S, typename Char = char_t<S>>
|
||||||
void vprint(std::FILE* f, const text_style& ts, const S& format,
|
void vprint(std::FILE* f, const text_style& ts, const S& format,
|
||||||
basic_format_args<buffer_context<Char>> args) {
|
basic_format_args<buffer_context<Char>> args) {
|
||||||
bool has_style = false;
|
basic_memory_buffer<Char> buf;
|
||||||
if (ts.has_emphasis()) {
|
internal::vformat_to(buf, ts, to_string_view(format), args);
|
||||||
has_style = true;
|
buf.push_back(Char(0));
|
||||||
internal::fputs<Char>(internal::make_emphasis<Char>(ts.get_emphasis()), f);
|
internal::fputs(buf.data(), 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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -558,7 +541,9 @@ template <typename S, typename Char = char_t<S> >
|
|||||||
inline std::basic_string<Char> vformat(
|
inline std::basic_string<Char> vformat(
|
||||||
const text_style& ts, const S& format_str,
|
const text_style& ts, const S& format_str,
|
||||||
basic_format_args<buffer_context<Char>> args) {
|
basic_format_args<buffer_context<Char>> args) {
|
||||||
return internal::vformat(ts, to_string_view(format_str), args);
|
basic_memory_buffer<Char> buf;
|
||||||
|
internal::vformat_to(buf, ts, to_string_view(format_str), args);
|
||||||
|
return fmt::to_string(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -576,8 +561,8 @@ inline std::basic_string<Char> vformat(
|
|||||||
template <typename S, typename... Args, typename Char = char_t<S>>
|
template <typename S, typename... Args, typename Char = char_t<S>>
|
||||||
inline std::basic_string<Char> format(const text_style& ts, const S& format_str,
|
inline std::basic_string<Char> format(const text_style& ts, const S& format_str,
|
||||||
const Args&... args) {
|
const Args&... args) {
|
||||||
return internal::vformat(ts, to_string_view(format_str),
|
return vformat(ts, to_string_view(format_str),
|
||||||
{internal::make_args_checked(format_str, args...)});
|
{internal::make_args_checked<Args...>(format_str, args...)});
|
||||||
}
|
}
|
||||||
|
|
||||||
FMT_END_NAMESPACE
|
FMT_END_NAMESPACE
|
||||||
|
@ -14,250 +14,44 @@
|
|||||||
FMT_BEGIN_NAMESPACE
|
FMT_BEGIN_NAMESPACE
|
||||||
namespace internal {
|
namespace internal {
|
||||||
|
|
||||||
|
// Part of a compiled format string. It can be either literal text or a
|
||||||
|
// replacement field.
|
||||||
template <typename Char> struct format_part {
|
template <typename Char> struct format_part {
|
||||||
public:
|
enum class kind { arg_index, arg_name, text, replacement };
|
||||||
struct named_argument_id {
|
|
||||||
FMT_CONSTEXPR named_argument_id(internal::string_view_metadata id)
|
struct replacement {
|
||||||
: id(id) {}
|
arg_ref<Char> arg_id;
|
||||||
internal::string_view_metadata id;
|
dynamic_format_specs<Char> specs;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct argument_id {
|
kind part_kind;
|
||||||
FMT_CONSTEXPR argument_id() : argument_id(0u) {}
|
|
||||||
|
|
||||||
FMT_CONSTEXPR argument_id(unsigned id)
|
|
||||||
: which(which_arg_id::index), val(id) {}
|
|
||||||
|
|
||||||
FMT_CONSTEXPR argument_id(internal::string_view_metadata id)
|
|
||||||
: which(which_arg_id::named_index), val(id) {}
|
|
||||||
|
|
||||||
enum class which_arg_id { index, named_index };
|
|
||||||
|
|
||||||
which_arg_id which;
|
|
||||||
|
|
||||||
union value {
|
union value {
|
||||||
FMT_CONSTEXPR value() : index(0u) {}
|
unsigned arg_index;
|
||||||
FMT_CONSTEXPR value(unsigned id) : index(id) {}
|
basic_string_view<Char> str;
|
||||||
FMT_CONSTEXPR value(internal::string_view_metadata id)
|
replacement repl;
|
||||||
: named_index(id) {}
|
|
||||||
|
|
||||||
unsigned index;
|
FMT_CONSTEXPR value(unsigned index = 0) : arg_index(index) {}
|
||||||
internal::string_view_metadata named_index;
|
FMT_CONSTEXPR value(basic_string_view<Char> s) : str(s) {}
|
||||||
|
FMT_CONSTEXPR value(replacement r) : repl(r) {}
|
||||||
} val;
|
} val;
|
||||||
};
|
// Position past the end of the argument id.
|
||||||
|
const Char* arg_id_end = nullptr;
|
||||||
|
|
||||||
struct specification {
|
FMT_CONSTEXPR format_part(kind k = kind::arg_index, value v = {})
|
||||||
FMT_CONSTEXPR specification() : arg_id(0u) {}
|
: part_kind(k), val(v) {}
|
||||||
FMT_CONSTEXPR specification(unsigned id) : arg_id(id) {}
|
|
||||||
|
|
||||||
FMT_CONSTEXPR specification(internal::string_view_metadata id)
|
static FMT_CONSTEXPR format_part make_arg_index(unsigned index) {
|
||||||
: arg_id(id) {}
|
return format_part(kind::arg_index, index);
|
||||||
|
|
||||||
argument_id arg_id;
|
|
||||||
internal::dynamic_format_specs<Char> parsed_specs;
|
|
||||||
};
|
|
||||||
|
|
||||||
FMT_CONSTEXPR format_part()
|
|
||||||
: which(kind::argument_id), end_of_argument_id(0u), val(0u) {}
|
|
||||||
|
|
||||||
FMT_CONSTEXPR format_part(internal::string_view_metadata text)
|
|
||||||
: which(kind::text), end_of_argument_id(0u), val(text) {}
|
|
||||||
|
|
||||||
FMT_CONSTEXPR format_part(unsigned id)
|
|
||||||
: which(kind::argument_id), end_of_argument_id(0u), val(id) {}
|
|
||||||
|
|
||||||
FMT_CONSTEXPR format_part(named_argument_id arg_id)
|
|
||||||
: which(kind::named_argument_id), end_of_argument_id(0u), val(arg_id) {}
|
|
||||||
|
|
||||||
FMT_CONSTEXPR format_part(specification spec)
|
|
||||||
: which(kind::specification), end_of_argument_id(0u), val(spec) {}
|
|
||||||
|
|
||||||
enum class kind { argument_id, named_argument_id, text, specification };
|
|
||||||
|
|
||||||
kind which;
|
|
||||||
std::size_t end_of_argument_id;
|
|
||||||
union value {
|
|
||||||
FMT_CONSTEXPR value() : arg_id(0u) {}
|
|
||||||
FMT_CONSTEXPR value(unsigned id) : arg_id(id) {}
|
|
||||||
FMT_CONSTEXPR value(named_argument_id named_id)
|
|
||||||
: named_arg_id(named_id.id) {}
|
|
||||||
FMT_CONSTEXPR value(internal::string_view_metadata t) : text(t) {}
|
|
||||||
FMT_CONSTEXPR value(specification s) : spec(s) {}
|
|
||||||
unsigned arg_id;
|
|
||||||
internal::string_view_metadata named_arg_id;
|
|
||||||
internal::string_view_metadata text;
|
|
||||||
specification spec;
|
|
||||||
} val;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename Char, typename PartsContainer>
|
|
||||||
class format_preparation_handler : public internal::error_handler {
|
|
||||||
private:
|
|
||||||
using part = format_part<Char>;
|
|
||||||
|
|
||||||
public:
|
|
||||||
using iterator = typename basic_string_view<Char>::iterator;
|
|
||||||
|
|
||||||
FMT_CONSTEXPR format_preparation_handler(basic_string_view<Char> format,
|
|
||||||
PartsContainer& parts)
|
|
||||||
: parts_(parts), format_(format), parse_context_(format) {}
|
|
||||||
|
|
||||||
FMT_CONSTEXPR void on_text(const Char* begin, const Char* end) {
|
|
||||||
if (begin == end) return;
|
|
||||||
const auto offset = begin - format_.data();
|
|
||||||
const auto size = end - begin;
|
|
||||||
parts_.push_back(part(string_view_metadata(offset, size)));
|
|
||||||
}
|
}
|
||||||
|
static FMT_CONSTEXPR format_part make_arg_name(basic_string_view<Char> name) {
|
||||||
FMT_CONSTEXPR void on_arg_id() {
|
return format_part(kind::arg_name, name);
|
||||||
parts_.push_back(part(parse_context_.next_arg_id()));
|
|
||||||
}
|
}
|
||||||
|
static FMT_CONSTEXPR format_part make_text(basic_string_view<Char> text) {
|
||||||
FMT_CONSTEXPR void on_arg_id(unsigned id) {
|
return format_part(kind::text, text);
|
||||||
parse_context_.check_arg_id(id);
|
|
||||||
parts_.push_back(part(id));
|
|
||||||
}
|
}
|
||||||
|
static FMT_CONSTEXPR format_part make_replacement(replacement repl) {
|
||||||
FMT_CONSTEXPR void on_arg_id(basic_string_view<Char> id) {
|
return format_part(kind::replacement, repl);
|
||||||
const auto view = string_view_metadata(format_, id);
|
|
||||||
const auto arg_id = typename part::named_argument_id(view);
|
|
||||||
parts_.push_back(part(arg_id));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FMT_CONSTEXPR void on_replacement_field(const Char* ptr) {
|
|
||||||
parts_.back().end_of_argument_id = ptr - format_.begin();
|
|
||||||
}
|
|
||||||
|
|
||||||
FMT_CONSTEXPR const Char* on_format_specs(const Char* begin,
|
|
||||||
const Char* end) {
|
|
||||||
const auto specs_offset = to_unsigned(begin - format_.begin());
|
|
||||||
|
|
||||||
using parse_context = basic_parse_context<Char>;
|
|
||||||
internal::dynamic_format_specs<Char> parsed_specs;
|
|
||||||
dynamic_specs_handler<parse_context> handler(parsed_specs, parse_context_);
|
|
||||||
begin = parse_format_specs(begin, end, handler);
|
|
||||||
|
|
||||||
if (*begin != '}') on_error("missing '}' in format string");
|
|
||||||
|
|
||||||
auto& last_part = parts_.back();
|
|
||||||
auto specs = last_part.which == part::kind::argument_id
|
|
||||||
? typename part::specification(last_part.val.arg_id)
|
|
||||||
: typename part::specification(last_part.val.named_arg_id);
|
|
||||||
specs.parsed_specs = parsed_specs;
|
|
||||||
last_part = part(specs);
|
|
||||||
last_part.end_of_argument_id = specs_offset;
|
|
||||||
return begin;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
PartsContainer& parts_;
|
|
||||||
basic_string_view<Char> format_;
|
|
||||||
basic_parse_context<Char> parse_context_;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename Format, typename PreparedPartsProvider, typename... Args>
|
|
||||||
class prepared_format {
|
|
||||||
public:
|
|
||||||
using char_type = char_t<Format>;
|
|
||||||
using format_part_t = format_part<char_type>;
|
|
||||||
|
|
||||||
constexpr prepared_format(Format f)
|
|
||||||
: format_(std::move(f)), parts_provider_(to_string_view(format_)) {}
|
|
||||||
|
|
||||||
prepared_format() = delete;
|
|
||||||
|
|
||||||
using context = buffer_context<char_type>;
|
|
||||||
|
|
||||||
template <typename Range, typename Context>
|
|
||||||
auto vformat_to(Range out, basic_format_args<Context> args) const ->
|
|
||||||
typename Context::iterator {
|
|
||||||
const auto format_view = internal::to_string_view(format_);
|
|
||||||
basic_parse_context<char_type> parse_ctx(format_view);
|
|
||||||
Context ctx(out.begin(), args);
|
|
||||||
|
|
||||||
const auto& parts = parts_provider_.parts();
|
|
||||||
for (auto part_it = parts.begin(); part_it != parts.end(); ++part_it) {
|
|
||||||
const auto& part = *part_it;
|
|
||||||
const auto& value = part.val;
|
|
||||||
|
|
||||||
switch (part.which) {
|
|
||||||
case format_part_t::kind::text: {
|
|
||||||
const auto text = value.text.to_view(format_view.data());
|
|
||||||
auto output = ctx.out();
|
|
||||||
auto&& it = internal::reserve(output, text.size());
|
|
||||||
it = std::copy_n(text.begin(), text.size(), it);
|
|
||||||
ctx.advance_to(output);
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case format_part_t::kind::argument_id: {
|
|
||||||
advance_parse_context_to_specification(parse_ctx, part);
|
|
||||||
format_arg<Range>(parse_ctx, ctx, value.arg_id);
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case format_part_t::kind::named_argument_id: {
|
|
||||||
advance_parse_context_to_specification(parse_ctx, part);
|
|
||||||
const auto named_arg_id =
|
|
||||||
value.named_arg_id.to_view(format_view.data());
|
|
||||||
format_arg<Range>(parse_ctx, ctx, named_arg_id);
|
|
||||||
} break;
|
|
||||||
case format_part_t::kind::specification: {
|
|
||||||
const auto& arg_id_value = value.spec.arg_id.val;
|
|
||||||
const auto arg = value.spec.arg_id.which ==
|
|
||||||
format_part_t::argument_id::which_arg_id::index
|
|
||||||
? ctx.arg(arg_id_value.index)
|
|
||||||
: ctx.arg(arg_id_value.named_index.to_view(
|
|
||||||
to_string_view(format_).data()));
|
|
||||||
|
|
||||||
auto specs = value.spec.parsed_specs;
|
|
||||||
|
|
||||||
handle_dynamic_spec<internal::width_checker>(
|
|
||||||
specs.width, specs.width_ref, ctx, format_view.begin());
|
|
||||||
handle_dynamic_spec<internal::precision_checker>(
|
|
||||||
specs.precision, specs.precision_ref, ctx, format_view.begin());
|
|
||||||
|
|
||||||
check_prepared_specs(specs, arg.type());
|
|
||||||
advance_parse_context_to_specification(parse_ctx, part);
|
|
||||||
ctx.advance_to(
|
|
||||||
visit_format_arg(arg_formatter<Range>(ctx, nullptr, &specs), arg));
|
|
||||||
} break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ctx.out();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
void advance_parse_context_to_specification(
|
|
||||||
basic_parse_context<char_type>& parse_ctx,
|
|
||||||
const format_part_t& part) const {
|
|
||||||
const auto view = to_string_view(format_);
|
|
||||||
const auto specification_begin = view.data() + part.end_of_argument_id;
|
|
||||||
advance_to(parse_ctx, specification_begin);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename Range, typename Context, typename Id>
|
|
||||||
void format_arg(basic_parse_context<char_type>& parse_ctx, Context& ctx,
|
|
||||||
Id arg_id) const {
|
|
||||||
parse_ctx.check_arg_id(arg_id);
|
|
||||||
const auto stopped_at =
|
|
||||||
visit_format_arg(arg_formatter<Range>(ctx), ctx.arg(arg_id));
|
|
||||||
ctx.advance_to(stopped_at);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename Char>
|
|
||||||
void check_prepared_specs(const basic_format_specs<Char>& specs,
|
|
||||||
internal::type arg_type) const {
|
|
||||||
internal::error_handler h;
|
|
||||||
numeric_specs_checker<internal::error_handler> checker(h, arg_type);
|
|
||||||
if (specs.align == align::numeric) checker.require_numeric_argument();
|
|
||||||
if (specs.sign != sign::none) checker.check_sign();
|
|
||||||
if (specs.alt) checker.require_numeric_argument();
|
|
||||||
if (specs.precision >= 0) checker.check_precision();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
Format format_;
|
|
||||||
PreparedPartsProvider parts_provider_;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename Char> struct part_counter {
|
template <typename Char> struct part_counter {
|
||||||
@ -276,13 +70,13 @@ template <typename Char> struct part_counter {
|
|||||||
FMT_CONSTEXPR const Char* on_format_specs(const Char* begin,
|
FMT_CONSTEXPR const Char* on_format_specs(const Char* begin,
|
||||||
const Char* end) {
|
const Char* end) {
|
||||||
// Find the matching brace.
|
// Find the matching brace.
|
||||||
unsigned braces_counter = 0;
|
unsigned brace_counter = 0;
|
||||||
for (; begin != end; ++begin) {
|
for (; begin != end; ++begin) {
|
||||||
if (*begin == '{') {
|
if (*begin == '{') {
|
||||||
++braces_counter;
|
++brace_counter;
|
||||||
} else if (*begin == '}') {
|
} else if (*begin == '}') {
|
||||||
if (braces_counter == 0u) break;
|
if (brace_counter == 0u) break;
|
||||||
--braces_counter;
|
--brace_counter;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return begin;
|
return begin;
|
||||||
@ -291,156 +85,486 @@ template <typename Char> struct part_counter {
|
|||||||
FMT_CONSTEXPR void on_error(const char*) {}
|
FMT_CONSTEXPR void on_error(const char*) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename Format> class compiletime_prepared_parts_type_provider {
|
// Counts the number of parts in a format string.
|
||||||
private:
|
template <typename Char>
|
||||||
using char_type = char_t<Format>;
|
FMT_CONSTEXPR unsigned count_parts(basic_string_view<Char> format_str) {
|
||||||
|
part_counter<Char> counter;
|
||||||
static FMT_CONSTEXPR unsigned count_parts() {
|
parse_format_string<true>(format_str, counter);
|
||||||
FMT_CONSTEXPR_DECL const auto text = to_string_view(Format{});
|
|
||||||
part_counter<char_type> counter;
|
|
||||||
internal::parse_format_string</*IS_CONSTEXPR=*/true>(text, counter);
|
|
||||||
return counter.num_parts;
|
return counter.num_parts;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Workaround for old compilers. Compiletime parts preparation will not be
|
template <typename Char, typename PartHandler>
|
||||||
// performed with them anyway.
|
class format_string_compiler : public error_handler {
|
||||||
|
private:
|
||||||
|
using part = format_part<Char>;
|
||||||
|
|
||||||
|
PartHandler handler_;
|
||||||
|
part part_;
|
||||||
|
basic_string_view<Char> format_str_;
|
||||||
|
basic_format_parse_context<Char> parse_context_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
FMT_CONSTEXPR format_string_compiler(basic_string_view<Char> format_str,
|
||||||
|
PartHandler handler)
|
||||||
|
: handler_(handler),
|
||||||
|
format_str_(format_str),
|
||||||
|
parse_context_(format_str) {}
|
||||||
|
|
||||||
|
FMT_CONSTEXPR void on_text(const Char* begin, const Char* end) {
|
||||||
|
if (begin != end)
|
||||||
|
handler_(part::make_text({begin, to_unsigned(end - begin)}));
|
||||||
|
}
|
||||||
|
|
||||||
|
FMT_CONSTEXPR void on_arg_id() {
|
||||||
|
part_ = part::make_arg_index(parse_context_.next_arg_id());
|
||||||
|
}
|
||||||
|
|
||||||
|
FMT_CONSTEXPR void on_arg_id(unsigned id) {
|
||||||
|
parse_context_.check_arg_id(id);
|
||||||
|
part_ = part::make_arg_index(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
FMT_CONSTEXPR void on_arg_id(basic_string_view<Char> id) {
|
||||||
|
part_ = part::make_arg_name(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
FMT_CONSTEXPR void on_replacement_field(const Char* ptr) {
|
||||||
|
part_.arg_id_end = ptr;
|
||||||
|
handler_(part_);
|
||||||
|
}
|
||||||
|
|
||||||
|
FMT_CONSTEXPR const Char* on_format_specs(const Char* begin,
|
||||||
|
const Char* end) {
|
||||||
|
auto repl = typename part::replacement();
|
||||||
|
dynamic_specs_handler<basic_format_parse_context<Char>> handler(
|
||||||
|
repl.specs, parse_context_);
|
||||||
|
auto it = parse_format_specs(begin, end, handler);
|
||||||
|
if (*it != '}') on_error("missing '}' in format string");
|
||||||
|
repl.arg_id = part_.part_kind == part::kind::arg_index
|
||||||
|
? arg_ref<Char>(part_.val.arg_index)
|
||||||
|
: arg_ref<Char>(part_.val.str);
|
||||||
|
auto part = part::make_replacement(repl);
|
||||||
|
part.arg_id_end = begin;
|
||||||
|
handler_(part);
|
||||||
|
return it;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Compiles a format string and invokes handler(part) for each parsed part.
|
||||||
|
template <bool IS_CONSTEXPR, typename Char, typename PartHandler>
|
||||||
|
FMT_CONSTEXPR void compile_format_string(basic_string_view<Char> format_str,
|
||||||
|
PartHandler handler) {
|
||||||
|
parse_format_string<IS_CONSTEXPR>(
|
||||||
|
format_str,
|
||||||
|
format_string_compiler<Char, PartHandler>(format_str, handler));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Range, typename Context, typename Id>
|
||||||
|
void format_arg(
|
||||||
|
basic_format_parse_context<typename Range::value_type>& parse_ctx,
|
||||||
|
Context& ctx, Id arg_id) {
|
||||||
|
ctx.advance_to(
|
||||||
|
visit_format_arg(arg_formatter<Range>(ctx, &parse_ctx), ctx.arg(arg_id)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// vformat_to is defined in a subnamespace to prevent ADL.
|
||||||
|
namespace cf {
|
||||||
|
template <typename Context, typename Range, typename CompiledFormat>
|
||||||
|
auto vformat_to(Range out, CompiledFormat& cf, basic_format_args<Context> args)
|
||||||
|
-> typename Context::iterator {
|
||||||
|
using char_type = typename Context::char_type;
|
||||||
|
basic_format_parse_context<char_type> parse_ctx(
|
||||||
|
to_string_view(cf.format_str_));
|
||||||
|
Context ctx(out.begin(), args);
|
||||||
|
|
||||||
|
const auto& parts = cf.parts();
|
||||||
|
for (auto part_it = std::begin(parts); part_it != std::end(parts);
|
||||||
|
++part_it) {
|
||||||
|
const auto& part = *part_it;
|
||||||
|
const auto& value = part.val;
|
||||||
|
|
||||||
|
using format_part_t = format_part<char_type>;
|
||||||
|
switch (part.part_kind) {
|
||||||
|
case format_part_t::kind::text: {
|
||||||
|
const auto text = value.str;
|
||||||
|
auto output = ctx.out();
|
||||||
|
auto&& it = reserve(output, text.size());
|
||||||
|
it = std::copy_n(text.begin(), text.size(), it);
|
||||||
|
ctx.advance_to(output);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case format_part_t::kind::arg_index:
|
||||||
|
advance_to(parse_ctx, part.arg_id_end);
|
||||||
|
internal::format_arg<Range>(parse_ctx, ctx, value.arg_index);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case format_part_t::kind::arg_name:
|
||||||
|
advance_to(parse_ctx, part.arg_id_end);
|
||||||
|
internal::format_arg<Range>(parse_ctx, ctx, value.str);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case format_part_t::kind::replacement: {
|
||||||
|
const auto& arg_id_value = value.repl.arg_id.val;
|
||||||
|
const auto arg = value.repl.arg_id.kind == arg_id_kind::index
|
||||||
|
? ctx.arg(arg_id_value.index)
|
||||||
|
: ctx.arg(arg_id_value.name);
|
||||||
|
|
||||||
|
auto specs = value.repl.specs;
|
||||||
|
|
||||||
|
handle_dynamic_spec<width_checker>(specs.width, specs.width_ref, ctx);
|
||||||
|
handle_dynamic_spec<precision_checker>(specs.precision,
|
||||||
|
specs.precision_ref, ctx);
|
||||||
|
|
||||||
|
error_handler h;
|
||||||
|
numeric_specs_checker<error_handler> checker(h, arg.type());
|
||||||
|
if (specs.align == align::numeric) checker.require_numeric_argument();
|
||||||
|
if (specs.sign != sign::none) checker.check_sign();
|
||||||
|
if (specs.alt) checker.require_numeric_argument();
|
||||||
|
if (specs.precision >= 0) checker.check_precision();
|
||||||
|
|
||||||
|
advance_to(parse_ctx, part.arg_id_end);
|
||||||
|
ctx.advance_to(
|
||||||
|
visit_format_arg(arg_formatter<Range>(ctx, nullptr, &specs), arg));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ctx.out();
|
||||||
|
}
|
||||||
|
} // namespace cf
|
||||||
|
|
||||||
|
struct basic_compiled_format {};
|
||||||
|
|
||||||
|
template <typename S, typename = void>
|
||||||
|
struct compiled_format_base : basic_compiled_format {
|
||||||
|
using char_type = char_t<S>;
|
||||||
|
using parts_container = std::vector<internal::format_part<char_type>>;
|
||||||
|
|
||||||
|
parts_container compiled_parts;
|
||||||
|
|
||||||
|
explicit compiled_format_base(basic_string_view<char_type> format_str) {
|
||||||
|
compile_format_string<false>(format_str,
|
||||||
|
[this](const format_part<char_type>& part) {
|
||||||
|
compiled_parts.push_back(part);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const parts_container& parts() const { return compiled_parts; }
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Char, unsigned N> struct format_part_array {
|
||||||
|
format_part<Char> data[N] = {};
|
||||||
|
FMT_CONSTEXPR format_part_array() = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Char, unsigned N>
|
||||||
|
FMT_CONSTEXPR format_part_array<Char, N> compile_to_parts(
|
||||||
|
basic_string_view<Char> format_str) {
|
||||||
|
format_part_array<Char, N> parts;
|
||||||
|
unsigned counter = 0;
|
||||||
|
// This is not a lambda for compatibility with older compilers.
|
||||||
|
struct {
|
||||||
|
format_part<Char>* parts;
|
||||||
|
unsigned* counter;
|
||||||
|
FMT_CONSTEXPR void operator()(const format_part<Char>& part) {
|
||||||
|
parts[(*counter)++] = part;
|
||||||
|
}
|
||||||
|
} collector{parts.data, &counter};
|
||||||
|
compile_format_string<true>(format_str, collector);
|
||||||
|
if (counter < N) {
|
||||||
|
parts.data[counter] =
|
||||||
|
format_part<Char>::make_text(basic_string_view<Char>());
|
||||||
|
}
|
||||||
|
return parts;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T> constexpr const T& constexpr_max(const T& a, const T& b) {
|
||||||
|
return (a < b) ? b : a;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename S>
|
||||||
|
struct compiled_format_base<S, enable_if_t<is_compile_string<S>::value>>
|
||||||
|
: basic_compiled_format {
|
||||||
|
using char_type = char_t<S>;
|
||||||
|
|
||||||
|
FMT_CONSTEXPR explicit compiled_format_base(basic_string_view<char_type>) {}
|
||||||
|
|
||||||
|
// Workaround for old compilers. Format string compilation will not be
|
||||||
|
// performed there anyway.
|
||||||
#if FMT_USE_CONSTEXPR
|
#if FMT_USE_CONSTEXPR
|
||||||
static FMT_CONSTEXPR_DECL const unsigned number_of_format_parts =
|
static FMT_CONSTEXPR_DECL const unsigned num_format_parts =
|
||||||
compiletime_prepared_parts_type_provider::count_parts();
|
constexpr_max(count_parts(to_string_view(S())), 1u);
|
||||||
#else
|
#else
|
||||||
static const unsigned number_of_format_parts = 0u;
|
static const unsigned num_format_parts = 1;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
using parts_container = format_part<char_type>[num_format_parts];
|
||||||
|
|
||||||
|
const parts_container& parts() const {
|
||||||
|
static FMT_CONSTEXPR_DECL const auto compiled_parts =
|
||||||
|
compile_to_parts<char_type, num_format_parts>(
|
||||||
|
internal::to_string_view(S()));
|
||||||
|
return compiled_parts.data;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename S, typename... Args>
|
||||||
|
class compiled_format : private compiled_format_base<S> {
|
||||||
public:
|
public:
|
||||||
template <unsigned N> struct format_parts_array {
|
using typename compiled_format_base<S>::char_type;
|
||||||
using value_type = format_part<char_type>;
|
|
||||||
|
|
||||||
FMT_CONSTEXPR format_parts_array() : arr{} {}
|
|
||||||
|
|
||||||
FMT_CONSTEXPR value_type& operator[](unsigned ind) { return arr[ind]; }
|
|
||||||
|
|
||||||
FMT_CONSTEXPR const value_type* begin() const { return arr; }
|
|
||||||
FMT_CONSTEXPR const value_type* end() const { return begin() + N; }
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
value_type arr[N];
|
basic_string_view<char_type> format_str_;
|
||||||
};
|
|
||||||
|
|
||||||
struct empty {
|
template <typename Context, typename Range, typename CompiledFormat>
|
||||||
// Parts preparator will search for it
|
friend auto cf::vformat_to(Range out, CompiledFormat& cf,
|
||||||
using value_type = format_part<char_type>;
|
basic_format_args<Context> args) ->
|
||||||
};
|
typename Context::iterator;
|
||||||
|
|
||||||
using type = conditional_t<number_of_format_parts != 0,
|
|
||||||
format_parts_array<number_of_format_parts>, empty>;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename Parts> class compiletime_prepared_parts_collector {
|
|
||||||
private:
|
|
||||||
using format_part = typename Parts::value_type;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
FMT_CONSTEXPR explicit compiletime_prepared_parts_collector(Parts& parts)
|
compiled_format() = delete;
|
||||||
: parts_{parts}, counter_{0u} {}
|
explicit constexpr compiled_format(basic_string_view<char_type> format_str)
|
||||||
|
: compiled_format_base<S>(format_str), format_str_(format_str) {}
|
||||||
FMT_CONSTEXPR void push_back(format_part part) { parts_[counter_++] = part; }
|
|
||||||
|
|
||||||
FMT_CONSTEXPR format_part& back() { return parts_[counter_ - 1]; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
Parts& parts_;
|
|
||||||
unsigned counter_;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename PartsContainer, typename Char>
|
#ifdef __cpp_if_constexpr
|
||||||
FMT_CONSTEXPR PartsContainer prepare_parts(basic_string_view<Char> format) {
|
template <typename... Args> struct type_list {};
|
||||||
PartsContainer parts;
|
|
||||||
internal::parse_format_string</*IS_CONSTEXPR=*/false>(
|
// Returns a reference to the argument at index N from [first, rest...].
|
||||||
format, format_preparation_handler<Char, PartsContainer>(format, parts));
|
template <int N, typename T, typename... Args>
|
||||||
return parts;
|
constexpr const auto& get(const T& first, const Args&... rest) {
|
||||||
|
static_assert(N < 1 + sizeof...(Args), "index is out of bounds");
|
||||||
|
if constexpr (N == 0)
|
||||||
|
return first;
|
||||||
|
else
|
||||||
|
return get<N - 1>(rest...);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename PartsContainer, typename Char>
|
template <int N, typename> struct get_type_impl;
|
||||||
FMT_CONSTEXPR PartsContainer
|
|
||||||
prepare_compiletime_parts(basic_string_view<Char> format) {
|
|
||||||
using collector = compiletime_prepared_parts_collector<PartsContainer>;
|
|
||||||
|
|
||||||
PartsContainer parts;
|
template <int N, typename... Args> struct get_type_impl<N, type_list<Args...>> {
|
||||||
collector c(parts);
|
using type = remove_cvref_t<decltype(get<N>(std::declval<Args>()...))>;
|
||||||
internal::parse_format_string</*IS_CONSTEXPR=*/true>(
|
};
|
||||||
format, format_preparation_handler<Char, collector>(format, c));
|
|
||||||
return parts;
|
template <int N, typename T>
|
||||||
|
using get_type = typename get_type_impl<N, T>::type;
|
||||||
|
|
||||||
|
template <typename Char> struct text {
|
||||||
|
basic_string_view<Char> data;
|
||||||
|
using char_type = Char;
|
||||||
|
|
||||||
|
template <typename OutputIt, typename... Args>
|
||||||
|
OutputIt format(OutputIt out, const Args&...) const {
|
||||||
|
// TODO: reserve
|
||||||
|
return copy_str<Char>(data.begin(), data.end(), out);
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
template <typename PartsContainer> class runtime_parts_provider {
|
|
||||||
public:
|
|
||||||
runtime_parts_provider() = delete;
|
|
||||||
template <typename Char>
|
template <typename Char>
|
||||||
runtime_parts_provider(basic_string_view<Char> format)
|
constexpr text<Char> make_text(basic_string_view<Char> s, size_t pos,
|
||||||
: parts_(prepare_parts<PartsContainer>(format)) {}
|
size_t size) {
|
||||||
|
return {{&s[pos], size}};
|
||||||
|
}
|
||||||
|
|
||||||
const PartsContainer& parts() const { return parts_; }
|
template <typename Char, typename OutputIt, typename T,
|
||||||
|
std::enable_if_t<std::is_integral_v<T>, int> = 0>
|
||||||
|
OutputIt format_default(OutputIt out, T value) {
|
||||||
|
// TODO: reserve
|
||||||
|
format_int fi(value);
|
||||||
|
return std::copy(fi.data(), fi.data() + fi.size(), out);
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
template <typename Char, typename OutputIt>
|
||||||
PartsContainer parts_;
|
OutputIt format_default(OutputIt out, double value) {
|
||||||
};
|
writer w(out);
|
||||||
|
w.write(value);
|
||||||
|
return w.out();
|
||||||
|
}
|
||||||
|
|
||||||
template <typename Format, typename PartsContainer>
|
template <typename Char, typename OutputIt>
|
||||||
struct compiletime_parts_provider {
|
OutputIt format_default(OutputIt out, Char value) {
|
||||||
compiletime_parts_provider() = delete;
|
*out++ = value;
|
||||||
template <typename Char>
|
return out;
|
||||||
FMT_CONSTEXPR compiletime_parts_provider(basic_string_view<Char>) {}
|
}
|
||||||
|
|
||||||
const PartsContainer& parts() const {
|
template <typename Char, typename OutputIt>
|
||||||
static FMT_CONSTEXPR_DECL const PartsContainer prepared_parts =
|
OutputIt format_default(OutputIt out, const Char* value) {
|
||||||
prepare_compiletime_parts<PartsContainer>(
|
auto length = std::char_traits<Char>::length(value);
|
||||||
internal::to_string_view(Format{}));
|
return copy_str<Char>(value, value + length, out);
|
||||||
|
}
|
||||||
|
|
||||||
return prepared_parts;
|
// A replacement field that refers to argument N.
|
||||||
|
template <typename Char, typename T, int N> struct field {
|
||||||
|
using char_type = Char;
|
||||||
|
|
||||||
|
template <typename OutputIt, typename... Args>
|
||||||
|
OutputIt format(OutputIt out, const Args&... args) const {
|
||||||
|
// This ensures that the argument type is convertile to `const T&`.
|
||||||
|
const T& arg = get<N>(args...);
|
||||||
|
return format_default<Char>(out, arg);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <typename L, typename R> struct concat {
|
||||||
|
L lhs;
|
||||||
|
R rhs;
|
||||||
|
using char_type = typename L::char_type;
|
||||||
|
|
||||||
|
template <typename OutputIt, typename... Args>
|
||||||
|
OutputIt format(OutputIt out, const Args&... args) const {
|
||||||
|
out = lhs.format(out, args...);
|
||||||
|
return rhs.format(out, args...);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename L, typename R>
|
||||||
|
constexpr concat<L, R> make_concat(L lhs, R rhs) {
|
||||||
|
return {lhs, rhs};
|
||||||
|
}
|
||||||
|
|
||||||
|
struct unknown_format {};
|
||||||
|
|
||||||
|
template <typename Char>
|
||||||
|
constexpr size_t parse_text(basic_string_view<Char> str, size_t pos) {
|
||||||
|
for (size_t size = str.size(); pos != size; ++pos) {
|
||||||
|
if (str[pos] == '{' || str[pos] == '}') break;
|
||||||
|
}
|
||||||
|
return pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Args, size_t POS, int ID, typename S>
|
||||||
|
constexpr auto compile_format_string(S format_str);
|
||||||
|
|
||||||
|
template <typename Args, size_t POS, int ID, typename T, typename S>
|
||||||
|
constexpr auto parse_tail(T head, S format_str) {
|
||||||
|
if constexpr (POS != to_string_view(format_str).size()) {
|
||||||
|
constexpr auto tail = compile_format_string<Args, POS, ID>(format_str);
|
||||||
|
if constexpr (std::is_same<remove_cvref_t<decltype(tail)>,
|
||||||
|
unknown_format>())
|
||||||
|
return tail;
|
||||||
|
else
|
||||||
|
return make_concat(head, tail);
|
||||||
|
} else {
|
||||||
|
return head;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compiles a non-empty format string and returns the compiled representation
|
||||||
|
// or unknown_format() on unrecognized input.
|
||||||
|
template <typename Args, size_t POS, int ID, typename S>
|
||||||
|
constexpr auto compile_format_string(S format_str) {
|
||||||
|
using char_type = typename S::char_type;
|
||||||
|
constexpr basic_string_view<char_type> str = format_str;
|
||||||
|
if constexpr (str[POS] == '{') {
|
||||||
|
if (POS + 1 == str.size())
|
||||||
|
throw format_error("unmatched '{' in format string");
|
||||||
|
if constexpr (str[POS + 1] == '{') {
|
||||||
|
return parse_tail<Args, POS + 2, ID>(make_text(str, POS, 1), format_str);
|
||||||
|
} else if constexpr (str[POS + 1] == '}') {
|
||||||
|
using type = get_type<ID, Args>;
|
||||||
|
if constexpr (std::is_same<type, int>::value) {
|
||||||
|
return parse_tail<Args, POS + 2, ID + 1>(field<char_type, type, ID>(),
|
||||||
|
format_str);
|
||||||
|
} else {
|
||||||
|
return unknown_format();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return unknown_format();
|
||||||
|
}
|
||||||
|
} else if constexpr (str[POS] == '}') {
|
||||||
|
if (POS + 1 == str.size())
|
||||||
|
throw format_error("unmatched '}' in format string");
|
||||||
|
return parse_tail<Args, POS + 2, ID>(make_text(str, POS, 1), format_str);
|
||||||
|
} else {
|
||||||
|
constexpr auto end = parse_text(str, POS + 1);
|
||||||
|
return parse_tail<Args, end, ID>(make_text(str, POS, end - POS),
|
||||||
|
format_str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif // __cpp_if_constexpr
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
|
|
||||||
#if FMT_USE_CONSTEXPR
|
#if FMT_USE_CONSTEXPR
|
||||||
|
# ifdef __cpp_if_constexpr
|
||||||
template <typename... Args, typename S,
|
template <typename... Args, typename S,
|
||||||
FMT_ENABLE_IF(is_compile_string<S>::value)>
|
FMT_ENABLE_IF(is_compile_string<S>::value)>
|
||||||
FMT_CONSTEXPR auto compile(S format_str) -> internal::prepared_format<
|
constexpr auto compile(S format_str) {
|
||||||
S,
|
constexpr basic_string_view<typename S::char_type> str = format_str;
|
||||||
internal::compiletime_parts_provider<
|
if constexpr (str.size() == 0) {
|
||||||
S,
|
return internal::make_text(str, 0, 0);
|
||||||
typename internal::compiletime_prepared_parts_type_provider<S>::type>,
|
} else {
|
||||||
Args...> {
|
constexpr auto result =
|
||||||
return format_str;
|
internal::compile_format_string<internal::type_list<Args...>, 0, 0>(
|
||||||
|
format_str);
|
||||||
|
if constexpr (std::is_same<remove_cvref_t<decltype(result)>,
|
||||||
|
internal::unknown_format>()) {
|
||||||
|
return internal::compiled_format<S, Args...>(to_string_view(format_str));
|
||||||
|
} else {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
template <typename... Args, typename Char, size_t N>
|
|
||||||
auto compile(const Char (&format_str)[N]) -> internal::prepared_format<
|
|
||||||
std::basic_string<Char>,
|
|
||||||
internal::runtime_parts_provider<std::vector<internal::format_part<Char>>>,
|
|
||||||
Args...> {
|
|
||||||
return std::basic_string<Char>(format_str, N - 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename CompiledFormat, typename... Args,
|
template <typename CompiledFormat, typename... Args,
|
||||||
typename Char = typename CompiledFormat::char_type>
|
typename Char = typename CompiledFormat::char_type,
|
||||||
|
FMT_ENABLE_IF(!std::is_base_of<internal::basic_compiled_format,
|
||||||
|
CompiledFormat>::value)>
|
||||||
std::basic_string<Char> format(const CompiledFormat& cf, const Args&... args) {
|
std::basic_string<Char> format(const CompiledFormat& cf, const Args&... args) {
|
||||||
basic_memory_buffer<Char> buffer;
|
basic_memory_buffer<Char> buffer;
|
||||||
using range = internal::buffer_range<Char>;
|
using range = buffer_range<Char>;
|
||||||
using context = buffer_context<Char>;
|
using context = buffer_context<Char>;
|
||||||
cf.template vformat_to<range, context>(range(buffer),
|
cf.format(std::back_inserter(buffer), args...);
|
||||||
|
return to_string(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename OutputIt, typename CompiledFormat, typename... Args,
|
||||||
|
FMT_ENABLE_IF(!std::is_base_of<internal::basic_compiled_format,
|
||||||
|
CompiledFormat>::value)>
|
||||||
|
OutputIt format_to(OutputIt out, const CompiledFormat& cf,
|
||||||
|
const Args&... args) {
|
||||||
|
return cf.format(out, args...);
|
||||||
|
}
|
||||||
|
# else
|
||||||
|
template <typename... Args, typename S,
|
||||||
|
FMT_ENABLE_IF(is_compile_string<S>::value)>
|
||||||
|
constexpr auto compile(S format_str) -> internal::compiled_format<S, Args...> {
|
||||||
|
return internal::compiled_format<S, Args...>(to_string_view(format_str));
|
||||||
|
}
|
||||||
|
# endif // __cpp_if_constexpr
|
||||||
|
#endif // FMT_USE_CONSTEXPR
|
||||||
|
|
||||||
|
// Compiles the format string which must be a string literal.
|
||||||
|
template <typename... Args, typename Char, size_t N>
|
||||||
|
auto compile(const Char (&format_str)[N])
|
||||||
|
-> internal::compiled_format<const Char*, Args...> {
|
||||||
|
return internal::compiled_format<const Char*, Args...>(
|
||||||
|
basic_string_view<Char>(format_str, N - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename CompiledFormat, typename... Args,
|
||||||
|
typename Char = typename CompiledFormat::char_type,
|
||||||
|
FMT_ENABLE_IF(std::is_base_of<internal::basic_compiled_format,
|
||||||
|
CompiledFormat>::value)>
|
||||||
|
std::basic_string<Char> format(const CompiledFormat& cf, const Args&... args) {
|
||||||
|
basic_memory_buffer<Char> buffer;
|
||||||
|
using range = buffer_range<Char>;
|
||||||
|
using context = buffer_context<Char>;
|
||||||
|
internal::cf::vformat_to<context>(range(buffer), cf,
|
||||||
{make_format_args<context>(args...)});
|
{make_format_args<context>(args...)});
|
||||||
return to_string(buffer);
|
return to_string(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename OutputIt, typename CompiledFormat, typename... Args>
|
template <typename OutputIt, typename CompiledFormat, typename... Args,
|
||||||
|
FMT_ENABLE_IF(std::is_base_of<internal::basic_compiled_format,
|
||||||
|
CompiledFormat>::value)>
|
||||||
OutputIt format_to(OutputIt out, const CompiledFormat& cf,
|
OutputIt format_to(OutputIt out, const CompiledFormat& cf,
|
||||||
const Args&... args) {
|
const Args&... args) {
|
||||||
using char_type = typename CompiledFormat::char_type;
|
using char_type = typename CompiledFormat::char_type;
|
||||||
using range = internal::output_range<OutputIt, char_type>;
|
using range = internal::output_range<OutputIt, char_type>;
|
||||||
using context = format_context_t<OutputIt, char_type>;
|
using context = format_context_t<OutputIt, char_type>;
|
||||||
return cf.template vformat_to<range, context>(
|
return internal::cf::vformat_to<context>(
|
||||||
range(out), {make_format_args<context>(args...)});
|
range(out), cf, {make_format_args<context>(args...)});
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename OutputIt, typename CompiledFormat, typename... Args,
|
template <typename OutputIt, typename CompiledFormat, typename... Args,
|
||||||
@ -455,10 +579,7 @@ format_to_n_result<OutputIt> format_to_n(OutputIt out, size_t n,
|
|||||||
|
|
||||||
template <typename CompiledFormat, typename... Args>
|
template <typename CompiledFormat, typename... Args>
|
||||||
std::size_t formatted_size(const CompiledFormat& cf, const Args&... args) {
|
std::size_t formatted_size(const CompiledFormat& cf, const Args&... args) {
|
||||||
return fmt::format_to(
|
return format_to(internal::counting_iterator(), cf, args...).count();
|
||||||
internal::counting_iterator<typename CompiledFormat::char_type>(),
|
|
||||||
cf, args...)
|
|
||||||
.count();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FMT_END_NAMESPACE
|
FMT_END_NAMESPACE
|
||||||
|
241
third_party/spdlog/include/spdlog/fmt/bundled/core.h
vendored
241
third_party/spdlog/include/spdlog/fmt/bundled/core.h
vendored
@ -8,7 +8,6 @@
|
|||||||
#ifndef FMT_CORE_H_
|
#ifndef FMT_CORE_H_
|
||||||
#define FMT_CORE_H_
|
#define FMT_CORE_H_
|
||||||
|
|
||||||
#include <cassert>
|
|
||||||
#include <cstdio> // std::FILE
|
#include <cstdio> // std::FILE
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
@ -16,7 +15,7 @@
|
|||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
|
||||||
// The fmt library version in the form major * 10000 + minor * 100 + patch.
|
// The fmt library version in the form major * 10000 + minor * 100 + patch.
|
||||||
#define FMT_VERSION 60000
|
#define FMT_VERSION 60101
|
||||||
|
|
||||||
#ifdef __has_feature
|
#ifdef __has_feature
|
||||||
# define FMT_HAS_FEATURE(x) __has_feature(x)
|
# define FMT_HAS_FEATURE(x) __has_feature(x)
|
||||||
@ -49,6 +48,12 @@
|
|||||||
# define FMT_HAS_GXX_CXX11 0
|
# define FMT_HAS_GXX_CXX11 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef __NVCC__
|
||||||
|
# define FMT_NVCC __NVCC__
|
||||||
|
#else
|
||||||
|
# define FMT_NVCC 0
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
# define FMT_MSC_VER _MSC_VER
|
# define FMT_MSC_VER _MSC_VER
|
||||||
#else
|
#else
|
||||||
@ -60,7 +65,8 @@
|
|||||||
#ifndef FMT_USE_CONSTEXPR
|
#ifndef FMT_USE_CONSTEXPR
|
||||||
# define FMT_USE_CONSTEXPR \
|
# define FMT_USE_CONSTEXPR \
|
||||||
(FMT_HAS_FEATURE(cxx_relaxed_constexpr) || FMT_MSC_VER >= 1910 || \
|
(FMT_HAS_FEATURE(cxx_relaxed_constexpr) || FMT_MSC_VER >= 1910 || \
|
||||||
(FMT_GCC_VERSION >= 600 && __cplusplus >= 201402L))
|
(FMT_GCC_VERSION >= 600 && __cplusplus >= 201402L)) && \
|
||||||
|
!FMT_NVCC
|
||||||
#endif
|
#endif
|
||||||
#if FMT_USE_CONSTEXPR
|
#if FMT_USE_CONSTEXPR
|
||||||
# define FMT_CONSTEXPR constexpr
|
# define FMT_CONSTEXPR constexpr
|
||||||
@ -133,6 +139,13 @@
|
|||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Workaround broken [[deprecated]] in the Intel compiler and NVCC.
|
||||||
|
#if defined(__INTEL_COMPILER) || FMT_NVCC
|
||||||
|
# define FMT_DEPRECATED_ALIAS
|
||||||
|
#else
|
||||||
|
# define FMT_DEPRECATED_ALIAS FMT_DEPRECATED
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef FMT_BEGIN_NAMESPACE
|
#ifndef FMT_BEGIN_NAMESPACE
|
||||||
# if FMT_HAS_FEATURE(cxx_inline_namespaces) || FMT_GCC_VERSION >= 404 || \
|
# if FMT_HAS_FEATURE(cxx_inline_namespaces) || FMT_GCC_VERSION >= 404 || \
|
||||||
FMT_MSC_VER >= 1900
|
FMT_MSC_VER >= 1900
|
||||||
@ -173,10 +186,6 @@
|
|||||||
# define FMT_EXTERN
|
# define FMT_EXTERN
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef FMT_ASSERT
|
|
||||||
# define FMT_ASSERT(condition, message) assert((condition) && message)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// libc++ supports string_view in pre-c++17.
|
// libc++ supports string_view in pre-c++17.
|
||||||
#if (FMT_HAS_INCLUDE(<string_view>) && \
|
#if (FMT_HAS_INCLUDE(<string_view>) && \
|
||||||
(__cplusplus > 201402L || defined(_LIBCPP_VERSION))) || \
|
(__cplusplus > 201402L || defined(_LIBCPP_VERSION))) || \
|
||||||
@ -200,6 +209,8 @@ template <typename T>
|
|||||||
using remove_reference_t = typename std::remove_reference<T>::type;
|
using remove_reference_t = typename std::remove_reference<T>::type;
|
||||||
template <typename T>
|
template <typename T>
|
||||||
using remove_const_t = typename std::remove_const<T>::type;
|
using remove_const_t = typename std::remove_const<T>::type;
|
||||||
|
template <typename T>
|
||||||
|
using remove_cvref_t = typename std::remove_cv<remove_reference_t<T>>::type;
|
||||||
|
|
||||||
struct monostate {};
|
struct monostate {};
|
||||||
|
|
||||||
@ -213,6 +224,19 @@ namespace internal {
|
|||||||
// A workaround for gcc 4.8 to make void_t work in a SFINAE context.
|
// A workaround for gcc 4.8 to make void_t work in a SFINAE context.
|
||||||
template <typename... Ts> struct void_t_impl { using type = void; };
|
template <typename... Ts> struct void_t_impl { using type = void; };
|
||||||
|
|
||||||
|
FMT_API void assert_fail(const char* file, int line, const char* message);
|
||||||
|
|
||||||
|
#ifndef FMT_ASSERT
|
||||||
|
# ifdef NDEBUG
|
||||||
|
# define FMT_ASSERT(condition, message)
|
||||||
|
# else
|
||||||
|
# define FMT_ASSERT(condition, message) \
|
||||||
|
((condition) \
|
||||||
|
? void() \
|
||||||
|
: fmt::internal::assert_fail(__FILE__, __LINE__, (message)))
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(FMT_USE_STRING_VIEW)
|
#if defined(FMT_USE_STRING_VIEW)
|
||||||
template <typename Char> using std_string_view = std::basic_string_view<Char>;
|
template <typename Char> using std_string_view = std::basic_string_view<Char>;
|
||||||
#elif defined(FMT_USE_EXPERIMENTAL_STRING_VIEW)
|
#elif defined(FMT_USE_EXPERIMENTAL_STRING_VIEW)
|
||||||
@ -222,7 +246,21 @@ using std_string_view = std::experimental::basic_string_view<Char>;
|
|||||||
template <typename T> struct std_string_view {};
|
template <typename T> struct std_string_view {};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Casts nonnegative integer to unsigned.
|
#ifdef FMT_USE_INT128
|
||||||
|
// Do nothing.
|
||||||
|
#elif defined(__SIZEOF_INT128__)
|
||||||
|
# define FMT_USE_INT128 1
|
||||||
|
using int128_t = __int128_t;
|
||||||
|
using uint128_t = __uint128_t;
|
||||||
|
#else
|
||||||
|
# define FMT_USE_INT128 0
|
||||||
|
#endif
|
||||||
|
#if !FMT_USE_INT128
|
||||||
|
struct int128_t {};
|
||||||
|
struct uint128_t {};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Casts a nonnegative integer to unsigned.
|
||||||
template <typename Int>
|
template <typename Int>
|
||||||
FMT_CONSTEXPR typename std::make_unsigned<Int>::type to_unsigned(Int value) {
|
FMT_CONSTEXPR typename std::make_unsigned<Int>::type to_unsigned(Int value) {
|
||||||
FMT_ASSERT(value >= 0, "negative value");
|
FMT_ASSERT(value >= 0, "negative value");
|
||||||
@ -266,9 +304,10 @@ template <typename Char> class basic_string_view {
|
|||||||
: data_(s), size_(std::char_traits<Char>::length(s)) {}
|
: data_(s), size_(std::char_traits<Char>::length(s)) {}
|
||||||
|
|
||||||
/** Constructs a string reference from a ``std::basic_string`` object. */
|
/** Constructs a string reference from a ``std::basic_string`` object. */
|
||||||
template <typename Alloc>
|
template <typename Traits, typename Alloc>
|
||||||
FMT_CONSTEXPR basic_string_view(const std::basic_string<Char, Alloc>& s)
|
FMT_CONSTEXPR basic_string_view(
|
||||||
FMT_NOEXCEPT : data_(s.data()),
|
const std::basic_string<Char, Traits, Alloc>& s) FMT_NOEXCEPT
|
||||||
|
: data_(s.data()),
|
||||||
size_(s.size()) {}
|
size_(s.size()) {}
|
||||||
|
|
||||||
template <
|
template <
|
||||||
@ -286,6 +325,8 @@ template <typename Char> class basic_string_view {
|
|||||||
FMT_CONSTEXPR iterator begin() const { return data_; }
|
FMT_CONSTEXPR iterator begin() const { return data_; }
|
||||||
FMT_CONSTEXPR iterator end() const { return data_ + size_; }
|
FMT_CONSTEXPR iterator end() const { return data_ + size_; }
|
||||||
|
|
||||||
|
FMT_CONSTEXPR const Char& operator[](size_t pos) const { return data_[pos]; }
|
||||||
|
|
||||||
FMT_CONSTEXPR void remove_prefix(size_t n) {
|
FMT_CONSTEXPR void remove_prefix(size_t n) {
|
||||||
data_ += n;
|
data_ += n;
|
||||||
size_ -= n;
|
size_ -= n;
|
||||||
@ -357,10 +398,10 @@ inline basic_string_view<Char> to_string_view(const Char* s) {
|
|||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Char, typename Traits, typename Allocator>
|
template <typename Char, typename Traits, typename Alloc>
|
||||||
inline basic_string_view<Char> to_string_view(
|
inline basic_string_view<Char> to_string_view(
|
||||||
const std::basic_string<Char, Traits, Allocator>& s) {
|
const std::basic_string<Char, Traits, Alloc>& s) {
|
||||||
return {s.data(), s.size()};
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Char>
|
template <typename Char>
|
||||||
@ -405,8 +446,8 @@ template <typename S> struct char_t_impl<S, enable_if_t<is_string<S>::value>> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct error_handler {
|
struct error_handler {
|
||||||
FMT_CONSTEXPR error_handler() {}
|
FMT_CONSTEXPR error_handler() = default;
|
||||||
FMT_CONSTEXPR error_handler(const error_handler&) {}
|
FMT_CONSTEXPR error_handler(const error_handler&) = default;
|
||||||
|
|
||||||
// This function is intentionally not constexpr to give a compile-time error.
|
// This function is intentionally not constexpr to give a compile-time error.
|
||||||
FMT_NORETURN FMT_API void on_error(const char* message);
|
FMT_NORETURN FMT_API void on_error(const char* message);
|
||||||
@ -416,10 +457,24 @@ struct error_handler {
|
|||||||
/** String's character type. */
|
/** String's character type. */
|
||||||
template <typename S> using char_t = typename internal::char_t_impl<S>::type;
|
template <typename S> using char_t = typename internal::char_t_impl<S>::type;
|
||||||
|
|
||||||
// Parsing context consisting of a format string range being parsed and an
|
/**
|
||||||
// argument counter for automatic indexing.
|
\rst
|
||||||
|
Parsing context consisting of a format string range being parsed and an
|
||||||
|
argument counter for automatic indexing.
|
||||||
|
|
||||||
|
You can use one of the following type aliases for common character types:
|
||||||
|
|
||||||
|
+-----------------------+-------------------------------------+
|
||||||
|
| Type | Definition |
|
||||||
|
+=======================+=====================================+
|
||||||
|
| format_parse_context | basic_format_parse_context<char> |
|
||||||
|
+-----------------------+-------------------------------------+
|
||||||
|
| wformat_parse_context | basic_format_parse_context<wchar_t> |
|
||||||
|
+-----------------------+-------------------------------------+
|
||||||
|
\endrst
|
||||||
|
*/
|
||||||
template <typename Char, typename ErrorHandler = internal::error_handler>
|
template <typename Char, typename ErrorHandler = internal::error_handler>
|
||||||
class basic_parse_context : private ErrorHandler {
|
class basic_format_parse_context : private ErrorHandler {
|
||||||
private:
|
private:
|
||||||
basic_string_view<Char> format_str_;
|
basic_string_view<Char> format_str_;
|
||||||
int next_arg_id_;
|
int next_arg_id_;
|
||||||
@ -428,38 +483,47 @@ class basic_parse_context : private ErrorHandler {
|
|||||||
using char_type = Char;
|
using char_type = Char;
|
||||||
using iterator = typename basic_string_view<Char>::iterator;
|
using iterator = typename basic_string_view<Char>::iterator;
|
||||||
|
|
||||||
explicit FMT_CONSTEXPR basic_parse_context(basic_string_view<Char> format_str,
|
explicit FMT_CONSTEXPR basic_format_parse_context(
|
||||||
ErrorHandler eh = ErrorHandler())
|
basic_string_view<Char> format_str, ErrorHandler eh = ErrorHandler())
|
||||||
: ErrorHandler(eh), format_str_(format_str), next_arg_id_(0) {}
|
: ErrorHandler(eh), format_str_(format_str), next_arg_id_(0) {}
|
||||||
|
|
||||||
// Returns an iterator to the beginning of the format string range being
|
/**
|
||||||
// parsed.
|
Returns an iterator to the beginning of the format string range being
|
||||||
|
parsed.
|
||||||
|
*/
|
||||||
FMT_CONSTEXPR iterator begin() const FMT_NOEXCEPT {
|
FMT_CONSTEXPR iterator begin() const FMT_NOEXCEPT {
|
||||||
return format_str_.begin();
|
return format_str_.begin();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns an iterator past the end of the format string range being parsed.
|
/**
|
||||||
|
Returns an iterator past the end of the format string range being parsed.
|
||||||
|
*/
|
||||||
FMT_CONSTEXPR iterator end() const FMT_NOEXCEPT { return format_str_.end(); }
|
FMT_CONSTEXPR iterator end() const FMT_NOEXCEPT { return format_str_.end(); }
|
||||||
|
|
||||||
// Advances the begin iterator to ``it``.
|
/** Advances the begin iterator to ``it``. */
|
||||||
FMT_CONSTEXPR void advance_to(iterator it) {
|
FMT_CONSTEXPR void advance_to(iterator it) {
|
||||||
format_str_.remove_prefix(internal::to_unsigned(it - begin()));
|
format_str_.remove_prefix(internal::to_unsigned(it - begin()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns the next argument index.
|
/**
|
||||||
|
Reports an error if using the manual argument indexing; otherwise returns
|
||||||
|
the next argument index and switches to the automatic indexing.
|
||||||
|
*/
|
||||||
FMT_CONSTEXPR int next_arg_id() {
|
FMT_CONSTEXPR int next_arg_id() {
|
||||||
if (next_arg_id_ >= 0) return next_arg_id_++;
|
if (next_arg_id_ >= 0) return next_arg_id_++;
|
||||||
on_error("cannot switch from manual to automatic argument indexing");
|
on_error("cannot switch from manual to automatic argument indexing");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
FMT_CONSTEXPR bool check_arg_id(int) {
|
/**
|
||||||
if (next_arg_id_ > 0) {
|
Reports an error if using the automatic argument indexing; otherwise
|
||||||
|
switches to the manual indexing.
|
||||||
|
*/
|
||||||
|
FMT_CONSTEXPR void check_arg_id(int) {
|
||||||
|
if (next_arg_id_ > 0)
|
||||||
on_error("cannot switch from automatic to manual argument indexing");
|
on_error("cannot switch from automatic to manual argument indexing");
|
||||||
return false;
|
else
|
||||||
}
|
|
||||||
next_arg_id_ = -1;
|
next_arg_id_ = -1;
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FMT_CONSTEXPR void check_arg_id(basic_string_view<Char>) {}
|
FMT_CONSTEXPR void check_arg_id(basic_string_view<Char>) {}
|
||||||
@ -471,11 +535,14 @@ class basic_parse_context : private ErrorHandler {
|
|||||||
FMT_CONSTEXPR ErrorHandler error_handler() const { return *this; }
|
FMT_CONSTEXPR ErrorHandler error_handler() const { return *this; }
|
||||||
};
|
};
|
||||||
|
|
||||||
using format_parse_context = basic_parse_context<char>;
|
using format_parse_context = basic_format_parse_context<char>;
|
||||||
using wformat_parse_context = basic_parse_context<wchar_t>;
|
using wformat_parse_context = basic_format_parse_context<wchar_t>;
|
||||||
|
|
||||||
using parse_context FMT_DEPRECATED = basic_parse_context<char>;
|
template <typename Char, typename ErrorHandler = internal::error_handler>
|
||||||
using wparse_context FMT_DEPRECATED = basic_parse_context<wchar_t>;
|
using basic_parse_context FMT_DEPRECATED_ALIAS =
|
||||||
|
basic_format_parse_context<Char, ErrorHandler>;
|
||||||
|
using parse_context FMT_DEPRECATED_ALIAS = basic_format_parse_context<char>;
|
||||||
|
using wparse_context FMT_DEPRECATED_ALIAS = basic_format_parse_context<wchar_t>;
|
||||||
|
|
||||||
template <typename Context> class basic_format_arg;
|
template <typename Context> class basic_format_arg;
|
||||||
template <typename Context> class basic_format_args;
|
template <typename Context> class basic_format_args;
|
||||||
@ -492,20 +559,17 @@ struct FMT_DEPRECATED convert_to_int
|
|||||||
: bool_constant<!std::is_arithmetic<T>::value &&
|
: bool_constant<!std::is_arithmetic<T>::value &&
|
||||||
std::is_convertible<T, int>::value> {};
|
std::is_convertible<T, int>::value> {};
|
||||||
|
|
||||||
namespace internal {
|
|
||||||
|
|
||||||
// Specifies if T has an enabled formatter specialization. A type can be
|
// Specifies if T has an enabled formatter specialization. A type can be
|
||||||
// formattable even if it doesn't have a formatter e.g. via a conversion.
|
// formattable even if it doesn't have a formatter e.g. via a conversion.
|
||||||
template <typename T, typename Context>
|
template <typename T, typename Context>
|
||||||
using has_formatter =
|
using has_formatter =
|
||||||
std::is_constructible<typename Context::template formatter_type<T>>;
|
std::is_constructible<typename Context::template formatter_type<T>>;
|
||||||
|
|
||||||
|
namespace internal {
|
||||||
|
|
||||||
/** A contiguous memory buffer with an optional growing ability. */
|
/** A contiguous memory buffer with an optional growing ability. */
|
||||||
template <typename T> class buffer {
|
template <typename T> class buffer {
|
||||||
private:
|
private:
|
||||||
buffer(const buffer&) = delete;
|
|
||||||
void operator=(const buffer&) = delete;
|
|
||||||
|
|
||||||
T* ptr_;
|
T* ptr_;
|
||||||
std::size_t size_;
|
std::size_t size_;
|
||||||
std::size_t capacity_;
|
std::size_t capacity_;
|
||||||
@ -532,7 +596,9 @@ template <typename T> class buffer {
|
|||||||
using value_type = T;
|
using value_type = T;
|
||||||
using const_reference = const T&;
|
using const_reference = const T&;
|
||||||
|
|
||||||
virtual ~buffer() {}
|
buffer(const buffer&) = delete;
|
||||||
|
void operator=(const buffer&) = delete;
|
||||||
|
virtual ~buffer() = default;
|
||||||
|
|
||||||
T* begin() FMT_NOEXCEPT { return ptr_; }
|
T* begin() FMT_NOEXCEPT { return ptr_; }
|
||||||
T* end() FMT_NOEXCEPT { return ptr_ + size_; }
|
T* end() FMT_NOEXCEPT { return ptr_ + size_; }
|
||||||
@ -626,10 +692,13 @@ enum type {
|
|||||||
uint_type,
|
uint_type,
|
||||||
long_long_type,
|
long_long_type,
|
||||||
ulong_long_type,
|
ulong_long_type,
|
||||||
|
int128_type,
|
||||||
|
uint128_type,
|
||||||
bool_type,
|
bool_type,
|
||||||
char_type,
|
char_type,
|
||||||
last_integer_type = char_type,
|
last_integer_type = char_type,
|
||||||
// followed by floating-point types.
|
// followed by floating-point types.
|
||||||
|
float_type,
|
||||||
double_type,
|
double_type,
|
||||||
long_double_type,
|
long_double_type,
|
||||||
last_numeric_type = long_double_type,
|
last_numeric_type = long_double_type,
|
||||||
@ -652,20 +721,23 @@ FMT_TYPE_CONSTANT(int, int_type);
|
|||||||
FMT_TYPE_CONSTANT(unsigned, uint_type);
|
FMT_TYPE_CONSTANT(unsigned, uint_type);
|
||||||
FMT_TYPE_CONSTANT(long long, long_long_type);
|
FMT_TYPE_CONSTANT(long long, long_long_type);
|
||||||
FMT_TYPE_CONSTANT(unsigned long long, ulong_long_type);
|
FMT_TYPE_CONSTANT(unsigned long long, ulong_long_type);
|
||||||
|
FMT_TYPE_CONSTANT(int128_t, int128_type);
|
||||||
|
FMT_TYPE_CONSTANT(uint128_t, uint128_type);
|
||||||
FMT_TYPE_CONSTANT(bool, bool_type);
|
FMT_TYPE_CONSTANT(bool, bool_type);
|
||||||
FMT_TYPE_CONSTANT(Char, char_type);
|
FMT_TYPE_CONSTANT(Char, char_type);
|
||||||
|
FMT_TYPE_CONSTANT(float, float_type);
|
||||||
FMT_TYPE_CONSTANT(double, double_type);
|
FMT_TYPE_CONSTANT(double, double_type);
|
||||||
FMT_TYPE_CONSTANT(long double, long_double_type);
|
FMT_TYPE_CONSTANT(long double, long_double_type);
|
||||||
FMT_TYPE_CONSTANT(const Char*, cstring_type);
|
FMT_TYPE_CONSTANT(const Char*, cstring_type);
|
||||||
FMT_TYPE_CONSTANT(basic_string_view<Char>, string_type);
|
FMT_TYPE_CONSTANT(basic_string_view<Char>, string_type);
|
||||||
FMT_TYPE_CONSTANT(const void*, pointer_type);
|
FMT_TYPE_CONSTANT(const void*, pointer_type);
|
||||||
|
|
||||||
FMT_CONSTEXPR bool is_integral(type t) {
|
FMT_CONSTEXPR bool is_integral_type(type t) {
|
||||||
FMT_ASSERT(t != named_arg_type, "invalid argument type");
|
FMT_ASSERT(t != named_arg_type, "invalid argument type");
|
||||||
return t > none_type && t <= last_integer_type;
|
return t > none_type && t <= last_integer_type;
|
||||||
}
|
}
|
||||||
|
|
||||||
FMT_CONSTEXPR bool is_arithmetic(type t) {
|
FMT_CONSTEXPR bool is_arithmetic_type(type t) {
|
||||||
FMT_ASSERT(t != named_arg_type, "invalid argument type");
|
FMT_ASSERT(t != named_arg_type, "invalid argument type");
|
||||||
return t > none_type && t <= last_numeric_type;
|
return t > none_type && t <= last_numeric_type;
|
||||||
}
|
}
|
||||||
@ -676,7 +748,7 @@ template <typename Char> struct string_value {
|
|||||||
};
|
};
|
||||||
|
|
||||||
template <typename Context> struct custom_value {
|
template <typename Context> struct custom_value {
|
||||||
using parse_context = basic_parse_context<typename Context::char_type>;
|
using parse_context = basic_format_parse_context<typename Context::char_type>;
|
||||||
const void* value;
|
const void* value;
|
||||||
void (*format)(const void* arg, parse_context& parse_ctx, Context& ctx);
|
void (*format)(const void* arg, parse_context& parse_ctx, Context& ctx);
|
||||||
};
|
};
|
||||||
@ -691,8 +763,11 @@ template <typename Context> class value {
|
|||||||
unsigned uint_value;
|
unsigned uint_value;
|
||||||
long long long_long_value;
|
long long long_long_value;
|
||||||
unsigned long long ulong_long_value;
|
unsigned long long ulong_long_value;
|
||||||
|
int128_t int128_value;
|
||||||
|
uint128_t uint128_value;
|
||||||
bool bool_value;
|
bool bool_value;
|
||||||
char_type char_value;
|
char_type char_value;
|
||||||
|
float float_value;
|
||||||
double double_value;
|
double double_value;
|
||||||
long double long_double_value;
|
long double long_double_value;
|
||||||
const void* pointer;
|
const void* pointer;
|
||||||
@ -705,6 +780,9 @@ template <typename Context> class value {
|
|||||||
FMT_CONSTEXPR value(unsigned val) : uint_value(val) {}
|
FMT_CONSTEXPR value(unsigned val) : uint_value(val) {}
|
||||||
value(long long val) : long_long_value(val) {}
|
value(long long val) : long_long_value(val) {}
|
||||||
value(unsigned long long val) : ulong_long_value(val) {}
|
value(unsigned long long val) : ulong_long_value(val) {}
|
||||||
|
value(int128_t val) : int128_value(val) {}
|
||||||
|
value(uint128_t val) : uint128_value(val) {}
|
||||||
|
value(float val) : float_value(val) {}
|
||||||
value(double val) : double_value(val) {}
|
value(double val) : double_value(val) {}
|
||||||
value(long double val) : long_double_value(val) {}
|
value(long double val) : long_double_value(val) {}
|
||||||
value(bool val) : bool_value(val) {}
|
value(bool val) : bool_value(val) {}
|
||||||
@ -732,8 +810,8 @@ template <typename Context> class value {
|
|||||||
private:
|
private:
|
||||||
// Formats an argument of a custom type, such as a user-defined class.
|
// Formats an argument of a custom type, such as a user-defined class.
|
||||||
template <typename T, typename Formatter>
|
template <typename T, typename Formatter>
|
||||||
static void format_custom_arg(const void* arg,
|
static void format_custom_arg(
|
||||||
basic_parse_context<char_type>& parse_ctx,
|
const void* arg, basic_format_parse_context<char_type>& parse_ctx,
|
||||||
Context& ctx) {
|
Context& ctx) {
|
||||||
Formatter f;
|
Formatter f;
|
||||||
parse_ctx.advance_to(f.parse(parse_ctx));
|
parse_ctx.advance_to(f.parse(parse_ctx));
|
||||||
@ -764,6 +842,8 @@ template <typename Context> struct arg_mapper {
|
|||||||
FMT_CONSTEXPR ulong_type map(unsigned long val) { return val; }
|
FMT_CONSTEXPR ulong_type map(unsigned long val) { return val; }
|
||||||
FMT_CONSTEXPR long long map(long long val) { return val; }
|
FMT_CONSTEXPR long long map(long long val) { return val; }
|
||||||
FMT_CONSTEXPR unsigned long long map(unsigned long long val) { return val; }
|
FMT_CONSTEXPR unsigned long long map(unsigned long long val) { return val; }
|
||||||
|
FMT_CONSTEXPR int128_t map(int128_t val) { return val; }
|
||||||
|
FMT_CONSTEXPR uint128_t map(uint128_t val) { return val; }
|
||||||
FMT_CONSTEXPR bool map(bool val) { return val; }
|
FMT_CONSTEXPR bool map(bool val) { return val; }
|
||||||
|
|
||||||
template <typename T, FMT_ENABLE_IF(is_char<T>::value)>
|
template <typename T, FMT_ENABLE_IF(is_char<T>::value)>
|
||||||
@ -774,7 +854,7 @@ template <typename Context> struct arg_mapper {
|
|||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
FMT_CONSTEXPR double map(float val) { return static_cast<double>(val); }
|
FMT_CONSTEXPR float map(float val) { return val; }
|
||||||
FMT_CONSTEXPR double map(double val) { return val; }
|
FMT_CONSTEXPR double map(double val) { return val; }
|
||||||
FMT_CONSTEXPR long double map(long double val) { return val; }
|
FMT_CONSTEXPR long double map(long double val) { return val; }
|
||||||
|
|
||||||
@ -793,6 +873,15 @@ template <typename Context> struct arg_mapper {
|
|||||||
FMT_CONSTEXPR basic_string_view<char_type> map(const T& val) {
|
FMT_CONSTEXPR basic_string_view<char_type> map(const T& val) {
|
||||||
return basic_string_view<char_type>(val);
|
return basic_string_view<char_type>(val);
|
||||||
}
|
}
|
||||||
|
template <
|
||||||
|
typename T,
|
||||||
|
FMT_ENABLE_IF(
|
||||||
|
std::is_constructible<std_string_view<char_type>, T>::value &&
|
||||||
|
!std::is_constructible<basic_string_view<char_type>, T>::value &&
|
||||||
|
!is_string<T>::value)>
|
||||||
|
FMT_CONSTEXPR basic_string_view<char_type> map(const T& val) {
|
||||||
|
return std_string_view<char_type>(val);
|
||||||
|
}
|
||||||
FMT_CONSTEXPR const char* map(const signed char* val) {
|
FMT_CONSTEXPR const char* map(const signed char* val) {
|
||||||
static_assert(std::is_same<char_type, char>::value, "invalid string type");
|
static_assert(std::is_same<char_type, char>::value, "invalid string type");
|
||||||
return reinterpret_cast<const char*>(val);
|
return reinterpret_cast<const char*>(val);
|
||||||
@ -818,11 +907,14 @@ template <typename Context> struct arg_mapper {
|
|||||||
FMT_ENABLE_IF(std::is_enum<T>::value &&
|
FMT_ENABLE_IF(std::is_enum<T>::value &&
|
||||||
!has_formatter<T, Context>::value &&
|
!has_formatter<T, Context>::value &&
|
||||||
!has_fallback_formatter<T, Context>::value)>
|
!has_fallback_formatter<T, Context>::value)>
|
||||||
FMT_CONSTEXPR int map(const T& val) {
|
FMT_CONSTEXPR auto map(const T& val) -> decltype(
|
||||||
return static_cast<int>(val);
|
map(static_cast<typename std::underlying_type<T>::type>(val))) {
|
||||||
|
return map(static_cast<typename std::underlying_type<T>::type>(val));
|
||||||
}
|
}
|
||||||
template <typename T,
|
template <typename T,
|
||||||
FMT_ENABLE_IF(!is_string<T>::value && !is_char<T>::value &&
|
FMT_ENABLE_IF(!is_string<T>::value && !is_char<T>::value &&
|
||||||
|
!std::is_constructible<basic_string_view<char_type>,
|
||||||
|
T>::value &&
|
||||||
(has_formatter<T, Context>::value ||
|
(has_formatter<T, Context>::value ||
|
||||||
has_fallback_formatter<T, Context>::value))>
|
has_fallback_formatter<T, Context>::value))>
|
||||||
FMT_CONSTEXPR const T& map(const T& val) {
|
FMT_CONSTEXPR const T& map(const T& val) {
|
||||||
@ -841,12 +933,13 @@ template <typename Context> struct arg_mapper {
|
|||||||
// A type constant after applying arg_mapper<Context>.
|
// A type constant after applying arg_mapper<Context>.
|
||||||
template <typename T, typename Context>
|
template <typename T, typename Context>
|
||||||
using mapped_type_constant =
|
using mapped_type_constant =
|
||||||
type_constant<decltype(arg_mapper<Context>().map(std::declval<T>())),
|
type_constant<decltype(arg_mapper<Context>().map(std::declval<const T&>())),
|
||||||
typename Context::char_type>;
|
typename Context::char_type>;
|
||||||
|
|
||||||
|
enum { packed_arg_bits = 5 };
|
||||||
// Maximum number of arguments with packed types.
|
// Maximum number of arguments with packed types.
|
||||||
enum { max_packed_args = 15 };
|
enum { max_packed_args = 63 / packed_arg_bits };
|
||||||
enum : unsigned long long { is_unpacked_bit = 1ull << 63 };
|
enum : unsigned long long { is_unpacked_bit = 1ULL << 63 };
|
||||||
|
|
||||||
template <typename Context> class arg_map;
|
template <typename Context> class arg_map;
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
@ -877,7 +970,8 @@ template <typename Context> class basic_format_arg {
|
|||||||
public:
|
public:
|
||||||
explicit handle(internal::custom_value<Context> custom) : custom_(custom) {}
|
explicit handle(internal::custom_value<Context> custom) : custom_(custom) {}
|
||||||
|
|
||||||
void format(basic_parse_context<char_type>& parse_ctx, Context& ctx) const {
|
void format(basic_format_parse_context<char_type>& parse_ctx,
|
||||||
|
Context& ctx) const {
|
||||||
custom_.format(custom_.value, parse_ctx, ctx);
|
custom_.format(custom_.value, parse_ctx, ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -893,8 +987,8 @@ template <typename Context> class basic_format_arg {
|
|||||||
|
|
||||||
internal::type type() const { return type_; }
|
internal::type type() const { return type_; }
|
||||||
|
|
||||||
bool is_integral() const { return internal::is_integral(type_); }
|
bool is_integral() const { return internal::is_integral_type(type_); }
|
||||||
bool is_arithmetic() const { return internal::is_arithmetic(type_); }
|
bool is_arithmetic() const { return internal::is_arithmetic_type(type_); }
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -923,10 +1017,22 @@ FMT_CONSTEXPR auto visit_format_arg(Visitor&& vis,
|
|||||||
return vis(arg.value_.long_long_value);
|
return vis(arg.value_.long_long_value);
|
||||||
case internal::ulong_long_type:
|
case internal::ulong_long_type:
|
||||||
return vis(arg.value_.ulong_long_value);
|
return vis(arg.value_.ulong_long_value);
|
||||||
|
#if FMT_USE_INT128
|
||||||
|
case internal::int128_type:
|
||||||
|
return vis(arg.value_.int128_value);
|
||||||
|
case internal::uint128_type:
|
||||||
|
return vis(arg.value_.uint128_value);
|
||||||
|
#else
|
||||||
|
case internal::int128_type:
|
||||||
|
case internal::uint128_type:
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
case internal::bool_type:
|
case internal::bool_type:
|
||||||
return vis(arg.value_.bool_value);
|
return vis(arg.value_.bool_value);
|
||||||
case internal::char_type:
|
case internal::char_type:
|
||||||
return vis(arg.value_.char_value);
|
return vis(arg.value_.char_value);
|
||||||
|
case internal::float_type:
|
||||||
|
return vis(arg.value_.float_value);
|
||||||
case internal::double_type:
|
case internal::double_type:
|
||||||
return vis(arg.value_.double_value);
|
return vis(arg.value_.double_value);
|
||||||
case internal::long_double_type:
|
case internal::long_double_type:
|
||||||
@ -948,9 +1054,6 @@ namespace internal {
|
|||||||
// A map from argument names to their values for named arguments.
|
// A map from argument names to their values for named arguments.
|
||||||
template <typename Context> class arg_map {
|
template <typename Context> class arg_map {
|
||||||
private:
|
private:
|
||||||
arg_map(const arg_map&) = delete;
|
|
||||||
void operator=(const arg_map&) = delete;
|
|
||||||
|
|
||||||
using char_type = typename Context::char_type;
|
using char_type = typename Context::char_type;
|
||||||
|
|
||||||
struct entry {
|
struct entry {
|
||||||
@ -968,6 +1071,8 @@ template <typename Context> class arg_map {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
arg_map(const arg_map&) = delete;
|
||||||
|
void operator=(const arg_map&) = delete;
|
||||||
arg_map() : map_(nullptr), size_(0) {}
|
arg_map() : map_(nullptr), size_(0) {}
|
||||||
void init(const basic_format_args<Context>& args);
|
void init(const basic_format_args<Context>& args);
|
||||||
~arg_map() { delete[] map_; }
|
~arg_map() { delete[] map_; }
|
||||||
@ -990,6 +1095,8 @@ class locale_ref {
|
|||||||
locale_ref() : locale_(nullptr) {}
|
locale_ref() : locale_(nullptr) {}
|
||||||
template <typename Locale> explicit locale_ref(const Locale& loc);
|
template <typename Locale> explicit locale_ref(const Locale& loc);
|
||||||
|
|
||||||
|
explicit operator bool() const FMT_NOEXCEPT { return locale_ != nullptr; }
|
||||||
|
|
||||||
template <typename Locale> Locale get() const;
|
template <typename Locale> Locale get() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -998,7 +1105,7 @@ template <typename> constexpr unsigned long long encode_types() { return 0; }
|
|||||||
template <typename Context, typename Arg, typename... Args>
|
template <typename Context, typename Arg, typename... Args>
|
||||||
constexpr unsigned long long encode_types() {
|
constexpr unsigned long long encode_types() {
|
||||||
return mapped_type_constant<Arg, Context>::value |
|
return mapped_type_constant<Arg, Context>::value |
|
||||||
(encode_types<Context, Args...>() << 4);
|
(encode_types<Context, Args...>() << packed_arg_bits);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Context, typename T>
|
template <typename Context, typename T>
|
||||||
@ -1034,14 +1141,13 @@ template <typename OutputIt, typename Char> class basic_format_context {
|
|||||||
internal::arg_map<basic_format_context> map_;
|
internal::arg_map<basic_format_context> map_;
|
||||||
internal::locale_ref loc_;
|
internal::locale_ref loc_;
|
||||||
|
|
||||||
basic_format_context(const basic_format_context&) = delete;
|
|
||||||
void operator=(const basic_format_context&) = delete;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
using iterator = OutputIt;
|
using iterator = OutputIt;
|
||||||
using format_arg = basic_format_arg<basic_format_context>;
|
using format_arg = basic_format_arg<basic_format_context>;
|
||||||
template <typename T> using formatter_type = formatter<T, char_type>;
|
template <typename T> using formatter_type = formatter<T, char_type>;
|
||||||
|
|
||||||
|
basic_format_context(const basic_format_context&) = delete;
|
||||||
|
void operator=(const basic_format_context&) = delete;
|
||||||
/**
|
/**
|
||||||
Constructs a ``basic_format_context`` object. References to the arguments are
|
Constructs a ``basic_format_context`` object. References to the arguments are
|
||||||
stored in the object so make sure they have appropriate lifetimes.
|
stored in the object so make sure they have appropriate lifetimes.
|
||||||
@ -1100,7 +1206,6 @@ template <typename Context, typename... Args> class format_arg_store {
|
|||||||
static constexpr unsigned long long types =
|
static constexpr unsigned long long types =
|
||||||
is_packed ? internal::encode_types<Context, Args...>()
|
is_packed ? internal::encode_types<Context, Args...>()
|
||||||
: internal::is_unpacked_bit | num_args;
|
: internal::is_unpacked_bit | num_args;
|
||||||
FMT_DEPRECATED static constexpr unsigned long long TYPES = types;
|
|
||||||
|
|
||||||
format_arg_store(const Args&... args)
|
format_arg_store(const Args&... args)
|
||||||
: data_{internal::make_arg<is_packed, Context>(args)...} {}
|
: data_{internal::make_arg<is_packed, Context>(args)...} {}
|
||||||
@ -1143,8 +1248,9 @@ template <typename Context> class basic_format_args {
|
|||||||
bool is_packed() const { return (types_ & internal::is_unpacked_bit) == 0; }
|
bool is_packed() const { return (types_ & internal::is_unpacked_bit) == 0; }
|
||||||
|
|
||||||
internal::type type(int index) const {
|
internal::type type(int index) const {
|
||||||
int shift = index * 4;
|
int shift = index * internal::packed_arg_bits;
|
||||||
return static_cast<internal::type>((types_ & (0xfull << shift)) >> shift);
|
unsigned int mask = (1 << internal::packed_arg_bits) - 1;
|
||||||
|
return static_cast<internal::type>((types_ >> shift) & mask);
|
||||||
}
|
}
|
||||||
|
|
||||||
friend class internal::arg_map<Context>;
|
friend class internal::arg_map<Context>;
|
||||||
@ -1371,7 +1477,7 @@ inline std::basic_string<Char> format(const S& format_str, Args&&... args) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
FMT_API void vprint(std::FILE* f, string_view format_str, format_args args);
|
FMT_API void vprint(std::FILE* f, string_view format_str, format_args args);
|
||||||
FMT_API void vprint(std::FILE* f, wstring_view format_str, wformat_args args);
|
FMT_API void vprint(string_view format_str, format_args args);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\rst
|
\rst
|
||||||
@ -1391,9 +1497,6 @@ inline void print(std::FILE* f, const S& format_str, Args&&... args) {
|
|||||||
internal::make_args_checked<Args...>(format_str, args...));
|
internal::make_args_checked<Args...>(format_str, args...));
|
||||||
}
|
}
|
||||||
|
|
||||||
FMT_API void vprint(string_view format_str, format_args args);
|
|
||||||
FMT_API void vprint(wstring_view format_str, wformat_args args);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\rst
|
\rst
|
||||||
Prints formatted data to ``stdout``.
|
Prints formatted data to ``stdout``.
|
||||||
|
File diff suppressed because it is too large
Load Diff
1124
third_party/spdlog/include/spdlog/fmt/bundled/format.h
vendored
1124
third_party/spdlog/include/spdlog/fmt/bundled/format.h
vendored
File diff suppressed because it is too large
Load Diff
@ -46,9 +46,13 @@ template <class Char> class formatbuf : public std::basic_streambuf<Char> {
|
|||||||
|
|
||||||
template <typename Char> struct test_stream : std::basic_ostream<Char> {
|
template <typename Char> struct test_stream : std::basic_ostream<Char> {
|
||||||
private:
|
private:
|
||||||
struct null;
|
|
||||||
// Hide all operator<< from std::basic_ostream<Char>.
|
// Hide all operator<< from std::basic_ostream<Char>.
|
||||||
void operator<<(null);
|
void_t<> operator<<(null<>);
|
||||||
|
void_t<> operator<<(const Char*);
|
||||||
|
|
||||||
|
template <typename T, FMT_ENABLE_IF(std::is_convertible<T, int>::value &&
|
||||||
|
!std::is_enum<T>::value)>
|
||||||
|
void_t<> operator<<(T);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Checks if T has a user-defined operator<< (e.g. not a member of
|
// Checks if T has a user-defined operator<< (e.g. not a member of
|
||||||
@ -56,9 +60,9 @@ template <typename Char> struct test_stream : std::basic_ostream<Char> {
|
|||||||
template <typename T, typename Char> class is_streamable {
|
template <typename T, typename Char> class is_streamable {
|
||||||
private:
|
private:
|
||||||
template <typename U>
|
template <typename U>
|
||||||
static decltype((void)(std::declval<test_stream<Char>&>()
|
static bool_constant<!std::is_same<decltype(std::declval<test_stream<Char>&>()
|
||||||
<< std::declval<U>()),
|
<< std::declval<U>()),
|
||||||
std::true_type())
|
void_t<>>::value>
|
||||||
test(int);
|
test(int);
|
||||||
|
|
||||||
template <typename> static std::false_type test(...);
|
template <typename> static std::false_type test(...);
|
||||||
@ -75,8 +79,7 @@ void write(std::basic_ostream<Char>& os, buffer<Char>& buf) {
|
|||||||
const Char* buf_data = buf.data();
|
const Char* buf_data = buf.data();
|
||||||
using unsigned_streamsize = std::make_unsigned<std::streamsize>::type;
|
using unsigned_streamsize = std::make_unsigned<std::streamsize>::type;
|
||||||
unsigned_streamsize size = buf.size();
|
unsigned_streamsize size = buf.size();
|
||||||
unsigned_streamsize max_size =
|
unsigned_streamsize max_size = to_unsigned(max_value<std::streamsize>());
|
||||||
to_unsigned((std::numeric_limits<std::streamsize>::max)());
|
|
||||||
do {
|
do {
|
||||||
unsigned_streamsize n = size <= max_size ? size : max_size;
|
unsigned_streamsize n = size <= max_size ? size : max_size;
|
||||||
os.write(buf_data, static_cast<std::streamsize>(n));
|
os.write(buf_data, static_cast<std::streamsize>(n));
|
||||||
@ -86,9 +89,11 @@ void write(std::basic_ostream<Char>& os, buffer<Char>& buf) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename Char, typename T>
|
template <typename Char, typename T>
|
||||||
void format_value(buffer<Char>& buf, const T& value) {
|
void format_value(buffer<Char>& buf, const T& value,
|
||||||
|
locale_ref loc = locale_ref()) {
|
||||||
formatbuf<Char> format_buf(buf);
|
formatbuf<Char> format_buf(buf);
|
||||||
std::basic_ostream<Char> output(&format_buf);
|
std::basic_ostream<Char> output(&format_buf);
|
||||||
|
if (loc) output.imbue(loc.get<std::locale>());
|
||||||
output.exceptions(std::ios_base::failbit | std::ios_base::badbit);
|
output.exceptions(std::ios_base::failbit | std::ios_base::badbit);
|
||||||
output << value;
|
output << value;
|
||||||
buf.resize(buf.size());
|
buf.resize(buf.size());
|
||||||
@ -101,7 +106,7 @@ struct fallback_formatter<T, Char, enable_if_t<is_streamable<T, Char>::value>>
|
|||||||
template <typename Context>
|
template <typename Context>
|
||||||
auto format(const T& value, Context& ctx) -> decltype(ctx.out()) {
|
auto format(const T& value, Context& ctx) -> decltype(ctx.out()) {
|
||||||
basic_memory_buffer<Char> buffer;
|
basic_memory_buffer<Char> buffer;
|
||||||
format_value(buffer, value);
|
format_value(buffer, value, ctx.locale());
|
||||||
basic_string_view<Char> str(buffer.data(), buffer.size());
|
basic_string_view<Char> str(buffer.data(), buffer.size());
|
||||||
return formatter<basic_string_view<Char>, Char>::format(str, ctx);
|
return formatter<basic_string_view<Char>, Char>::format(str, ctx);
|
||||||
}
|
}
|
||||||
|
@ -13,11 +13,10 @@
|
|||||||
# undef __STRICT_ANSI__
|
# undef __STRICT_ANSI__
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <errno.h>
|
#include <cerrno>
|
||||||
#include <fcntl.h> // for O_RDONLY
|
#include <clocale> // for locale_t
|
||||||
#include <locale.h> // for locale_t
|
#include <cstdio>
|
||||||
#include <stdio.h>
|
#include <cstdlib> // for strtod_l
|
||||||
#include <stdlib.h> // for strtod_l
|
|
||||||
|
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
|
|
||||||
@ -27,6 +26,18 @@
|
|||||||
|
|
||||||
#include "format.h"
|
#include "format.h"
|
||||||
|
|
||||||
|
// UWP doesn't provide _pipe.
|
||||||
|
#if FMT_HAS_INCLUDE("winapifamily.h")
|
||||||
|
# include <winapifamily.h>
|
||||||
|
#endif
|
||||||
|
#if FMT_HAS_INCLUDE("fcntl.h") && \
|
||||||
|
(!defined(WINAPI_FAMILY) || (WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP))
|
||||||
|
# include <fcntl.h> // for O_RDONLY
|
||||||
|
# define FMT_USE_FCNTL 1
|
||||||
|
#else
|
||||||
|
# define FMT_USE_FCNTL 0
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef FMT_POSIX
|
#ifndef FMT_POSIX
|
||||||
# if defined(_WIN32) && !defined(__MINGW32__)
|
# if defined(_WIN32) && !defined(__MINGW32__)
|
||||||
// Fix warnings about deprecated symbols.
|
// Fix warnings about deprecated symbols.
|
||||||
@ -54,8 +65,8 @@
|
|||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
# define FMT_RETRY_VAL(result, expression, error_result) \
|
# define FMT_RETRY_VAL(result, expression, error_result) \
|
||||||
do { \
|
do { \
|
||||||
result = (expression); \
|
(result) = (expression); \
|
||||||
} while (result == error_result && errno == EINTR)
|
} while ((result) == (error_result) && errno == EINTR)
|
||||||
#else
|
#else
|
||||||
# define FMT_RETRY_VAL(result, expression, error_result) result = (expression)
|
# define FMT_RETRY_VAL(result, expression, error_result) result = (expression)
|
||||||
#endif
|
#endif
|
||||||
@ -132,16 +143,15 @@ class buffered_file {
|
|||||||
explicit buffered_file(FILE* f) : file_(f) {}
|
explicit buffered_file(FILE* f) : file_(f) {}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
buffered_file(const buffered_file&) = delete;
|
||||||
|
void operator=(const buffered_file&) = delete;
|
||||||
|
|
||||||
// Constructs a buffered_file object which doesn't represent any file.
|
// Constructs a buffered_file object which doesn't represent any file.
|
||||||
buffered_file() FMT_NOEXCEPT : file_(nullptr) {}
|
buffered_file() FMT_NOEXCEPT : file_(nullptr) {}
|
||||||
|
|
||||||
// Destroys the object closing the file it represents if any.
|
// Destroys the object closing the file it represents if any.
|
||||||
FMT_API ~buffered_file() FMT_NOEXCEPT;
|
FMT_API ~buffered_file() FMT_NOEXCEPT;
|
||||||
|
|
||||||
private:
|
|
||||||
buffered_file(const buffered_file&) = delete;
|
|
||||||
void operator=(const buffered_file&) = delete;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
buffered_file(buffered_file&& other) FMT_NOEXCEPT : file_(other.file_) {
|
buffered_file(buffered_file&& other) FMT_NOEXCEPT : file_(other.file_) {
|
||||||
other.file_ = nullptr;
|
other.file_ = nullptr;
|
||||||
@ -177,6 +187,7 @@ class buffered_file {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#if FMT_USE_FCNTL
|
||||||
// A file. Closed file is represented by a file object with descriptor -1.
|
// A file. Closed file is represented by a file object with descriptor -1.
|
||||||
// Methods that are not declared with FMT_NOEXCEPT may throw
|
// Methods that are not declared with FMT_NOEXCEPT may throw
|
||||||
// fmt::system_error in case of failure. Note that some errors such as
|
// fmt::system_error in case of failure. Note that some errors such as
|
||||||
@ -204,14 +215,13 @@ class file {
|
|||||||
// Opens a file and constructs a file object representing this file.
|
// Opens a file and constructs a file object representing this file.
|
||||||
FMT_API file(cstring_view path, int oflag);
|
FMT_API file(cstring_view path, int oflag);
|
||||||
|
|
||||||
private:
|
public:
|
||||||
file(const file&) = delete;
|
file(const file&) = delete;
|
||||||
void operator=(const file&) = delete;
|
void operator=(const file&) = delete;
|
||||||
|
|
||||||
public:
|
|
||||||
file(file&& other) FMT_NOEXCEPT : fd_(other.fd_) { other.fd_ = -1; }
|
file(file&& other) FMT_NOEXCEPT : fd_(other.fd_) { other.fd_ = -1; }
|
||||||
|
|
||||||
file& operator=(file&& other) {
|
file& operator=(file&& other) FMT_NOEXCEPT {
|
||||||
close();
|
close();
|
||||||
fd_ = other.fd_;
|
fd_ = other.fd_;
|
||||||
other.fd_ = -1;
|
other.fd_ = -1;
|
||||||
@ -260,6 +270,7 @@ class file {
|
|||||||
|
|
||||||
// Returns the memory page size.
|
// Returns the memory page size.
|
||||||
long getpagesize();
|
long getpagesize();
|
||||||
|
#endif // FMT_USE_FCNTL
|
||||||
|
|
||||||
#ifdef FMT_LOCALE
|
#ifdef FMT_LOCALE
|
||||||
// A "C" numeric locale.
|
// A "C" numeric locale.
|
||||||
@ -283,11 +294,10 @@ class Locale {
|
|||||||
|
|
||||||
locale_t locale_;
|
locale_t locale_;
|
||||||
|
|
||||||
Locale(const Locale&) = delete;
|
|
||||||
void operator=(const Locale&) = delete;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
using type = locale_t;
|
using type = locale_t;
|
||||||
|
Locale(const Locale&) = delete;
|
||||||
|
void operator=(const Locale&) = delete;
|
||||||
|
|
||||||
Locale() : locale_(newlocale(LC_NUMERIC_MASK, "C", nullptr)) {
|
Locale() : locale_(newlocale(LC_NUMERIC_MASK, "C", nullptr)) {
|
||||||
if (!locale_) FMT_THROW(system_error(errno, "cannot create locale"));
|
if (!locale_) FMT_THROW(system_error(errno, "cannot create locale"));
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Formatting library for C++
|
// Formatting library for C++ - legacy printf implementation
|
||||||
//
|
//
|
||||||
// Copyright (c) 2012 - 2016, Victor Zverovich
|
// Copyright (c) 2012 - 2016, Victor Zverovich
|
||||||
// All rights reserved.
|
// All rights reserved.
|
||||||
@ -8,7 +8,7 @@
|
|||||||
#ifndef FMT_PRINTF_H_
|
#ifndef FMT_PRINTF_H_
|
||||||
#define FMT_PRINTF_H_
|
#define FMT_PRINTF_H_
|
||||||
|
|
||||||
#include <algorithm> // std::fill_n
|
#include <algorithm> // std::max
|
||||||
#include <limits> // std::numeric_limits
|
#include <limits> // std::numeric_limits
|
||||||
|
|
||||||
#include "ostream.h"
|
#include "ostream.h"
|
||||||
@ -16,15 +16,11 @@
|
|||||||
FMT_BEGIN_NAMESPACE
|
FMT_BEGIN_NAMESPACE
|
||||||
namespace internal {
|
namespace internal {
|
||||||
|
|
||||||
// A helper function to suppress bogus "conditional expression is constant"
|
|
||||||
// warnings.
|
|
||||||
template <typename T> inline T const_check(T value) { 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> struct int_checker {
|
template <bool IsSigned> struct int_checker {
|
||||||
template <typename T> static bool fits_in_int(T value) {
|
template <typename T> static bool fits_in_int(T value) {
|
||||||
unsigned max = std::numeric_limits<int>::max();
|
unsigned max = max_value<int>();
|
||||||
return value <= max;
|
return value <= max;
|
||||||
}
|
}
|
||||||
static bool fits_in_int(bool) { return true; }
|
static bool fits_in_int(bool) { return true; }
|
||||||
@ -33,7 +29,7 @@ template <bool IsSigned> struct int_checker {
|
|||||||
template <> struct int_checker<true> {
|
template <> struct int_checker<true> {
|
||||||
template <typename T> static bool fits_in_int(T value) {
|
template <typename T> static bool fits_in_int(T value) {
|
||||||
return value >= std::numeric_limits<int>::min() &&
|
return value >= std::numeric_limits<int>::min() &&
|
||||||
value <= std::numeric_limits<int>::max();
|
value <= max_value<int>();
|
||||||
}
|
}
|
||||||
static bool fits_in_int(int) { return true; }
|
static bool fits_in_int(int) { return true; }
|
||||||
};
|
};
|
||||||
@ -158,12 +154,12 @@ template <typename Char> class printf_width_handler {
|
|||||||
|
|
||||||
template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
|
template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
|
||||||
unsigned operator()(T value) {
|
unsigned operator()(T value) {
|
||||||
auto width = static_cast<uint32_or_64_t<T>>(value);
|
auto width = static_cast<uint32_or_64_or_128_t<T>>(value);
|
||||||
if (internal::is_negative(value)) {
|
if (internal::is_negative(value)) {
|
||||||
specs_.align = align::left;
|
specs_.align = align::left;
|
||||||
width = 0 - width;
|
width = 0 - width;
|
||||||
}
|
}
|
||||||
unsigned int_max = std::numeric_limits<int>::max();
|
unsigned int_max = max_value<int>();
|
||||||
if (width > int_max) FMT_THROW(format_error("number is too big"));
|
if (width > int_max) FMT_THROW(format_error("number is too big"));
|
||||||
return static_cast<unsigned>(width);
|
return static_cast<unsigned>(width);
|
||||||
}
|
}
|
||||||
@ -235,7 +231,7 @@ class printf_arg_formatter : public internal::arg_formatter_base<Range> {
|
|||||||
printf_arg_formatter(iterator iter, format_specs& specs, context_type& ctx)
|
printf_arg_formatter(iterator iter, format_specs& specs, context_type& ctx)
|
||||||
: base(Range(iter), &specs, internal::locale_ref()), context_(ctx) {}
|
: base(Range(iter), &specs, internal::locale_ref()), context_(ctx) {}
|
||||||
|
|
||||||
template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
|
template <typename T, FMT_ENABLE_IF(fmt::internal::is_integral<T>::value)>
|
||||||
iterator operator()(T value) {
|
iterator operator()(T value) {
|
||||||
// MSVC2013 fails to compile separate overloads for bool and char_type so
|
// MSVC2013 fails to compile separate overloads for bool and char_type so
|
||||||
// use std::is_same instead.
|
// use std::is_same instead.
|
||||||
@ -332,14 +328,14 @@ template <typename OutputIt, typename Char> class basic_printf_context {
|
|||||||
|
|
||||||
OutputIt out_;
|
OutputIt out_;
|
||||||
basic_format_args<basic_printf_context> args_;
|
basic_format_args<basic_printf_context> args_;
|
||||||
basic_parse_context<Char> parse_ctx_;
|
basic_format_parse_context<Char> parse_ctx_;
|
||||||
|
|
||||||
static void parse_flags(format_specs& specs, const Char*& it,
|
static void parse_flags(format_specs& specs, const Char*& it,
|
||||||
const Char* end);
|
const Char* end);
|
||||||
|
|
||||||
// Returns the argument with specified index or, if arg_index is equal
|
// Returns the argument with specified index or, if arg_index is equal
|
||||||
// to the maximum unsigned value, the next argument.
|
// to the maximum unsigned value, the next argument.
|
||||||
format_arg get_arg(unsigned arg_index = std::numeric_limits<unsigned>::max());
|
format_arg get_arg(unsigned arg_index = internal::max_value<unsigned>());
|
||||||
|
|
||||||
// Parses argument index, flags and width and returns the argument index.
|
// Parses argument index, flags and width and returns the argument index.
|
||||||
unsigned parse_header(const Char*& it, const Char* end, format_specs& specs);
|
unsigned parse_header(const Char*& it, const Char* end, format_specs& specs);
|
||||||
@ -361,15 +357,14 @@ template <typename OutputIt, typename Char> class basic_printf_context {
|
|||||||
|
|
||||||
format_arg arg(unsigned id) const { return args_.get(id); }
|
format_arg arg(unsigned id) const { return args_.get(id); }
|
||||||
|
|
||||||
basic_parse_context<Char>& parse_context() { return parse_ctx_; }
|
basic_format_parse_context<Char>& parse_context() { return parse_ctx_; }
|
||||||
|
|
||||||
FMT_CONSTEXPR void on_error(const char* message) {
|
FMT_CONSTEXPR void on_error(const char* message) {
|
||||||
parse_ctx_.on_error(message);
|
parse_ctx_.on_error(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Formats stored arguments and writes the output to the range. */
|
/** Formats stored arguments and writes the output to the range. */
|
||||||
template <typename ArgFormatter =
|
template <typename ArgFormatter = printf_arg_formatter<buffer_range<Char>>>
|
||||||
printf_arg_formatter<internal::buffer_range<Char>>>
|
|
||||||
OutputIt format();
|
OutputIt format();
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -403,7 +398,7 @@ void basic_printf_context<OutputIt, Char>::parse_flags(format_specs& specs,
|
|||||||
template <typename OutputIt, typename Char>
|
template <typename OutputIt, typename Char>
|
||||||
typename basic_printf_context<OutputIt, Char>::format_arg
|
typename basic_printf_context<OutputIt, Char>::format_arg
|
||||||
basic_printf_context<OutputIt, Char>::get_arg(unsigned arg_index) {
|
basic_printf_context<OutputIt, Char>::get_arg(unsigned arg_index) {
|
||||||
if (arg_index == std::numeric_limits<unsigned>::max())
|
if (arg_index == internal::max_value<unsigned>())
|
||||||
arg_index = parse_ctx_.next_arg_id();
|
arg_index = parse_ctx_.next_arg_id();
|
||||||
else
|
else
|
||||||
parse_ctx_.check_arg_id(--arg_index);
|
parse_ctx_.check_arg_id(--arg_index);
|
||||||
@ -413,7 +408,7 @@ basic_printf_context<OutputIt, Char>::get_arg(unsigned arg_index) {
|
|||||||
template <typename OutputIt, typename Char>
|
template <typename OutputIt, typename Char>
|
||||||
unsigned basic_printf_context<OutputIt, Char>::parse_header(
|
unsigned basic_printf_context<OutputIt, Char>::parse_header(
|
||||||
const Char*& it, const Char* end, format_specs& specs) {
|
const Char*& it, const Char* end, format_specs& specs) {
|
||||||
unsigned arg_index = std::numeric_limits<unsigned>::max();
|
unsigned arg_index = internal::max_value<unsigned>();
|
||||||
char_type c = *it;
|
char_type c = *it;
|
||||||
if (c >= '0' && c <= '9') {
|
if (c >= '0' && c <= '9') {
|
||||||
// Parse an argument index (if followed by '$') or a width possibly
|
// Parse an argument index (if followed by '$') or a width possibly
|
||||||
@ -470,6 +465,7 @@ OutputIt basic_printf_context<OutputIt, Char>::format() {
|
|||||||
|
|
||||||
// Parse argument index, flags and width.
|
// Parse argument index, flags and width.
|
||||||
unsigned arg_index = parse_header(it, end, specs);
|
unsigned arg_index = parse_header(it, end, specs);
|
||||||
|
if (arg_index == 0) on_error("argument index out of range");
|
||||||
|
|
||||||
// Parse precision.
|
// Parse precision.
|
||||||
if (it != end && *it == '.') {
|
if (it != end && *it == '.') {
|
||||||
|
@ -246,7 +246,8 @@ template <typename T, typename Char> struct is_range {
|
|||||||
static FMT_CONSTEXPR_DECL const bool value =
|
static FMT_CONSTEXPR_DECL const bool value =
|
||||||
internal::is_range_<T>::value &&
|
internal::is_range_<T>::value &&
|
||||||
!internal::is_like_std_string<T>::value &&
|
!internal::is_like_std_string<T>::value &&
|
||||||
!std::is_convertible<T, std::basic_string<Char>>::value;
|
!std::is_convertible<T, std::basic_string<Char>>::value &&
|
||||||
|
!std::is_constructible<internal::std_string_view<Char>, T>::value;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename RangeT, typename Char>
|
template <typename RangeT, typename Char>
|
||||||
@ -283,6 +284,82 @@ struct formatter<RangeT, Char,
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <typename Char, typename... T> struct tuple_arg_join : internal::view {
|
||||||
|
const std::tuple<T...>& tuple;
|
||||||
|
basic_string_view<Char> sep;
|
||||||
|
|
||||||
|
tuple_arg_join(const std::tuple<T...>& t, basic_string_view<Char> s)
|
||||||
|
: tuple{t}, sep{s} {}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Char, typename... T>
|
||||||
|
struct formatter<tuple_arg_join<Char, T...>, Char> {
|
||||||
|
template <typename ParseContext>
|
||||||
|
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
|
||||||
|
return ctx.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename FormatContext>
|
||||||
|
typename FormatContext::iterator format(
|
||||||
|
const tuple_arg_join<Char, T...>& value, FormatContext& ctx) {
|
||||||
|
return format(value, ctx, internal::make_index_sequence<sizeof...(T)>{});
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
template <typename FormatContext, size_t... N>
|
||||||
|
typename FormatContext::iterator format(
|
||||||
|
const tuple_arg_join<Char, T...>& value, FormatContext& ctx,
|
||||||
|
internal::index_sequence<N...>) {
|
||||||
|
return format_args(value, ctx, std::get<N>(value.tuple)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename FormatContext>
|
||||||
|
typename FormatContext::iterator format_args(
|
||||||
|
const tuple_arg_join<Char, T...>&, FormatContext& ctx) {
|
||||||
|
// NOTE: for compilers that support C++17, this empty function instantiation
|
||||||
|
// can be replaced with a constexpr branch in the variadic overload.
|
||||||
|
return ctx.out();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename FormatContext, typename Arg, typename... Args>
|
||||||
|
typename FormatContext::iterator format_args(
|
||||||
|
const tuple_arg_join<Char, T...>& value, FormatContext& ctx,
|
||||||
|
const Arg& arg, const Args&... args) {
|
||||||
|
using base = formatter<typename std::decay<Arg>::type, Char>;
|
||||||
|
auto out = ctx.out();
|
||||||
|
out = base{}.format(arg, ctx);
|
||||||
|
if (sizeof...(Args) > 0) {
|
||||||
|
out = std::copy(value.sep.begin(), value.sep.end(), out);
|
||||||
|
ctx.advance_to(out);
|
||||||
|
return format_args(value, ctx, args...);
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
\rst
|
||||||
|
Returns an object that formats `tuple` with elements separated by `sep`.
|
||||||
|
|
||||||
|
**Example**::
|
||||||
|
|
||||||
|
std::tuple<int, char> t = {1, 'a'};
|
||||||
|
fmt::print("{}", fmt::join(t, ", "));
|
||||||
|
// Output: "1, a"
|
||||||
|
\endrst
|
||||||
|
*/
|
||||||
|
template <typename... T>
|
||||||
|
FMT_CONSTEXPR tuple_arg_join<char, T...> join(const std::tuple<T...>& tuple,
|
||||||
|
string_view sep) {
|
||||||
|
return {tuple, sep};
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename... T>
|
||||||
|
FMT_CONSTEXPR tuple_arg_join<wchar_t, T...> join(const std::tuple<T...>& tuple,
|
||||||
|
wstring_view sep) {
|
||||||
|
return {tuple, sep};
|
||||||
|
}
|
||||||
|
|
||||||
FMT_END_NAMESPACE
|
FMT_END_NAMESPACE
|
||||||
|
|
||||||
#endif // FMT_RANGES_H_
|
#endif // FMT_RANGES_H_
|
||||||
|
@ -1,293 +0,0 @@
|
|||||||
/*
|
|
||||||
* For conversion between std::chrono::durations without undefined
|
|
||||||
* behaviour or erroneous results.
|
|
||||||
* This is a stripped down version of duration_cast, for inclusion in fmt.
|
|
||||||
* See https://github.com/pauldreik/safe_duration_cast
|
|
||||||
*
|
|
||||||
* Copyright Paul Dreik 2019
|
|
||||||
*
|
|
||||||
* This file is licensed under the fmt license, see format.h
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <chrono>
|
|
||||||
#include <cmath>
|
|
||||||
#include <limits>
|
|
||||||
#include <type_traits>
|
|
||||||
|
|
||||||
#include "format.h"
|
|
||||||
|
|
||||||
FMT_BEGIN_NAMESPACE
|
|
||||||
|
|
||||||
namespace safe_duration_cast {
|
|
||||||
|
|
||||||
template <typename To, typename From,
|
|
||||||
FMT_ENABLE_IF(!std::is_same<From, To>::value &&
|
|
||||||
std::numeric_limits<From>::is_signed ==
|
|
||||||
std::numeric_limits<To>::is_signed)>
|
|
||||||
FMT_CONSTEXPR To lossless_integral_conversion(const From from, int& ec) {
|
|
||||||
ec = 0;
|
|
||||||
using F = std::numeric_limits<From>;
|
|
||||||
using T = std::numeric_limits<To>;
|
|
||||||
static_assert(F::is_integer, "From must be integral");
|
|
||||||
static_assert(T::is_integer, "To must be integral");
|
|
||||||
|
|
||||||
// A and B are both signed, or both unsigned.
|
|
||||||
if (F::digits <= T::digits) {
|
|
||||||
// From fits in To without any problem.
|
|
||||||
} else {
|
|
||||||
// From does not always fit in To, resort to a dynamic check.
|
|
||||||
if (from < T::min() || from > T::max()) {
|
|
||||||
// outside range.
|
|
||||||
ec = 1;
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return static_cast<To>(from);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* converts From to To, without loss. If the dynamic value of from
|
|
||||||
* can't be converted to To without loss, ec is set.
|
|
||||||
*/
|
|
||||||
template <typename To, typename From,
|
|
||||||
FMT_ENABLE_IF(!std::is_same<From, To>::value &&
|
|
||||||
std::numeric_limits<From>::is_signed !=
|
|
||||||
std::numeric_limits<To>::is_signed)>
|
|
||||||
FMT_CONSTEXPR To lossless_integral_conversion(const From from, int& ec) {
|
|
||||||
ec = 0;
|
|
||||||
using F = std::numeric_limits<From>;
|
|
||||||
using T = std::numeric_limits<To>;
|
|
||||||
static_assert(F::is_integer, "From must be integral");
|
|
||||||
static_assert(T::is_integer, "To must be integral");
|
|
||||||
|
|
||||||
if (F::is_signed && !T::is_signed) {
|
|
||||||
// From may be negative, not allowed!
|
|
||||||
if (from < 0) {
|
|
||||||
ec = 1;
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
// From is positive. Can it always fit in To?
|
|
||||||
if (F::digits <= T::digits) {
|
|
||||||
// yes, From always fits in To.
|
|
||||||
} else {
|
|
||||||
// from may not fit in To, we have to do a dynamic check
|
|
||||||
if (from > static_cast<From>(T::max())) {
|
|
||||||
ec = 1;
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!F::is_signed && T::is_signed) {
|
|
||||||
// can from be held in To?
|
|
||||||
if (F::digits < T::digits) {
|
|
||||||
// yes, From always fits in To.
|
|
||||||
} else {
|
|
||||||
// from may not fit in To, we have to do a dynamic check
|
|
||||||
if (from > static_cast<From>(T::max())) {
|
|
||||||
// outside range.
|
|
||||||
ec = 1;
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// reaching here means all is ok for lossless conversion.
|
|
||||||
return static_cast<To>(from);
|
|
||||||
|
|
||||||
} // function
|
|
||||||
|
|
||||||
template <typename To, typename From,
|
|
||||||
FMT_ENABLE_IF(std::is_same<From, To>::value)>
|
|
||||||
FMT_CONSTEXPR To lossless_integral_conversion(const From from, int& ec) {
|
|
||||||
ec = 0;
|
|
||||||
return from;
|
|
||||||
} // function
|
|
||||||
|
|
||||||
// clang-format off
|
|
||||||
/**
|
|
||||||
* converts From to To if possible, otherwise ec is set.
|
|
||||||
*
|
|
||||||
* input | output
|
|
||||||
* ---------------------------------|---------------
|
|
||||||
* NaN | NaN
|
|
||||||
* Inf | Inf
|
|
||||||
* normal, fits in output | converted (possibly lossy)
|
|
||||||
* normal, does not fit in output | ec is set
|
|
||||||
* subnormal | best effort
|
|
||||||
* -Inf | -Inf
|
|
||||||
*/
|
|
||||||
// clang-format on
|
|
||||||
template <typename To, typename From,
|
|
||||||
FMT_ENABLE_IF(!std::is_same<From, To>::value)>
|
|
||||||
FMT_CONSTEXPR To safe_float_conversion(const From from, int& ec) {
|
|
||||||
ec = 0;
|
|
||||||
using T = std::numeric_limits<To>;
|
|
||||||
static_assert(std::is_floating_point<From>::value, "From must be floating");
|
|
||||||
static_assert(std::is_floating_point<To>::value, "To must be floating");
|
|
||||||
|
|
||||||
// catch the only happy case
|
|
||||||
if (std::isfinite(from)) {
|
|
||||||
if (from >= T::lowest() && from <= T::max()) {
|
|
||||||
return static_cast<To>(from);
|
|
||||||
}
|
|
||||||
// not within range.
|
|
||||||
ec = 1;
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
// nan and inf will be preserved
|
|
||||||
return static_cast<To>(from);
|
|
||||||
} // function
|
|
||||||
|
|
||||||
template <typename To, typename From,
|
|
||||||
FMT_ENABLE_IF(std::is_same<From, To>::value)>
|
|
||||||
FMT_CONSTEXPR To safe_float_conversion(const From from, int& ec) {
|
|
||||||
ec = 0;
|
|
||||||
static_assert(std::is_floating_point<From>::value, "From must be floating");
|
|
||||||
return from;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* safe duration cast between integral durations
|
|
||||||
*/
|
|
||||||
template <typename To, typename FromRep, typename FromPeriod,
|
|
||||||
FMT_ENABLE_IF(std::is_integral<FromRep>::value),
|
|
||||||
FMT_ENABLE_IF(std::is_integral<typename To::rep>::value)>
|
|
||||||
To safe_duration_cast(std::chrono::duration<FromRep, FromPeriod> from,
|
|
||||||
int& ec) {
|
|
||||||
using From = std::chrono::duration<FromRep, FromPeriod>;
|
|
||||||
ec = 0;
|
|
||||||
// the basic idea is that we need to convert from count() in the from type
|
|
||||||
// to count() in the To type, by multiplying it with this:
|
|
||||||
using Factor = std::ratio_divide<typename From::period, typename To::period>;
|
|
||||||
|
|
||||||
static_assert(Factor::num > 0, "num must be positive");
|
|
||||||
static_assert(Factor::den > 0, "den must be positive");
|
|
||||||
|
|
||||||
// the conversion is like this: multiply from.count() with Factor::num
|
|
||||||
// /Factor::den and convert it to To::rep, all this without
|
|
||||||
// overflow/underflow. let's start by finding a suitable type that can hold
|
|
||||||
// both To, From and Factor::num
|
|
||||||
using IntermediateRep =
|
|
||||||
typename std::common_type<typename From::rep, typename To::rep,
|
|
||||||
decltype(Factor::num)>::type;
|
|
||||||
|
|
||||||
// safe conversion to IntermediateRep
|
|
||||||
IntermediateRep count =
|
|
||||||
lossless_integral_conversion<IntermediateRep>(from.count(), ec);
|
|
||||||
if (ec) {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
// multiply with Factor::num without overflow or underflow
|
|
||||||
if (Factor::num != 1) {
|
|
||||||
constexpr auto max1 =
|
|
||||||
std::numeric_limits<IntermediateRep>::max() / Factor::num;
|
|
||||||
if (count > max1) {
|
|
||||||
ec = 1;
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
constexpr auto min1 =
|
|
||||||
std::numeric_limits<IntermediateRep>::min() / Factor::num;
|
|
||||||
if (count < min1) {
|
|
||||||
ec = 1;
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
count *= Factor::num;
|
|
||||||
}
|
|
||||||
|
|
||||||
// this can't go wrong, right? den>0 is checked earlier.
|
|
||||||
if (Factor::den != 1) {
|
|
||||||
count /= Factor::den;
|
|
||||||
}
|
|
||||||
// convert to the to type, safely
|
|
||||||
using ToRep = typename To::rep;
|
|
||||||
const ToRep tocount = lossless_integral_conversion<ToRep>(count, ec);
|
|
||||||
if (ec) {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
return To{tocount};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* safe duration_cast between floating point durations
|
|
||||||
*/
|
|
||||||
template <typename To, typename FromRep, typename FromPeriod,
|
|
||||||
FMT_ENABLE_IF(std::is_floating_point<FromRep>::value),
|
|
||||||
FMT_ENABLE_IF(std::is_floating_point<typename To::rep>::value)>
|
|
||||||
To safe_duration_cast(std::chrono::duration<FromRep, FromPeriod> from,
|
|
||||||
int& ec) {
|
|
||||||
using From = std::chrono::duration<FromRep, FromPeriod>;
|
|
||||||
ec = 0;
|
|
||||||
if (std::isnan(from.count())) {
|
|
||||||
// nan in, gives nan out. easy.
|
|
||||||
return To{std::numeric_limits<typename To::rep>::quiet_NaN()};
|
|
||||||
}
|
|
||||||
// maybe we should also check if from is denormal, and decide what to do about
|
|
||||||
// it.
|
|
||||||
|
|
||||||
// +-inf should be preserved.
|
|
||||||
if (std::isinf(from.count())) {
|
|
||||||
return To{from.count()};
|
|
||||||
}
|
|
||||||
|
|
||||||
// the basic idea is that we need to convert from count() in the from type
|
|
||||||
// to count() in the To type, by multiplying it with this:
|
|
||||||
using Factor = std::ratio_divide<typename From::period, typename To::period>;
|
|
||||||
|
|
||||||
static_assert(Factor::num > 0, "num must be positive");
|
|
||||||
static_assert(Factor::den > 0, "den must be positive");
|
|
||||||
|
|
||||||
// the conversion is like this: multiply from.count() with Factor::num
|
|
||||||
// /Factor::den and convert it to To::rep, all this without
|
|
||||||
// overflow/underflow. let's start by finding a suitable type that can hold
|
|
||||||
// both To, From and Factor::num
|
|
||||||
using IntermediateRep =
|
|
||||||
typename std::common_type<typename From::rep, typename To::rep,
|
|
||||||
decltype(Factor::num)>::type;
|
|
||||||
|
|
||||||
// force conversion of From::rep -> IntermediateRep to be safe,
|
|
||||||
// even if it will never happen be narrowing in this context.
|
|
||||||
IntermediateRep count =
|
|
||||||
safe_float_conversion<IntermediateRep>(from.count(), ec);
|
|
||||||
if (ec) {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
// multiply with Factor::num without overflow or underflow
|
|
||||||
if (Factor::num != 1) {
|
|
||||||
constexpr auto max1 = std::numeric_limits<IntermediateRep>::max() /
|
|
||||||
static_cast<IntermediateRep>(Factor::num);
|
|
||||||
if (count > max1) {
|
|
||||||
ec = 1;
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
constexpr auto min1 = std::numeric_limits<IntermediateRep>::lowest() /
|
|
||||||
static_cast<IntermediateRep>(Factor::num);
|
|
||||||
if (count < min1) {
|
|
||||||
ec = 1;
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
count *= static_cast<IntermediateRep>(Factor::num);
|
|
||||||
}
|
|
||||||
|
|
||||||
// this can't go wrong, right? den>0 is checked earlier.
|
|
||||||
if (Factor::den != 1) {
|
|
||||||
using common_t = typename std::common_type<IntermediateRep, intmax_t>::type;
|
|
||||||
count /= static_cast<common_t>(Factor::den);
|
|
||||||
}
|
|
||||||
|
|
||||||
// convert to the to type, safely
|
|
||||||
using ToRep = typename To::rep;
|
|
||||||
|
|
||||||
const ToRep tocount = safe_float_conversion<ToRep>(count, ec);
|
|
||||||
if (ec) {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
return To{tocount};
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace safe_duration_cast
|
|
||||||
|
|
||||||
FMT_END_NAMESPACE
|
|
16
third_party/spdlog/include/spdlog/fmt/fmt.h
vendored
16
third_party/spdlog/include/spdlog/fmt/fmt.h
vendored
@ -10,6 +10,13 @@
|
|||||||
// By default spdlog include its own copy.
|
// By default spdlog include its own copy.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
#if defined(__GNUC__) || defined(__clang__)
|
||||||
|
#pragma GCC diagnostic push
|
||||||
|
#pragma GCC diagnostic ignored "-Wimplicit-fallthrough"
|
||||||
|
#pragma GCC diagnostic ignored "-Wsign-conversion"
|
||||||
|
#endif // __GNUC__ || __clang__
|
||||||
|
|
||||||
|
|
||||||
#if !defined(SPDLOG_FMT_EXTERNAL)
|
#if !defined(SPDLOG_FMT_EXTERNAL)
|
||||||
#ifdef SPDLOG_HEADER_ONLY
|
#ifdef SPDLOG_HEADER_ONLY
|
||||||
#ifndef FMT_HEADER_ONLY
|
#ifndef FMT_HEADER_ONLY
|
||||||
@ -22,6 +29,11 @@
|
|||||||
#include "bundled/core.h"
|
#include "bundled/core.h"
|
||||||
#include "bundled/format.h"
|
#include "bundled/format.h"
|
||||||
#else // SPDLOG_FMT_EXTERNAL is defined - use external fmtlib
|
#else // SPDLOG_FMT_EXTERNAL is defined - use external fmtlib
|
||||||
#include "fmt/core.h"
|
#include <fmt/core.h>
|
||||||
#include "fmt/format.h"
|
#include <fmt/format.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// pop warnings supressions
|
||||||
|
#if defined(__GNUC__) || defined(__clang__)
|
||||||
|
#pragma GCC diagnostic pop
|
||||||
#endif
|
#endif
|
||||||
|
@ -3,8 +3,8 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "fmt/fmt.h"
|
#include <spdlog/fmt/fmt.h>
|
||||||
#include "spdlog/details/log_msg.h"
|
#include <spdlog/details/log_msg.h>
|
||||||
|
|
||||||
namespace spdlog {
|
namespace spdlog {
|
||||||
|
|
||||||
|
34
third_party/spdlog/include/spdlog/logger-inl.h
vendored
34
third_party/spdlog/include/spdlog/logger-inl.h
vendored
@ -4,12 +4,12 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#ifndef SPDLOG_HEADER_ONLY
|
#ifndef SPDLOG_HEADER_ONLY
|
||||||
#include "spdlog/logger.h"
|
#include <spdlog/logger.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "spdlog/sinks/sink.h"
|
#include <spdlog/sinks/sink.h>
|
||||||
#include "spdlog/details/backtracer.h"
|
#include <spdlog/details/backtracer.h>
|
||||||
#include "spdlog/details/pattern_formatter.h"
|
#include <spdlog/details/pattern_formatter.h>
|
||||||
|
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
|
|
||||||
@ -64,11 +64,6 @@ SPDLOG_INLINE void swap(logger &a, logger &b)
|
|||||||
a.swap(b);
|
a.swap(b);
|
||||||
}
|
}
|
||||||
|
|
||||||
SPDLOG_INLINE bool logger::should_log(level::level_enum msg_level) const
|
|
||||||
{
|
|
||||||
return msg_level >= level_.load(std::memory_order_relaxed);
|
|
||||||
}
|
|
||||||
|
|
||||||
SPDLOG_INLINE void logger::set_level(level::level_enum log_level)
|
SPDLOG_INLINE void logger::set_level(level::level_enum log_level)
|
||||||
{
|
{
|
||||||
level_.store(log_level);
|
level_.store(log_level);
|
||||||
@ -85,7 +80,7 @@ SPDLOG_INLINE const std::string &logger::name() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
// set formatting for the sinks in this logger.
|
// set formatting for the sinks in this logger.
|
||||||
// each sink will get a seperate instance of the formatter object.
|
// each sink will get a separate instance of the formatter object.
|
||||||
SPDLOG_INLINE void logger::set_formatter(std::unique_ptr<formatter> f)
|
SPDLOG_INLINE void logger::set_formatter(std::unique_ptr<formatter> f)
|
||||||
{
|
{
|
||||||
for (auto it = sinks_.begin(); it != sinks_.end(); ++it)
|
for (auto it = sinks_.begin(); it != sinks_.end(); ++it)
|
||||||
@ -155,7 +150,7 @@ SPDLOG_INLINE std::vector<sink_ptr> &logger::sinks()
|
|||||||
// error handler
|
// error handler
|
||||||
SPDLOG_INLINE void logger::set_error_handler(err_handler handler)
|
SPDLOG_INLINE void logger::set_error_handler(err_handler handler)
|
||||||
{
|
{
|
||||||
custom_err_handler_ = handler;
|
custom_err_handler_ = std::move(handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
// create new logger with same sinks and configuration.
|
// create new logger with same sinks and configuration.
|
||||||
@ -167,6 +162,18 @@ SPDLOG_INLINE std::shared_ptr<logger> logger::clone(std::string logger_name)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// protected methods
|
// protected methods
|
||||||
|
SPDLOG_INLINE void logger::log_it_(const spdlog::details::log_msg &log_msg, bool log_enabled, bool traceback_enabled)
|
||||||
|
{
|
||||||
|
if (log_enabled)
|
||||||
|
{
|
||||||
|
sink_it_(log_msg);
|
||||||
|
}
|
||||||
|
if (traceback_enabled)
|
||||||
|
{
|
||||||
|
tracer_.push_back(log_msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
SPDLOG_INLINE void logger::sink_it_(const details::log_msg &msg)
|
SPDLOG_INLINE void logger::sink_it_(const details::log_msg &msg)
|
||||||
{
|
{
|
||||||
for (auto &sink : sinks_)
|
for (auto &sink : sinks_)
|
||||||
@ -202,10 +209,10 @@ SPDLOG_INLINE void logger::flush_()
|
|||||||
SPDLOG_INLINE void logger::dump_backtrace_()
|
SPDLOG_INLINE void logger::dump_backtrace_()
|
||||||
{
|
{
|
||||||
using details::log_msg;
|
using details::log_msg;
|
||||||
if (tracer_)
|
if (tracer_.enabled())
|
||||||
{
|
{
|
||||||
sink_it_(log_msg{name(), level::info, "****************** Backtrace Start ******************"});
|
sink_it_(log_msg{name(), level::info, "****************** Backtrace Start ******************"});
|
||||||
tracer_.foreach_pop([this](const details::log_msg &msg) { this->sink_it_(msg); });
|
tracer_.foreach_pop([this](const log_msg &msg) { this->sink_it_(msg); });
|
||||||
sink_it_(log_msg{name(), level::info, "****************** Backtrace End ********************"});
|
sink_it_(log_msg{name(), level::info, "****************** Backtrace End ********************"});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -218,7 +225,6 @@ SPDLOG_INLINE bool logger::should_flush_(const details::log_msg &msg)
|
|||||||
|
|
||||||
SPDLOG_INLINE void logger::err_handler_(const std::string &msg)
|
SPDLOG_INLINE void logger::err_handler_(const std::string &msg)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (custom_err_handler_)
|
if (custom_err_handler_)
|
||||||
{
|
{
|
||||||
custom_err_handler_(msg);
|
custom_err_handler_(msg);
|
||||||
|
85
third_party/spdlog/include/spdlog/logger.h
vendored
85
third_party/spdlog/include/spdlog/logger.h
vendored
@ -3,8 +3,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
// Thread safe logger (except for set_pattern(..), set_formatter(..) and
|
// Thread safe logger (except for set_error_handler())
|
||||||
// set_error_handler())
|
|
||||||
// Has name, log level, vector of std::shared sink pointers and formatter
|
// Has name, log level, vector of std::shared sink pointers and formatter
|
||||||
// Upon each log write the logger:
|
// Upon each log write the logger:
|
||||||
// 1. Checks if its log level is enough to log the message and if yes:
|
// 1. Checks if its log level is enough to log the message and if yes:
|
||||||
@ -15,12 +14,12 @@
|
|||||||
// The use of private formatter per sink provides the opportunity to cache some
|
// The use of private formatter per sink provides the opportunity to cache some
|
||||||
// formatted data, and support for different format per sink.
|
// formatted data, and support for different format per sink.
|
||||||
|
|
||||||
#include "spdlog/common.h"
|
#include <spdlog/common.h>
|
||||||
#include "spdlog/details/log_msg.h"
|
#include <spdlog/details/log_msg.h>
|
||||||
#include "spdlog/details/backtracer.h"
|
#include <spdlog/details/backtracer.h>
|
||||||
|
|
||||||
#ifdef SPDLOG_WCHAR_TO_UTF8_SUPPORT
|
#ifdef SPDLOG_WCHAR_TO_UTF8_SUPPORT
|
||||||
#include "spdlog/details/os.h"
|
#include <spdlog/details/os.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@ -77,8 +76,9 @@ public:
|
|||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
void log(source_loc loc, level::level_enum lvl, string_view_t fmt, const Args &... args)
|
void log(source_loc loc, level::level_enum lvl, string_view_t fmt, const Args &... args)
|
||||||
{
|
{
|
||||||
auto level_enabled = should_log(lvl);
|
bool log_enabled = should_log(lvl);
|
||||||
if (!level_enabled && !tracer_)
|
bool traceback_enabled = tracer_.enabled();
|
||||||
|
if (!log_enabled && !traceback_enabled)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -87,14 +87,7 @@ public:
|
|||||||
memory_buf_t buf;
|
memory_buf_t buf;
|
||||||
fmt::format_to(buf, fmt, args...);
|
fmt::format_to(buf, fmt, args...);
|
||||||
details::log_msg log_msg(loc, name_, lvl, string_view_t(buf.data(), buf.size()));
|
details::log_msg log_msg(loc, name_, lvl, string_view_t(buf.data(), buf.size()));
|
||||||
if (level_enabled)
|
log_it_(log_msg, log_enabled, traceback_enabled);
|
||||||
{
|
|
||||||
sink_it_(log_msg);
|
|
||||||
}
|
|
||||||
if (tracer_)
|
|
||||||
{
|
|
||||||
tracer_.push_back(log_msg);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
SPDLOG_LOGGER_CATCH()
|
SPDLOG_LOGGER_CATCH()
|
||||||
}
|
}
|
||||||
@ -151,24 +144,15 @@ public:
|
|||||||
template<class T, typename std::enable_if<std::is_convertible<const T &, spdlog::string_view_t>::value, T>::type * = nullptr>
|
template<class T, typename std::enable_if<std::is_convertible<const T &, spdlog::string_view_t>::value, T>::type * = nullptr>
|
||||||
void log(source_loc loc, level::level_enum lvl, const T &msg)
|
void log(source_loc loc, level::level_enum lvl, const T &msg)
|
||||||
{
|
{
|
||||||
auto level_enabled = should_log(lvl);
|
bool log_enabled = should_log(lvl);
|
||||||
if (!level_enabled && !tracer_)
|
bool traceback_enabled = tracer_.enabled();
|
||||||
|
if (!log_enabled && !traceback_enabled)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
SPDLOG_TRY
|
|
||||||
{
|
|
||||||
details::log_msg log_msg(loc, name_, lvl, msg);
|
details::log_msg log_msg(loc, name_, lvl, msg);
|
||||||
if (level_enabled)
|
log_it_(log_msg, log_enabled, traceback_enabled);
|
||||||
{
|
|
||||||
sink_it_(log_msg);
|
|
||||||
}
|
|
||||||
if (tracer_)
|
|
||||||
{
|
|
||||||
tracer_.push_back(log_msg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
SPDLOG_LOGGER_CATCH()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void log(level::level_enum lvl, string_view_t msg)
|
void log(level::level_enum lvl, string_view_t msg)
|
||||||
@ -229,8 +213,9 @@ public:
|
|||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
void log(source_loc loc, level::level_enum lvl, wstring_view_t fmt, const Args &... args)
|
void log(source_loc loc, level::level_enum lvl, wstring_view_t fmt, const Args &... args)
|
||||||
{
|
{
|
||||||
auto level_enabled = should_log(lvl);
|
bool log_enabled = should_log(lvl);
|
||||||
if (!level_enabled && !tracer_)
|
bool traceback_enabled = tracer_.enabled();
|
||||||
|
if (!log_enabled && !traceback_enabled)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -243,15 +228,7 @@ public:
|
|||||||
memory_buf_t buf;
|
memory_buf_t buf;
|
||||||
details::os::wstr_to_utf8buf(wstring_view_t(wbuf.data(), wbuf.size()), buf);
|
details::os::wstr_to_utf8buf(wstring_view_t(wbuf.data(), wbuf.size()), buf);
|
||||||
details::log_msg log_msg(loc, name_, lvl, string_view_t(buf.data(), buf.size()));
|
details::log_msg log_msg(loc, name_, lvl, string_view_t(buf.data(), buf.size()));
|
||||||
|
log_it_(log_msg, log_enabled, traceback_enabled);
|
||||||
if (level_enabled)
|
|
||||||
{
|
|
||||||
sink_it_(log_msg);
|
|
||||||
}
|
|
||||||
if (tracer_)
|
|
||||||
{
|
|
||||||
tracer_.push_back(log_msg);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
SPDLOG_LOGGER_CATCH()
|
SPDLOG_LOGGER_CATCH()
|
||||||
}
|
}
|
||||||
@ -302,25 +279,36 @@ public:
|
|||||||
template<class T, typename std::enable_if<is_convertible_to_wstring_view<const T &>::value, T>::type * = nullptr>
|
template<class T, typename std::enable_if<is_convertible_to_wstring_view<const T &>::value, T>::type * = nullptr>
|
||||||
void log(source_loc loc, level::level_enum lvl, const T &msg)
|
void log(source_loc loc, level::level_enum lvl, const T &msg)
|
||||||
{
|
{
|
||||||
if (!should_log(lvl))
|
bool log_enabled = should_log(lvl);
|
||||||
|
bool traceback_enabled = tracer_.enabled();
|
||||||
|
if (!log_enabled && !traceback_enabled)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
SPDLOG_TRY
|
||||||
{
|
{
|
||||||
memory_buf_t buf;
|
memory_buf_t buf;
|
||||||
details::os::wstr_to_utf8buf(msg, buf);
|
details::os::wstr_to_utf8buf(msg, buf);
|
||||||
|
|
||||||
details::log_msg log_msg(loc, name_, lvl, string_view_t(buf.data(), buf.size()));
|
details::log_msg log_msg(loc, name_, lvl, string_view_t(buf.data(), buf.size()));
|
||||||
sink_it_(log_msg);
|
log_it_(log_msg, log_enabled, traceback_enabled);
|
||||||
}
|
}
|
||||||
SPDLOG_LOGGER_CATCH()
|
SPDLOG_LOGGER_CATCH()
|
||||||
}
|
}
|
||||||
#endif // _WIN32
|
#endif // _WIN32
|
||||||
#endif // SPDLOG_WCHAR_TO_UTF8_SUPPORT
|
#endif // SPDLOG_WCHAR_TO_UTF8_SUPPORT
|
||||||
|
|
||||||
bool should_log(level::level_enum msg_level) const;
|
// return true logging is enabled for the given level.
|
||||||
|
bool should_log(level::level_enum msg_level) const
|
||||||
|
{
|
||||||
|
return msg_level >= level_.load(std::memory_order_relaxed);
|
||||||
|
}
|
||||||
|
|
||||||
|
// return true if backtrace logging is enabled.
|
||||||
|
bool should_backtrace() const
|
||||||
|
{
|
||||||
|
return tracer_.enabled();
|
||||||
|
}
|
||||||
|
|
||||||
void set_level(level::level_enum log_level);
|
void set_level(level::level_enum log_level);
|
||||||
|
|
||||||
@ -329,7 +317,7 @@ public:
|
|||||||
const std::string &name() const;
|
const std::string &name() const;
|
||||||
|
|
||||||
// set formatting for the sinks in this logger.
|
// set formatting for the sinks in this logger.
|
||||||
// each sink will get a seperate instance of the formatter object.
|
// each sink will get a separate instance of the formatter object.
|
||||||
void set_formatter(std::unique_ptr<formatter> f);
|
void set_formatter(std::unique_ptr<formatter> f);
|
||||||
|
|
||||||
void set_pattern(std::string pattern, pattern_time_type time_type = pattern_time_type::local);
|
void set_pattern(std::string pattern, pattern_time_type time_type = pattern_time_type::local);
|
||||||
@ -364,6 +352,9 @@ protected:
|
|||||||
err_handler custom_err_handler_{nullptr};
|
err_handler custom_err_handler_{nullptr};
|
||||||
details::backtracer tracer_;
|
details::backtracer tracer_;
|
||||||
|
|
||||||
|
// log the given message (if the given log level is high enough),
|
||||||
|
// and save backtrace (if backtrace is enabled).
|
||||||
|
void log_it_(const details::log_msg &log_msg, bool log_enabled, bool traceback_enabled);
|
||||||
virtual void sink_it_(const details::log_msg &msg);
|
virtual void sink_it_(const details::log_msg &msg);
|
||||||
virtual void flush_();
|
virtual void flush_();
|
||||||
void dump_backtrace_();
|
void dump_backtrace_();
|
||||||
|
@ -5,11 +5,11 @@
|
|||||||
|
|
||||||
#ifdef __ANDROID__
|
#ifdef __ANDROID__
|
||||||
|
|
||||||
#include "spdlog/details/fmt_helper.h"
|
#include <spdlog/details/fmt_helper.h>
|
||||||
#include "spdlog/details/null_mutex.h"
|
#include <spdlog/details/null_mutex.h>
|
||||||
#include "spdlog/details/os.h"
|
#include <spdlog/details/os.h>
|
||||||
#include "spdlog/sinks/base_sink.h"
|
#include <spdlog/sinks/base_sink.h>
|
||||||
#include "spdlog/details/synchronous_factory.h"
|
#include <spdlog/details/synchronous_factory.h>
|
||||||
|
|
||||||
#include <android/log.h>
|
#include <android/log.h>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
@ -4,11 +4,11 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#ifndef SPDLOG_HEADER_ONLY
|
#ifndef SPDLOG_HEADER_ONLY
|
||||||
#include "spdlog/sinks/ansicolor_sink.h"
|
#include <spdlog/sinks/ansicolor_sink.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "spdlog/details/pattern_formatter.h"
|
#include <spdlog/details/pattern_formatter.h>
|
||||||
#include "spdlog/details/os.h"
|
#include <spdlog/details/os.h>
|
||||||
|
|
||||||
namespace spdlog {
|
namespace spdlog {
|
||||||
namespace sinks {
|
namespace sinks {
|
||||||
|
@ -3,9 +3,9 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "spdlog/details/console_globals.h"
|
#include <spdlog/details/console_globals.h>
|
||||||
#include "spdlog/details/null_mutex.h"
|
#include <spdlog/details/null_mutex.h>
|
||||||
#include "spdlog/sinks/sink.h"
|
#include <spdlog/sinks/sink.h>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
@ -4,11 +4,11 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#ifndef SPDLOG_HEADER_ONLY
|
#ifndef SPDLOG_HEADER_ONLY
|
||||||
#include "spdlog/sinks/base_sink.h"
|
#include <spdlog/sinks/base_sink.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "spdlog/common.h"
|
#include <spdlog/common.h>
|
||||||
#include "spdlog/details/pattern_formatter.h"
|
#include <spdlog/details/pattern_formatter.h>
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
|
@ -9,9 +9,9 @@
|
|||||||
// implementers..
|
// implementers..
|
||||||
//
|
//
|
||||||
|
|
||||||
#include "spdlog/common.h"
|
#include <spdlog/common.h>
|
||||||
#include "spdlog/details/log_msg.h"
|
#include <spdlog/details/log_msg.h>
|
||||||
#include "spdlog/sinks/sink.h"
|
#include <spdlog/sinks/sink.h>
|
||||||
|
|
||||||
namespace spdlog {
|
namespace spdlog {
|
||||||
namespace sinks {
|
namespace sinks {
|
||||||
|
@ -4,11 +4,11 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#ifndef SPDLOG_HEADER_ONLY
|
#ifndef SPDLOG_HEADER_ONLY
|
||||||
#include "spdlog/sinks/basic_file_sink.h"
|
#include <spdlog/sinks/basic_file_sink.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "spdlog/common.h"
|
#include <spdlog/common.h>
|
||||||
#include "spdlog/details/os.h"
|
#include <spdlog/details/os.h>
|
||||||
|
|
||||||
namespace spdlog {
|
namespace spdlog {
|
||||||
namespace sinks {
|
namespace sinks {
|
||||||
|
@ -3,10 +3,10 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "spdlog/details/file_helper.h"
|
#include <spdlog/details/file_helper.h>
|
||||||
#include "spdlog/details/null_mutex.h"
|
#include <spdlog/details/null_mutex.h>
|
||||||
#include "spdlog/sinks/base_sink.h"
|
#include <spdlog/sinks/base_sink.h>
|
||||||
#include "spdlog/details/synchronous_factory.h"
|
#include <spdlog/details/synchronous_factory.h>
|
||||||
|
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
@ -3,13 +3,14 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "spdlog/common.h"
|
#include <spdlog/common.h>
|
||||||
#include "spdlog/details/file_helper.h"
|
#include <spdlog/details/file_helper.h>
|
||||||
#include "spdlog/details/null_mutex.h"
|
#include <spdlog/details/null_mutex.h>
|
||||||
#include "spdlog/fmt/fmt.h"
|
#include <spdlog/fmt/fmt.h>
|
||||||
#include "spdlog/sinks/base_sink.h"
|
#include <spdlog/sinks/base_sink.h>
|
||||||
#include "spdlog/details/os.h"
|
#include <spdlog/details/os.h>
|
||||||
#include "spdlog/details/synchronous_factory.h"
|
#include <spdlog/details/circular_q.h>
|
||||||
|
#include <spdlog/details/synchronous_factory.h>
|
||||||
|
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
@ -78,12 +79,7 @@ public:
|
|||||||
protected:
|
protected:
|
||||||
void sink_it_(const details::log_msg &msg) override
|
void sink_it_(const details::log_msg &msg) override
|
||||||
{
|
{
|
||||||
#ifdef SPDLOG_NO_DATETIME
|
|
||||||
auto time = log_clock::now();
|
|
||||||
#else
|
|
||||||
auto time = msg.time;
|
auto time = msg.time;
|
||||||
#endif
|
|
||||||
|
|
||||||
bool should_rotate = time >= rotation_tp_;
|
bool should_rotate = time >= rotation_tp_;
|
||||||
if (should_rotate)
|
if (should_rotate)
|
||||||
{
|
{
|
||||||
@ -95,7 +91,7 @@ protected:
|
|||||||
base_sink<Mutex>::formatter_->format(msg, formatted);
|
base_sink<Mutex>::formatter_->format(msg, formatted);
|
||||||
file_helper_.write(formatted);
|
file_helper_.write(formatted);
|
||||||
|
|
||||||
// Do the cleaning ony at the end because it might throw on failure.
|
// Do the cleaning only at the end because it might throw on failure.
|
||||||
if (should_rotate && max_files_ > 0)
|
if (should_rotate && max_files_ > 0)
|
||||||
{
|
{
|
||||||
delete_old_();
|
delete_old_();
|
||||||
|
@ -4,9 +4,9 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "base_sink.h"
|
#include "base_sink.h"
|
||||||
#include "spdlog/details/log_msg.h"
|
#include <spdlog/details/log_msg.h>
|
||||||
#include "spdlog/details/null_mutex.h"
|
#include <spdlog/details/null_mutex.h>
|
||||||
#include "spdlog/details/pattern_formatter.h"
|
#include <spdlog/details/pattern_formatter.h>
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
@ -24,6 +24,10 @@ class dist_sink : public base_sink<Mutex>
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
dist_sink() = default;
|
dist_sink() = default;
|
||||||
|
explicit dist_sink(std::vector<std::shared_ptr<sink>> sinks)
|
||||||
|
: sinks_(sinks)
|
||||||
|
{}
|
||||||
|
|
||||||
dist_sink(const dist_sink &) = delete;
|
dist_sink(const dist_sink &) = delete;
|
||||||
dist_sink &operator=(const dist_sink &) = delete;
|
dist_sink &operator=(const dist_sink &) = delete;
|
||||||
|
|
||||||
|
@ -4,8 +4,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "dist_sink.h"
|
#include "dist_sink.h"
|
||||||
#include "spdlog/details/null_mutex.h"
|
#include <spdlog/details/null_mutex.h>
|
||||||
#include "spdlog/details/log_msg.h"
|
#include <spdlog/details/log_msg.h>
|
||||||
|
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <string>
|
#include <string>
|
||||||
@ -16,7 +16,7 @@
|
|||||||
//
|
//
|
||||||
// Example:
|
// Example:
|
||||||
//
|
//
|
||||||
// #include "spdlog/sinks/dup_filter_sink.h"
|
// #include <spdlog/sinks/dup_filter_sink.h>
|
||||||
//
|
//
|
||||||
// int main() {
|
// int main() {
|
||||||
// auto dup_filter = std::make_shared<dup_filter_sink_st>(std::chrono::seconds(5));
|
// auto dup_filter = std::make_shared<dup_filter_sink_st>(std::chrono::seconds(5));
|
||||||
@ -33,10 +33,6 @@
|
|||||||
// [2019-06-25 17:50:56.512] [logger] [info] Skipped 3 duplicate messages..
|
// [2019-06-25 17:50:56.512] [logger] [info] Skipped 3 duplicate messages..
|
||||||
// [2019-06-25 17:50:56.512] [logger] [info] Different Hello
|
// [2019-06-25 17:50:56.512] [logger] [info] Different Hello
|
||||||
|
|
||||||
#ifdef SPDLOG_NO_DATETIME
|
|
||||||
#error "spdlog::sinks::dup_filter_sink: cannot work when SPDLOG_NO_DATETIME is defined"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace spdlog {
|
namespace spdlog {
|
||||||
namespace sinks {
|
namespace sinks {
|
||||||
template<typename Mutex>
|
template<typename Mutex>
|
||||||
|
@ -5,8 +5,8 @@
|
|||||||
|
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
|
|
||||||
#include "spdlog/details/null_mutex.h"
|
#include <spdlog/details/null_mutex.h>
|
||||||
#include "spdlog/sinks/base_sink.h"
|
#include <spdlog/sinks/base_sink.h>
|
||||||
|
|
||||||
#include <winbase.h>
|
#include <winbase.h>
|
||||||
|
|
||||||
|
@ -3,9 +3,9 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "spdlog/details/null_mutex.h"
|
#include <spdlog/details/null_mutex.h>
|
||||||
#include "spdlog/sinks/base_sink.h"
|
#include <spdlog/sinks/base_sink.h>
|
||||||
#include "spdlog/details/synchronous_factory.h"
|
#include <spdlog/details/synchronous_factory.h>
|
||||||
|
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
|
||||||
|
@ -3,8 +3,8 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "spdlog/details/null_mutex.h"
|
#include <spdlog/details/null_mutex.h>
|
||||||
#include "spdlog/sinks/base_sink.h"
|
#include <spdlog/sinks/base_sink.h>
|
||||||
|
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <ostream>
|
#include <ostream>
|
||||||
|
72
third_party/spdlog/include/spdlog/sinks/ringbuffer_sink.h
vendored
Normal file
72
third_party/spdlog/include/spdlog/sinks/ringbuffer_sink.h
vendored
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
|
||||||
|
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "spdlog/sinks/base_sink.h"
|
||||||
|
#include "spdlog/details/circular_q.h"
|
||||||
|
#include "spdlog/details/log_msg_buffer.h"
|
||||||
|
#include "spdlog/details/null_mutex.h"
|
||||||
|
|
||||||
|
#include <mutex>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace spdlog {
|
||||||
|
namespace sinks {
|
||||||
|
/*
|
||||||
|
* Ring buffer sink
|
||||||
|
*/
|
||||||
|
template<typename Mutex>
|
||||||
|
class ringbuffer_sink final : public base_sink<Mutex>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit ringbuffer_sink(size_t n_items)
|
||||||
|
: q_{n_items}
|
||||||
|
{}
|
||||||
|
|
||||||
|
std::vector<details::log_msg_buffer> last_raw(size_t lim = 0)
|
||||||
|
{
|
||||||
|
std::lock_guard<Mutex> lock(base_sink<Mutex>::mutex_);
|
||||||
|
auto n_items = lim > 0 ? (std::min)(lim, q_.size()) : q_.size();
|
||||||
|
std::vector<details::log_msg_buffer> ret;
|
||||||
|
ret.reserve(n_items);
|
||||||
|
for (size_t i = 0; i < n_items; i++)
|
||||||
|
{
|
||||||
|
ret.push_back(q_.at(i));
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> last_formatted(size_t lim = 0)
|
||||||
|
{
|
||||||
|
std::lock_guard<Mutex> lock(base_sink<Mutex>::mutex_);
|
||||||
|
auto n_items = lim > 0 ? (std::min)(lim, q_.size()) : q_.size();
|
||||||
|
std::vector<std::string> ret;
|
||||||
|
ret.reserve(n_items);
|
||||||
|
for (size_t i = 0; i < n_items; i++)
|
||||||
|
{
|
||||||
|
memory_buf_t formatted;
|
||||||
|
base_sink<Mutex>::formatter_->format(q_.at(i), formatted);
|
||||||
|
ret.push_back(fmt::to_string(formatted));
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void sink_it_(const details::log_msg &msg) override
|
||||||
|
{
|
||||||
|
q_.push_back(details::log_msg_buffer{msg});
|
||||||
|
}
|
||||||
|
void flush_() override {}
|
||||||
|
|
||||||
|
private:
|
||||||
|
details::circular_q<details::log_msg_buffer> q_;
|
||||||
|
};
|
||||||
|
|
||||||
|
using ringbuffer_sink_mt = ringbuffer_sink<std::mutex>;
|
||||||
|
using ringbuffer_sink_st = ringbuffer_sink<details::null_mutex>;
|
||||||
|
|
||||||
|
} // namespace sinks
|
||||||
|
|
||||||
|
} // namespace spdlog
|
@ -4,14 +4,14 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#ifndef SPDLOG_HEADER_ONLY
|
#ifndef SPDLOG_HEADER_ONLY
|
||||||
#include "spdlog/sinks/rotating_file_sink.h"
|
#include <spdlog/sinks/rotating_file_sink.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "spdlog/common.h"
|
#include <spdlog/common.h>
|
||||||
|
|
||||||
#include "spdlog/details/file_helper.h"
|
#include <spdlog/details/file_helper.h>
|
||||||
#include "spdlog/details/null_mutex.h"
|
#include <spdlog/details/null_mutex.h>
|
||||||
#include "spdlog/fmt/fmt.h"
|
#include <spdlog/fmt/fmt.h>
|
||||||
|
|
||||||
#include <cerrno>
|
#include <cerrno>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
@ -88,11 +88,12 @@ template<typename Mutex>
|
|||||||
SPDLOG_INLINE void rotating_file_sink<Mutex>::rotate_()
|
SPDLOG_INLINE void rotating_file_sink<Mutex>::rotate_()
|
||||||
{
|
{
|
||||||
using details::os::filename_to_str;
|
using details::os::filename_to_str;
|
||||||
|
using details::os::path_exists;
|
||||||
file_helper_.close();
|
file_helper_.close();
|
||||||
for (auto i = max_files_; i > 0; --i)
|
for (auto i = max_files_; i > 0; --i)
|
||||||
{
|
{
|
||||||
filename_t src = calc_filename(base_filename_, i - 1);
|
filename_t src = calc_filename(base_filename_, i - 1);
|
||||||
if (!details::file_helper::file_exists(src))
|
if (!path_exists(src))
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -3,10 +3,10 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "spdlog/sinks/base_sink.h"
|
#include <spdlog/sinks/base_sink.h>
|
||||||
#include "spdlog/details/file_helper.h"
|
#include <spdlog/details/file_helper.h>
|
||||||
#include "spdlog/details/null_mutex.h"
|
#include <spdlog/details/null_mutex.h>
|
||||||
#include "spdlog/details/synchronous_factory.h"
|
#include <spdlog/details/synchronous_factory.h>
|
||||||
|
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
@ -4,10 +4,10 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#ifndef SPDLOG_HEADER_ONLY
|
#ifndef SPDLOG_HEADER_ONLY
|
||||||
#include "spdlog/sinks/sink.h"
|
#include <spdlog/sinks/sink.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "spdlog/common.h"
|
#include <spdlog/common.h>
|
||||||
|
|
||||||
SPDLOG_INLINE bool spdlog::sinks::sink::should_log(spdlog::level::level_enum msg_level) const
|
SPDLOG_INLINE bool spdlog::sinks::sink::should_log(spdlog::level::level_enum msg_level) const
|
||||||
{
|
{
|
||||||
|
@ -3,8 +3,8 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "spdlog/details/log_msg.h"
|
#include <spdlog/details/log_msg.h>
|
||||||
#include "spdlog/formatter.h"
|
#include <spdlog/formatter.h>
|
||||||
|
|
||||||
namespace spdlog {
|
namespace spdlog {
|
||||||
|
|
||||||
|
@ -4,11 +4,11 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#ifndef SPDLOG_HEADER_ONLY
|
#ifndef SPDLOG_HEADER_ONLY
|
||||||
#include "spdlog/sinks/stdout_color_sinks.h"
|
#include <spdlog/sinks/stdout_color_sinks.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "spdlog/logger.h"
|
#include <spdlog/logger.h>
|
||||||
#include "spdlog/common.h"
|
#include <spdlog/common.h>
|
||||||
|
|
||||||
namespace spdlog {
|
namespace spdlog {
|
||||||
|
|
||||||
|
@ -4,12 +4,12 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#include "spdlog/sinks/wincolor_sink.h"
|
#include <spdlog/sinks/wincolor_sink.h>
|
||||||
#else
|
#else
|
||||||
#include "spdlog/sinks/ansicolor_sink.h"
|
#include <spdlog/sinks/ansicolor_sink.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "spdlog/details/synchronous_factory.h"
|
#include <spdlog/details/synchronous_factory.h>
|
||||||
|
|
||||||
namespace spdlog {
|
namespace spdlog {
|
||||||
namespace sinks {
|
namespace sinks {
|
||||||
|
@ -4,11 +4,11 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#ifndef SPDLOG_HEADER_ONLY
|
#ifndef SPDLOG_HEADER_ONLY
|
||||||
#include "spdlog/sinks/stdout_sinks.h"
|
#include <spdlog/sinks/stdout_sinks.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "spdlog/details/console_globals.h"
|
#include <spdlog/details/console_globals.h>
|
||||||
#include "spdlog/details/pattern_formatter.h"
|
#include <spdlog/details/pattern_formatter.h>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
namespace spdlog {
|
namespace spdlog {
|
||||||
|
@ -3,9 +3,9 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "spdlog/details/console_globals.h"
|
#include <spdlog/details/console_globals.h>
|
||||||
#include "spdlog/details/synchronous_factory.h"
|
#include <spdlog/details/synchronous_factory.h>
|
||||||
#include "spdlog/sinks/sink.h"
|
#include <spdlog/sinks/sink.h>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
|
|
||||||
namespace spdlog {
|
namespace spdlog {
|
||||||
|
@ -3,8 +3,8 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "spdlog/sinks/base_sink.h"
|
#include <spdlog/sinks/base_sink.h>
|
||||||
#include "spdlog/details/null_mutex.h"
|
#include <spdlog/details/null_mutex.h>
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
@ -3,10 +3,14 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "spdlog/sinks/base_sink.h"
|
#include <spdlog/sinks/base_sink.h>
|
||||||
#include "spdlog/details/null_mutex.h"
|
#include <spdlog/details/null_mutex.h>
|
||||||
#include "spdlog/details/synchronous_factory.h"
|
#include <spdlog/details/synchronous_factory.h>
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
#ifndef SD_JOURNAL_SUPPRESS_LOCATION
|
||||||
|
#define SD_JOURNAL_SUPPRESS_LOCATION
|
||||||
|
#endif
|
||||||
#include <systemd/sd-journal.h>
|
#include <systemd/sd-journal.h>
|
||||||
|
|
||||||
namespace spdlog {
|
namespace spdlog {
|
||||||
@ -56,13 +60,14 @@ protected:
|
|||||||
if (msg.source.empty())
|
if (msg.source.empty())
|
||||||
{
|
{
|
||||||
// Note: function call inside '()' to avoid macro expansion
|
// Note: function call inside '()' to avoid macro expansion
|
||||||
err = (sd_journal_send)(
|
err = (sd_journal_send)("MESSAGE=%.*s", static_cast<int>(length), msg.payload.data(), "PRIORITY=%d", syslog_level(msg.level),
|
||||||
"MESSAGE=%.*s", static_cast<int>(length), msg.payload.data(), "PRIORITY=%d", syslog_level(msg.level), nullptr);
|
"SYSLOG_IDENTIFIER=%.*s", static_cast<int>(msg.logger_name.size()), msg.logger_name.data(), nullptr);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
err = (sd_journal_send)("MESSAGE=%.*s", static_cast<int>(length), msg.payload.data(), "PRIORITY=%d", syslog_level(msg.level),
|
err = (sd_journal_send)("MESSAGE=%.*s", static_cast<int>(length), msg.payload.data(), "PRIORITY=%d", syslog_level(msg.level),
|
||||||
"SOURCE_FILE=%s", msg.source.filename, "SOURCE_LINE=%d", msg.source.line, "SOURCE_FUNC=%s", msg.source.funcname, nullptr);
|
"SYSLOG_IDENTIFIER=%.*s", static_cast<int>(msg.logger_name.size()), msg.logger_name.data(), "CODE_FILE=%s",
|
||||||
|
msg.source.filename, "CODE_LINE=%d", msg.source.line, "CODE_FUNC=%s", msg.source.funcname, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (err)
|
if (err)
|
||||||
|
@ -4,11 +4,11 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#ifndef SPDLOG_HEADER_ONLY
|
#ifndef SPDLOG_HEADER_ONLY
|
||||||
#include "spdlog/sinks/wincolor_sink.h"
|
#include <spdlog/sinks/wincolor_sink.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "spdlog/common.h"
|
#include <spdlog/common.h>
|
||||||
#include "spdlog/details/pattern_formatter.h"
|
#include <spdlog/details/pattern_formatter.h>
|
||||||
|
|
||||||
namespace spdlog {
|
namespace spdlog {
|
||||||
namespace sinks {
|
namespace sinks {
|
||||||
|
@ -3,10 +3,10 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "spdlog/common.h"
|
#include <spdlog/common.h>
|
||||||
#include "spdlog/details/console_globals.h"
|
#include <spdlog/details/console_globals.h>
|
||||||
#include "spdlog/details/null_mutex.h"
|
#include <spdlog/details/null_mutex.h>
|
||||||
#include "spdlog/sinks/sink.h"
|
#include <spdlog/sinks/sink.h>
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
10
third_party/spdlog/include/spdlog/spdlog-inl.h
vendored
10
third_party/spdlog/include/spdlog/spdlog-inl.h
vendored
@ -4,11 +4,11 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#ifndef SPDLOG_HEADER_ONLY
|
#ifndef SPDLOG_HEADER_ONLY
|
||||||
#include "spdlog/spdlog.h"
|
#include <spdlog/spdlog.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "spdlog/common.h"
|
#include <spdlog/common.h>
|
||||||
#include "spdlog/details/pattern_formatter.h"
|
#include <spdlog/details/pattern_formatter.h>
|
||||||
|
|
||||||
namespace spdlog {
|
namespace spdlog {
|
||||||
|
|
||||||
@ -92,9 +92,9 @@ SPDLOG_INLINE void shutdown()
|
|||||||
details::registry::instance().shutdown();
|
details::registry::instance().shutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
SPDLOG_INLINE void set_automatic_registration(bool automatic_registation)
|
SPDLOG_INLINE void set_automatic_registration(bool automatic_registration)
|
||||||
{
|
{
|
||||||
details::registry::instance().set_automatic_registration(automatic_registation);
|
details::registry::instance().set_automatic_registration(automatic_registration);
|
||||||
}
|
}
|
||||||
|
|
||||||
SPDLOG_INLINE std::shared_ptr<spdlog::logger> default_logger()
|
SPDLOG_INLINE std::shared_ptr<spdlog::logger> default_logger()
|
||||||
|
14
third_party/spdlog/include/spdlog/spdlog.h
vendored
14
third_party/spdlog/include/spdlog/spdlog.h
vendored
@ -9,11 +9,11 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "spdlog/common.h"
|
#include <spdlog/common.h>
|
||||||
#include "spdlog/details/registry.h"
|
#include <spdlog/details/registry.h>
|
||||||
#include "spdlog/logger.h"
|
#include <spdlog/logger.h>
|
||||||
#include "spdlog/version.h"
|
#include <spdlog/version.h>
|
||||||
#include "spdlog/details/synchronous_factory.h"
|
#include <spdlog/details/synchronous_factory.h>
|
||||||
|
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
@ -100,7 +100,7 @@ void drop_all();
|
|||||||
void shutdown();
|
void shutdown();
|
||||||
|
|
||||||
// Automatic registration of loggers when using spdlog::create() or spdlog::create_async
|
// Automatic registration of loggers when using spdlog::create() or spdlog::create_async
|
||||||
void set_automatic_registration(bool automatic_registation);
|
void set_automatic_registration(bool automatic_registration);
|
||||||
|
|
||||||
// API for using default logger (stdout_color_mt),
|
// API for using default logger (stdout_color_mt),
|
||||||
// e.g: spdlog::info("Message {}", 1);
|
// e.g: spdlog::info("Message {}", 1);
|
||||||
@ -285,7 +285,7 @@ inline void critical(wstring_view_t fmt, const Args &... args)
|
|||||||
// SPDLOG_LEVEL_OFF
|
// SPDLOG_LEVEL_OFF
|
||||||
//
|
//
|
||||||
|
|
||||||
#define SPDLOG_LOGGER_CALL(logger, level, ...) logger->log(spdlog::source_loc{__FILE__, __LINE__, SPDLOG_FUNCTION}, level, __VA_ARGS__)
|
#define SPDLOG_LOGGER_CALL(logger, level, ...) (logger)->log(spdlog::source_loc{__FILE__, __LINE__, SPDLOG_FUNCTION}, level, __VA_ARGS__)
|
||||||
|
|
||||||
#if SPDLOG_ACTIVE_LEVEL <= SPDLOG_LEVEL_TRACE
|
#if SPDLOG_ACTIVE_LEVEL <= SPDLOG_LEVEL_TRACE
|
||||||
#define SPDLOG_LOGGER_TRACE(logger, ...) SPDLOG_LOGGER_CALL(logger, spdlog::level::trace, __VA_ARGS__)
|
#define SPDLOG_LOGGER_TRACE(logger, ...) SPDLOG_LOGGER_CALL(logger, spdlog::level::trace, __VA_ARGS__)
|
||||||
|
13
third_party/spdlog/include/spdlog/tweakme.h
vendored
13
third_party/spdlog/include/spdlog/tweakme.h
vendored
@ -19,19 +19,6 @@
|
|||||||
// #define SPDLOG_CLOCK_COARSE
|
// #define SPDLOG_CLOCK_COARSE
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Uncomment if date/time logging is not needed and never appear in the log
|
|
||||||
// pattern.
|
|
||||||
// This will prevent spdlog from querying the clock on each log call.
|
|
||||||
//
|
|
||||||
// WARNING: If the log pattern contains any date/time while this flag is on, the
|
|
||||||
// result is undefined.
|
|
||||||
// You must set new pattern(spdlog::set_pattern(..") without any
|
|
||||||
// date/time in it
|
|
||||||
//
|
|
||||||
// #define SPDLOG_NO_DATETIME
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
// Uncomment if thread id logging is not needed (i.e. no %t in the log pattern).
|
// Uncomment if thread id logging is not needed (i.e. no %t in the log pattern).
|
||||||
// This will prevent spdlog from querying the thread id on each log call.
|
// This will prevent spdlog from querying the thread id on each log call.
|
||||||
|
4
third_party/spdlog/include/spdlog/version.h
vendored
4
third_party/spdlog/include/spdlog/version.h
vendored
@ -4,7 +4,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#define SPDLOG_VER_MAJOR 1
|
#define SPDLOG_VER_MAJOR 1
|
||||||
#define SPDLOG_VER_MINOR 4
|
#define SPDLOG_VER_MINOR 5
|
||||||
#define SPDLOG_VER_PATCH 1
|
#define SPDLOG_VER_PATCH 0
|
||||||
|
|
||||||
#define SPDLOG_VERSION (SPDLOG_VER_MAJOR * 10000 + SPDLOG_VER_MINOR * 100 + SPDLOG_VER_PATCH)
|
#define SPDLOG_VERSION (SPDLOG_VER_MAJOR * 10000 + SPDLOG_VER_MINOR * 100 + SPDLOG_VER_PATCH)
|
||||||
|
62
third_party/spdlog/meson.build
vendored
62
third_party/spdlog/meson.build
vendored
@ -21,7 +21,7 @@ dep_list += dependency('threads')
|
|||||||
# Check for FMT
|
# Check for FMT
|
||||||
if get_option('external_fmt')
|
if get_option('external_fmt')
|
||||||
if not meson.version().version_compare('>=0.49.0')
|
if not meson.version().version_compare('>=0.49.0')
|
||||||
warning('Finding fmt can fail wit meson versions before 0.49.0')
|
warning('Finding fmt can fail with meson versions before 0.49.0')
|
||||||
endif
|
endif
|
||||||
dep_list += dependency('fmt')
|
dep_list += dependency('fmt')
|
||||||
compile_args += '-DSPDLOG_FMT_EXTERNAL'
|
compile_args += '-DSPDLOG_FMT_EXTERNAL'
|
||||||
@ -31,6 +31,46 @@ if get_option('no_exceptions')
|
|||||||
compile_args += '-DSPDLOG_NO_EXCEPTIONS'
|
compile_args += '-DSPDLOG_NO_EXCEPTIONS'
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
if get_option('wchar_support')
|
||||||
|
if build_machine.system() != 'windows'
|
||||||
|
error('wchar_support only supported under windows')
|
||||||
|
endif
|
||||||
|
compile_args += '-DSPDLOG_WCHAR_TO_UTF8_SUPPORT'
|
||||||
|
endif
|
||||||
|
|
||||||
|
if get_option('wchar_filenames')
|
||||||
|
if build_machine.system() != 'windows'
|
||||||
|
error('wchar_filenames only supported under windows')
|
||||||
|
endif
|
||||||
|
compile_args += '-DSPDLOG_WCHAR_FILENAMES'
|
||||||
|
endif
|
||||||
|
|
||||||
|
if get_option('clock_coarse')
|
||||||
|
if build_machine.system() != 'linux'
|
||||||
|
error('clock_coarse only supported under linux')
|
||||||
|
endif
|
||||||
|
compile_args += '-DSPDLOG_CLOCK_COARSE'
|
||||||
|
endif
|
||||||
|
|
||||||
|
if get_option('prevent_child_fd')
|
||||||
|
compile_args += '-DSPDLOG_PREVENT_CHILD_FD'
|
||||||
|
endif
|
||||||
|
|
||||||
|
if get_option('no_thread_id')
|
||||||
|
compile_args += '-DSPDLOG_NO_THREAD_ID'
|
||||||
|
endif
|
||||||
|
|
||||||
|
if get_option('no_tls')
|
||||||
|
compile_args += '-DSPDLOG_NO_TLS'
|
||||||
|
endif
|
||||||
|
|
||||||
|
if get_option('no_atomic_levels')
|
||||||
|
compile_args += '-DSPDLOG_NO_ATOMIC_LEVELS'
|
||||||
|
endif
|
||||||
|
|
||||||
|
compile_args_compiled = compile_args + ['-DSPDLOG_COMPILED_LIB']
|
||||||
|
compile_args_ho = compile_args
|
||||||
|
|
||||||
# ------------------------------------
|
# ------------------------------------
|
||||||
# --- Compiled library version ---
|
# --- Compiled library version ---
|
||||||
# ------------------------------------
|
# ------------------------------------
|
||||||
@ -41,16 +81,19 @@ spdlog_srcs = files([
|
|||||||
'src/async.cpp',
|
'src/async.cpp',
|
||||||
'src/color_sinks.cpp',
|
'src/color_sinks.cpp',
|
||||||
'src/file_sinks.cpp',
|
'src/file_sinks.cpp',
|
||||||
'src/fmt.cpp',
|
|
||||||
'src/spdlog.cpp',
|
'src/spdlog.cpp',
|
||||||
'src/stdout_sinks.cpp'
|
'src/stdout_sinks.cpp'
|
||||||
])
|
])
|
||||||
|
|
||||||
|
if not get_option('external_fmt')
|
||||||
|
spdlog_srcs+= 'src/fmt.cpp'
|
||||||
|
endif
|
||||||
|
|
||||||
if get_option('library_type') == 'static'
|
if get_option('library_type') == 'static'
|
||||||
spdlog = static_library(
|
spdlog = static_library(
|
||||||
'spdlog',
|
'spdlog',
|
||||||
spdlog_srcs,
|
spdlog_srcs,
|
||||||
cpp_args : [compile_args] + ['-DSPDLOG_COMPILED_LIB'],
|
cpp_args : compile_args_compiled,
|
||||||
include_directories : spdlog_inc,
|
include_directories : spdlog_inc,
|
||||||
dependencies : dep_list,
|
dependencies : dep_list,
|
||||||
install : not meson.is_subproject()
|
install : not meson.is_subproject()
|
||||||
@ -58,17 +101,18 @@ if get_option('library_type') == 'static'
|
|||||||
else
|
else
|
||||||
spdlog = shared_library('spdlog',
|
spdlog = shared_library('spdlog',
|
||||||
spdlog_srcs,
|
spdlog_srcs,
|
||||||
cpp_args : [compile_args] + ['-DSPDLOG_COMPILED_LIB'],
|
cpp_args : compile_args_compiled,
|
||||||
include_directories : spdlog_inc,
|
include_directories : spdlog_inc,
|
||||||
dependencies : dep_list,
|
dependencies : dep_list,
|
||||||
install : not meson.is_subproject(),
|
install : not meson.is_subproject(),
|
||||||
|
version : meson.project_version(),
|
||||||
)
|
)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
spdlog_dep = declare_dependency(
|
spdlog_dep = declare_dependency(
|
||||||
link_with : spdlog,
|
link_with : spdlog,
|
||||||
include_directories : spdlog_inc,
|
include_directories : spdlog_inc,
|
||||||
compile_args : compile_args + ['-DSPDLOG_COMPILED_LIB'],
|
compile_args : compile_args_compiled,
|
||||||
dependencies : dep_list,
|
dependencies : dep_list,
|
||||||
version : meson.project_version(),
|
version : meson.project_version(),
|
||||||
)
|
)
|
||||||
@ -76,10 +120,9 @@ spdlog_dep = declare_dependency(
|
|||||||
# ----------------------------------
|
# ----------------------------------
|
||||||
# --- Header only dependency ---
|
# --- Header only dependency ---
|
||||||
# ----------------------------------
|
# ----------------------------------
|
||||||
|
|
||||||
spdlog_headeronly_dep = declare_dependency(
|
spdlog_headeronly_dep = declare_dependency(
|
||||||
include_directories : spdlog_inc,
|
include_directories : spdlog_inc,
|
||||||
compile_args : compile_args,
|
compile_args : compile_args_ho,
|
||||||
dependencies : dep_list,
|
dependencies : dep_list,
|
||||||
version : meson.project_version(),
|
version : meson.project_version(),
|
||||||
)
|
)
|
||||||
@ -97,7 +140,7 @@ if not meson.is_subproject()
|
|||||||
name : 'spdlog',
|
name : 'spdlog',
|
||||||
description : 'Fast C++ logging library',
|
description : 'Fast C++ logging library',
|
||||||
url : 'https://github.com/gabime/spdlog',
|
url : 'https://github.com/gabime/spdlog',
|
||||||
extra_cflags : ['-DSPDLOG_COMPILED_LIB']
|
extra_cflags : compile_args_compiled
|
||||||
)
|
)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
@ -105,7 +148,7 @@ endif
|
|||||||
# --- Conditionally add subdirs ---
|
# --- Conditionally add subdirs ---
|
||||||
# -------------------------------------
|
# -------------------------------------
|
||||||
|
|
||||||
if get_option('enable_tests')
|
if get_option('enable_tests') or get_option('enable_tests-ho')
|
||||||
subdir('tests')
|
subdir('tests')
|
||||||
endif
|
endif
|
||||||
|
|
||||||
@ -122,7 +165,6 @@ endif
|
|||||||
# -------------------
|
# -------------------
|
||||||
|
|
||||||
summary_str = '''spdlog build summary:
|
summary_str = '''spdlog build summary:
|
||||||
|
|
||||||
- using external fmt: @0@
|
- using external fmt: @0@
|
||||||
- building tests: @1@
|
- building tests: @1@
|
||||||
- building examples: @2@
|
- building examples: @2@
|
||||||
|
11
third_party/spdlog/meson_options.txt
vendored
11
third_party/spdlog/meson_options.txt
vendored
@ -1,6 +1,15 @@
|
|||||||
option('external_fmt', type: 'boolean', value: false, description: 'Use external fmt package instead of the bundled')
|
option('external_fmt', type: 'boolean', value: false, description: 'Use external fmt package instead of the bundled')
|
||||||
option('enable_examples', type: 'boolean', value: true, description: 'Build examples')
|
option('enable_examples', type: 'boolean', value: true, description: 'Build examples')
|
||||||
option('enable_benchmarks', type: 'boolean', value: false, description: 'Build benchmarks')
|
option('enable_benchmarks', type: 'boolean', value: false, description: 'Build benchmarks')
|
||||||
option('enable_tests', type: 'boolean', value: false, description: 'Build tests')
|
option('enable_tests', type: 'boolean', value: true, description: 'Build tests')
|
||||||
|
option('enable_tests_ho', type: 'boolean', value: false, description: 'Build header-only tests')
|
||||||
option('library_type', type: 'combo', choices: ['static', 'shared'], value: 'static', description: 'Library build type')
|
option('library_type', type: 'combo', choices: ['static', 'shared'], value: 'static', description: 'Library build type')
|
||||||
option('no_exceptions', type: 'boolean', value: false, description: 'Disabled exceptions - abort() instead any error')
|
option('no_exceptions', type: 'boolean', value: false, description: 'Disabled exceptions - abort() instead any error')
|
||||||
|
|
||||||
|
option('wchar_support', type: 'boolean', value: false, description:'(Windows only) Support wchar api')
|
||||||
|
option('wchar_filenames', type: 'boolean', value: false, description: '(Windows only) Support wchar filenames')
|
||||||
|
option('clock_coarse', type: 'boolean', value: false, description: '(Linux only) Use the much faster (but much less accurate) CLOCK_REALTIME_COARSE instead of the regular clock')
|
||||||
|
option('prevent_child_fd', type: 'boolean', value: false, description: 'Prevent from child processes to inherit log file descriptors')
|
||||||
|
option('no_thread_id', type: 'boolean', value: false, description: 'prevent spdlog from querying the thread id on each log call if thread id is not needed')
|
||||||
|
option('no_tls', type: 'boolean', value: false, description: 'prevent spdlog from using thread local storage')
|
||||||
|
option('no_atomic_levels', type: 'boolean', value: false, description: 'prevent spdlog from using of std::atomic log levels (use only if your code never modifies log levels concurrently')
|
||||||
|
15
third_party/spdlog/scripts/.clang-tidy
vendored
15
third_party/spdlog/scripts/.clang-tidy
vendored
@ -1,4 +1,17 @@
|
|||||||
Checks: 'modernize-*,modernize-use-override,google-*,-google-runtime-references,misc-*,clang-analyzer-*,-misc-non-private-member-variables-in-classes'
|
Checks: '\
|
||||||
|
cppcoreguidelines-*,\
|
||||||
|
performance-*,\
|
||||||
|
-performance-unnecessary-value-param,\
|
||||||
|
modernize-*,\
|
||||||
|
-modernize-use-trailing-return-type,\
|
||||||
|
google-*,\
|
||||||
|
-google-runtime-references,\
|
||||||
|
misc-*,\
|
||||||
|
-misc-non-private-member-variables-in-classes,\
|
||||||
|
cert-*,\
|
||||||
|
readability-*,\
|
||||||
|
clang-analyzer-*'
|
||||||
|
|
||||||
WarningsAsErrors: ''
|
WarningsAsErrors: ''
|
||||||
HeaderFilterRegex: 'async.h|async_logger.h|common.h|details|formatter.h|logger.h|sinks|spdlog.h|tweakme.h|version.h'
|
HeaderFilterRegex: 'async.h|async_logger.h|common.h|details|formatter.h|logger.h|sinks|spdlog.h|tweakme.h|version.h'
|
||||||
AnalyzeTemporaryDtors: false
|
AnalyzeTemporaryDtors: false
|
||||||
|
63
third_party/spdlog/src/fmt.cpp
vendored
63
third_party/spdlog/src/fmt.cpp
vendored
@ -6,30 +6,75 @@
|
|||||||
// Copyright (c) 2012 - 2016, Victor Zverovich
|
// Copyright (c) 2012 - 2016, Victor Zverovich
|
||||||
// All rights reserved.
|
// All rights reserved.
|
||||||
|
|
||||||
|
#if defined(__GNUC__) || defined(__clang__)
|
||||||
|
#pragma GCC diagnostic push
|
||||||
|
#pragma GCC diagnostic ignored "-Wimplicit-fallthrough"
|
||||||
|
#pragma GCC diagnostic ignored "-Wsign-conversion"
|
||||||
|
#endif
|
||||||
|
|
||||||
#if !defined(SPDLOG_FMT_EXTERNAL)
|
#if !defined(SPDLOG_FMT_EXTERNAL)
|
||||||
#include "spdlog/fmt/bundled/format-inl.h"
|
#include "spdlog/fmt/bundled/format-inl.h"
|
||||||
|
|
||||||
|
|
||||||
|
// pop warnings supressions
|
||||||
|
#if defined(__GNUC__) || defined(__clang__)
|
||||||
|
#pragma GCC diagnostic pop
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
FMT_BEGIN_NAMESPACE
|
FMT_BEGIN_NAMESPACE
|
||||||
template struct internal::basic_data<void>;
|
template struct FMT_API internal::basic_data<void>;
|
||||||
|
|
||||||
|
// Workaround a bug in MSVC2013 that prevents instantiation of format_float.
|
||||||
|
int (*instantiate_format_float)(double, int, internal::float_specs,
|
||||||
|
internal::buffer<char>&) =
|
||||||
|
internal::format_float;
|
||||||
|
|
||||||
|
#ifndef FMT_STATIC_THOUSANDS_SEPARATOR
|
||||||
template FMT_API internal::locale_ref::locale_ref(const std::locale& loc);
|
template FMT_API internal::locale_ref::locale_ref(const std::locale& loc);
|
||||||
template FMT_API std::locale internal::locale_ref::get<std::locale>() const;
|
template FMT_API std::locale internal::locale_ref::get<std::locale>() const;
|
||||||
|
#endif
|
||||||
|
|
||||||
// Explicit instantiations for char.
|
// Explicit instantiations for char.
|
||||||
|
|
||||||
|
template FMT_API std::string internal::grouping_impl<char>(locale_ref);
|
||||||
template FMT_API char internal::thousands_sep_impl(locale_ref);
|
template FMT_API char internal::thousands_sep_impl(locale_ref);
|
||||||
template FMT_API char internal::decimal_point_impl(locale_ref);
|
template FMT_API char internal::decimal_point_impl(locale_ref);
|
||||||
|
|
||||||
template FMT_API void internal::buffer<char>::append(const char*, const char*);
|
template FMT_API void internal::buffer<char>::append(const char*, const char*);
|
||||||
template FMT_API void internal::arg_map<format_context>::init(const basic_format_args<format_context> &args);
|
|
||||||
template FMT_API std::string internal::vformat<char>(string_view, basic_format_args<format_context>);
|
template FMT_API void internal::arg_map<format_context>::init(
|
||||||
template FMT_API format_context::iterator internal::vformat_to(internal::buffer<char> &, string_view, basic_format_args<format_context>);
|
const basic_format_args<format_context>& args);
|
||||||
template FMT_API char *internal::sprintf_format(double, internal::buffer<char> &, sprintf_specs);
|
|
||||||
template FMT_API char *internal::sprintf_format(long double, internal::buffer<char> &, sprintf_specs);
|
template FMT_API std::string internal::vformat<char>(
|
||||||
|
string_view, basic_format_args<format_context>);
|
||||||
|
|
||||||
|
template FMT_API format_context::iterator internal::vformat_to(
|
||||||
|
internal::buffer<char>&, string_view, basic_format_args<format_context>);
|
||||||
|
|
||||||
|
template FMT_API int internal::snprintf_float(double, int,
|
||||||
|
internal::float_specs,
|
||||||
|
internal::buffer<char>&);
|
||||||
|
template FMT_API int internal::snprintf_float(long double, int,
|
||||||
|
internal::float_specs,
|
||||||
|
internal::buffer<char>&);
|
||||||
|
template FMT_API int internal::format_float(double, int, internal::float_specs,
|
||||||
|
internal::buffer<char>&);
|
||||||
|
template FMT_API int internal::format_float(long double, int,
|
||||||
|
internal::float_specs,
|
||||||
|
internal::buffer<char>&);
|
||||||
|
|
||||||
// Explicit instantiations for wchar_t.
|
// Explicit instantiations for wchar_t.
|
||||||
|
|
||||||
|
template FMT_API std::string internal::grouping_impl<wchar_t>(locale_ref);
|
||||||
template FMT_API wchar_t internal::thousands_sep_impl(locale_ref);
|
template FMT_API wchar_t internal::thousands_sep_impl(locale_ref);
|
||||||
template FMT_API wchar_t internal::decimal_point_impl(locale_ref);
|
template FMT_API wchar_t internal::decimal_point_impl(locale_ref);
|
||||||
template FMT_API void internal::buffer<wchar_t>::append(const wchar_t *, const wchar_t *);
|
|
||||||
template FMT_API void internal::arg_map<wformat_context>::init(const basic_format_args<wformat_context> &);
|
template FMT_API void internal::buffer<wchar_t>::append(const wchar_t*,
|
||||||
template FMT_API std::wstring internal::vformat<wchar_t>(wstring_view, basic_format_args<wformat_context>);
|
const wchar_t*);
|
||||||
|
|
||||||
|
template FMT_API std::wstring internal::vformat<wchar_t>(
|
||||||
|
wstring_view, basic_format_args<wformat_context>);
|
||||||
FMT_END_NAMESPACE
|
FMT_END_NAMESPACE
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
46
third_party/spdlog/tests/CMakeLists.txt
vendored
46
third_party/spdlog/tests/CMakeLists.txt
vendored
@ -14,18 +14,16 @@ set(SPDLOG_UTESTS_SOURCES
|
|||||||
test_misc.cpp
|
test_misc.cpp
|
||||||
test_pattern_formatter.cpp
|
test_pattern_formatter.cpp
|
||||||
test_async.cpp
|
test_async.cpp
|
||||||
includes.h
|
|
||||||
test_registry.cpp
|
test_registry.cpp
|
||||||
test_macros.cpp
|
test_macros.cpp
|
||||||
utils.cpp
|
utils.cpp
|
||||||
utils.h
|
|
||||||
main.cpp
|
main.cpp
|
||||||
test_mpmc_q.cpp
|
test_mpmc_q.cpp
|
||||||
test_sink.h
|
test_dup_filter.cpp
|
||||||
test_fmt_helper.cpp
|
test_fmt_helper.cpp
|
||||||
test_stdout_api.cpp
|
test_stdout_api.cpp
|
||||||
test_dup_filter.cpp
|
test_backtrace.cpp
|
||||||
test_backtrace.cpp)
|
test_create_dir.cpp)
|
||||||
|
|
||||||
if(NOT SPDLOG_NO_EXCEPTIONS)
|
if(NOT SPDLOG_NO_EXCEPTIONS)
|
||||||
list(APPEND SPDLOG_UTESTS_SOURCES test_errors.cpp)
|
list(APPEND SPDLOG_UTESTS_SOURCES test_errors.cpp)
|
||||||
@ -35,34 +33,28 @@ if(systemd_FOUND)
|
|||||||
list(APPEND SPDLOG_UTESTS_SOURCES test_systemd.cpp)
|
list(APPEND SPDLOG_UTESTS_SOURCES test_systemd.cpp)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/logs")
|
|
||||||
enable_testing()
|
enable_testing()
|
||||||
|
|
||||||
|
function(spdlog_prepare_test test_target spdlog_lib)
|
||||||
|
add_executable(${test_target} ${SPDLOG_UTESTS_SOURCES})
|
||||||
|
spdlog_enable_warnings(${test_target})
|
||||||
|
target_link_libraries(${test_target} PRIVATE ${spdlog_lib})
|
||||||
|
if(systemd_FOUND)
|
||||||
|
target_link_libraries(${test_target} PRIVATE ${systemd_LIBRARIES})
|
||||||
|
endif()
|
||||||
|
if(SPDLOG_SANITIZE_ADDRESS)
|
||||||
|
spdlog_enable_sanitizer(${test_target})
|
||||||
|
endif()
|
||||||
|
add_test(NAME ${test_target} COMMAND ${test_target})
|
||||||
|
endfunction()
|
||||||
|
|
||||||
# The compiled library tests
|
# The compiled library tests
|
||||||
if(SPDLOG_BUILD_TESTS)
|
if(SPDLOG_BUILD_TESTS)
|
||||||
add_executable(spdlog-utests ${SPDLOG_UTESTS_SOURCES})
|
spdlog_prepare_test(spdlog-utests spdlog::spdlog)
|
||||||
spdlog_enable_warnings(spdlog-utests)
|
|
||||||
target_link_libraries(spdlog-utests PRIVATE spdlog)
|
|
||||||
|
|
||||||
if(systemd_FOUND)
|
|
||||||
target_link_libraries(spdlog-utests PRIVATE ${systemd_LIBRARIES})
|
|
||||||
endif()
|
|
||||||
if(SPDLOG_SANITIZE_ADDRESS)
|
|
||||||
spdlog_enable_sanitizer(spdlog-utests)
|
|
||||||
endif()
|
|
||||||
add_test(NAME spdlog-utests COMMAND spdlog-utests)
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# The header-only library version tests
|
# The header-only library version tests
|
||||||
if(SPDLOG_BUILD_TESTS_HO)
|
if(SPDLOG_BUILD_TESTS_HO)
|
||||||
add_executable(spdlog-utests-ho ${SPDLOG_UTESTS_SOURCES})
|
spdlog_prepare_test(spdlog-utests-ho spdlog::spdlog_header_only)
|
||||||
spdlog_enable_warnings(spdlog-utests-ho)
|
|
||||||
target_link_libraries(spdlog-utests-ho PRIVATE spdlog::spdlog_header_only)
|
|
||||||
if(systemd_FOUND)
|
|
||||||
target_link_libraries(spdlog-utests-ho PRIVATE ${systemd_LIBRARIES})
|
|
||||||
endif()
|
|
||||||
if(SPDLOG_SANITIZE_ADDRESS)
|
|
||||||
spdlog_set_address_sanitizer(spdlog-utests-ho)
|
|
||||||
endif()
|
|
||||||
add_test(NAME spdlog-utests-ho COMMAND spdlog-utests-ho)
|
|
||||||
endif()
|
endif()
|
||||||
|
27
third_party/spdlog/tests/meson.build
vendored
27
third_party/spdlog/tests/meson.build
vendored
@ -5,19 +5,18 @@ test_sources = files([
|
|||||||
'test_misc.cpp',
|
'test_misc.cpp',
|
||||||
'test_pattern_formatter.cpp',
|
'test_pattern_formatter.cpp',
|
||||||
'test_async.cpp',
|
'test_async.cpp',
|
||||||
'includes.h',
|
|
||||||
'test_registry.cpp',
|
'test_registry.cpp',
|
||||||
'test_macros.cpp',
|
'test_macros.cpp',
|
||||||
'utils.cpp',
|
'utils.cpp',
|
||||||
'main.cpp',
|
'main.cpp',
|
||||||
'test_mpmc_q.cpp',
|
'test_mpmc_q.cpp',
|
||||||
|
'test_dup_filter.cpp',
|
||||||
'test_fmt_helper.cpp',
|
'test_fmt_helper.cpp',
|
||||||
'test_stdout_api.cpp',
|
'test_stdout_api.cpp',
|
||||||
'test_dup_filter.cpp',
|
'test_backtrace.cpp',
|
||||||
'test_backtrace.cpp'
|
'test_create_dir.cpp'
|
||||||
])
|
])
|
||||||
|
|
||||||
|
|
||||||
if not get_option('no_exceptions')
|
if not get_option('no_exceptions')
|
||||||
test_sources += 'test_errors.cpp'
|
test_sources += 'test_errors.cpp'
|
||||||
endif
|
endif
|
||||||
@ -35,19 +34,15 @@ if systemd_dep.found()
|
|||||||
global_test_deps += systemd_dep
|
global_test_deps += systemd_dep
|
||||||
endif
|
endif
|
||||||
|
|
||||||
run_command('mkdir', 'logs')
|
|
||||||
# --------------------------------------
|
# --------------------------------------
|
||||||
# --- Build the test executables ---
|
# --- Build the test executables ---
|
||||||
# --------------------------------------
|
# --------------------------------------
|
||||||
|
if get_option('enable_tests')
|
||||||
|
test_exe = executable('spdlog-utests', test_sources, dependencies: global_test_deps + [spdlog_dep])
|
||||||
|
test('test_spdlog', test_exe, is_parallel : false)
|
||||||
|
endif
|
||||||
|
|
||||||
test_matrix = [
|
if get_option('enable_tests_ho')
|
||||||
['spdlog-utests', spdlog_dep],
|
test_exe = executable('spdlog-utests-ho', test_sources, dependencies: global_test_deps + [spdlog_headeronly_dep])
|
||||||
['spdlog-utests-ho', spdlog_headeronly_dep],
|
test('test_spdlog-ho', test_exe, is_parallel : false)
|
||||||
]
|
endif
|
||||||
|
|
||||||
foreach i : test_matrix
|
|
||||||
test_exe = executable(i[0], test_sources, dependencies: global_test_deps + [i[1]])
|
|
||||||
test('test_' + i[0], test_exe)
|
|
||||||
endforeach
|
|
||||||
|
|
||||||
run_command(find_program('mkdir'), meson.current_build_dir() + '/logs')
|
|
4
third_party/spdlog/tests/test_async.cpp
vendored
4
third_party/spdlog/tests/test_async.cpp
vendored
@ -157,7 +157,7 @@ TEST_CASE("to_file", "[async]")
|
|||||||
prepare_logdir();
|
prepare_logdir();
|
||||||
size_t messages = 1024;
|
size_t messages = 1024;
|
||||||
size_t tp_threads = 1;
|
size_t tp_threads = 1;
|
||||||
std::string filename = "logs/async_test.log";
|
std::string filename = "test_logs/async_test.log";
|
||||||
{
|
{
|
||||||
auto file_sink = std::make_shared<spdlog::sinks::basic_file_sink_mt>(filename, true);
|
auto file_sink = std::make_shared<spdlog::sinks::basic_file_sink_mt>(filename, true);
|
||||||
auto tp = std::make_shared<spdlog::details::thread_pool>(messages, tp_threads);
|
auto tp = std::make_shared<spdlog::details::thread_pool>(messages, tp_threads);
|
||||||
@ -179,7 +179,7 @@ TEST_CASE("to_file multi-workers", "[async]")
|
|||||||
prepare_logdir();
|
prepare_logdir();
|
||||||
size_t messages = 1024 * 10;
|
size_t messages = 1024 * 10;
|
||||||
size_t tp_threads = 10;
|
size_t tp_threads = 10;
|
||||||
std::string filename = "logs/async_test.log";
|
std::string filename = "test_logs/async_test.log";
|
||||||
{
|
{
|
||||||
auto file_sink = std::make_shared<spdlog::sinks::basic_file_sink_mt>(filename, true);
|
auto file_sink = std::make_shared<spdlog::sinks::basic_file_sink_mt>(filename, true);
|
||||||
auto tp = std::make_shared<spdlog::details::thread_pool>(messages, tp_threads);
|
auto tp = std::make_shared<spdlog::details::thread_pool>(messages, tp_threads);
|
||||||
|
80
third_party/spdlog/tests/test_create_dir.cpp
vendored
Normal file
80
third_party/spdlog/tests/test_create_dir.cpp
vendored
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
/*
|
||||||
|
* This content is released under the MIT License as specified in https://raw.githubusercontent.com/gabime/spdlog/master/LICENSE
|
||||||
|
*/
|
||||||
|
#include "includes.h"
|
||||||
|
|
||||||
|
using spdlog::details::os::create_dir;
|
||||||
|
using spdlog::details::os::path_exists;
|
||||||
|
|
||||||
|
bool try_create_dir(const char *path, const char *normalized_path)
|
||||||
|
{
|
||||||
|
auto rv = create_dir(path);
|
||||||
|
REQUIRE(rv == true);
|
||||||
|
return path_exists(normalized_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("create_dir", "[create_dir]")
|
||||||
|
{
|
||||||
|
prepare_logdir();
|
||||||
|
|
||||||
|
REQUIRE(try_create_dir("test_logs/dir1/dir1", "test_logs/dir1/dir1"));
|
||||||
|
REQUIRE(try_create_dir("test_logs/dir1/dir1", "test_logs/dir1/dir1")); // test existing
|
||||||
|
REQUIRE(try_create_dir("test_logs/dir1///dir2//", "test_logs/dir1/dir2"));
|
||||||
|
REQUIRE(try_create_dir("./test_logs/dir1/dir3", "test_logs/dir1/dir3"));
|
||||||
|
REQUIRE(try_create_dir("test_logs/../test_logs/dir1/dir4", "test_logs/dir1/dir4"));
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
// test backslash folder separator
|
||||||
|
REQUIRE(try_create_dir("test_logs\\dir1\\dir222", "test_logs\\dir1\\dir222"));
|
||||||
|
REQUIRE(try_create_dir("test_logs\\dir1\\dir223\\", "test_logs\\dir1\\dir223\\"));
|
||||||
|
REQUIRE(try_create_dir(".\\test_logs\\dir1\\dir2\\dir99\\..\\dir23", "test_logs\\dir1\\dir2\\dir23"));
|
||||||
|
REQUIRE(try_create_dir("test_logs\\..\\test_logs\\dir1\\dir5", "test_logs\\dir1\\dir5"));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("create_invalid_dir", "[create_dir]")
|
||||||
|
{
|
||||||
|
REQUIRE(create_dir("") == false);
|
||||||
|
REQUIRE(create_dir(spdlog::filename_t{}) == false);
|
||||||
|
#ifdef __linux__
|
||||||
|
REQUIRE(create_dir("/proc/spdlog-utest") == false);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("dir_name", "[create_dir]")
|
||||||
|
{
|
||||||
|
using spdlog::details::os::dir_name;
|
||||||
|
REQUIRE(dir_name("").empty());
|
||||||
|
REQUIRE(dir_name("dir").empty());
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
REQUIRE(dir_name(R"(dir\)") == "dir");
|
||||||
|
REQUIRE(dir_name(R"(dir\\\)") == R"(dir\\)");
|
||||||
|
REQUIRE(dir_name(R"(dir\file)") == "dir");
|
||||||
|
REQUIRE(dir_name(R"(dir/file)") == "dir");
|
||||||
|
REQUIRE(dir_name(R"(dir\file.txt)") == "dir");
|
||||||
|
REQUIRE(dir_name(R"(dir/file)") == "dir");
|
||||||
|
REQUIRE(dir_name(R"(dir\file.txt\)") == R"(dir\file.txt)");
|
||||||
|
REQUIRE(dir_name(R"(dir/file.txt/)") == R"(dir\file.txt)");
|
||||||
|
REQUIRE(dir_name(R"(\dir\file.txt)") == R"(\dir)");
|
||||||
|
REQUIRE(dir_name(R"(/dir/file.txt)") == R"(\dir)");
|
||||||
|
REQUIRE(dir_name(R"(\\dir\file.txt)") == R"(\\dir)");
|
||||||
|
REQUIRE(dir_name(R"(//dir/file.txt)") == R"(\\dir)");
|
||||||
|
REQUIRE(dir_name(R"(..\file.txt)") == "..");
|
||||||
|
REQUIRE(dir_name(R"(../file.txt)") == "..");
|
||||||
|
REQUIRE(dir_name(R"(.\file.txt)") == ".");
|
||||||
|
REQUIRE(dir_name(R"(./file.txt)") == ".");
|
||||||
|
REQUIRE(dir_name(R"(c:\\a\b\c\d\file.txt)") == R"(c:\\a\b\c\d)");
|
||||||
|
REQUIRE(dir_name(R"(c://a/b/c/d/file.txt)") == R"(c:\\a\b\c\d)");
|
||||||
|
#else
|
||||||
|
REQUIRE(dir_name("dir/") == "dir");
|
||||||
|
REQUIRE(dir_name("dir///") == "dir//");
|
||||||
|
REQUIRE(dir_name("dir/file") == "dir");
|
||||||
|
REQUIRE(dir_name("dir/file.txt") == "dir");
|
||||||
|
REQUIRE(dir_name("dir/file.txt/") == "dir/file.txt");
|
||||||
|
REQUIRE(dir_name("/dir/file.txt") == "/dir");
|
||||||
|
REQUIRE(dir_name("//dir/file.txt") == "//dir");
|
||||||
|
REQUIRE(dir_name("../file.txt") == "..");
|
||||||
|
REQUIRE(dir_name("./file.txt") == ".");
|
||||||
|
#endif
|
||||||
|
}
|
@ -10,7 +10,7 @@ TEST_CASE("daily_logger with dateonly calculator", "[daily_logger]")
|
|||||||
prepare_logdir();
|
prepare_logdir();
|
||||||
|
|
||||||
// calculate filename (time based)
|
// calculate filename (time based)
|
||||||
std::string basename = "logs/daily_dateonly";
|
std::string basename = "test_logs/daily_dateonly";
|
||||||
std::tm tm = spdlog::details::os::localtime();
|
std::tm tm = spdlog::details::os::localtime();
|
||||||
spdlog::memory_buf_t w;
|
spdlog::memory_buf_t w;
|
||||||
fmt::format_to(w, "{}_{:04d}-{:02d}-{:02d}", basename, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday);
|
fmt::format_to(w, "{}_{:04d}-{:02d}-{:02d}", basename, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday);
|
||||||
@ -44,7 +44,7 @@ TEST_CASE("daily_logger with custom calculator", "[daily_logger]")
|
|||||||
prepare_logdir();
|
prepare_logdir();
|
||||||
|
|
||||||
// calculate filename (time based)
|
// calculate filename (time based)
|
||||||
std::string basename = "logs/daily_dateonly";
|
std::string basename = "test_logs/daily_dateonly";
|
||||||
std::tm tm = spdlog::details::os::localtime();
|
std::tm tm = spdlog::details::os::localtime();
|
||||||
spdlog::memory_buf_t w;
|
spdlog::memory_buf_t w;
|
||||||
fmt::format_to(w, "{}{:04d}{:02d}{:02d}", basename, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday);
|
fmt::format_to(w, "{}{:04d}{:02d}{:02d}", basename, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday);
|
||||||
@ -119,7 +119,7 @@ static void test_rotate(int days_to_run, uint16_t max_days, uint16_t expected_n_
|
|||||||
|
|
||||||
prepare_logdir();
|
prepare_logdir();
|
||||||
|
|
||||||
std::string basename = "logs/daily_rotate.txt";
|
std::string basename = "test_logs/daily_rotate.txt";
|
||||||
daily_file_sink_st sink{basename, 2, 30, true, max_days};
|
daily_file_sink_st sink{basename, 2, 30, true, max_days};
|
||||||
|
|
||||||
// simulate messages with 24 intervals
|
// simulate messages with 24 intervals
|
||||||
@ -130,7 +130,7 @@ static void test_rotate(int days_to_run, uint16_t max_days, uint16_t expected_n_
|
|||||||
sink.log(create_msg(offset));
|
sink.log(create_msg(offset));
|
||||||
}
|
}
|
||||||
|
|
||||||
REQUIRE(count_files("logs") == static_cast<size_t>(expected_n_files));
|
REQUIRE(count_files("test_logs") == static_cast<size_t>(expected_n_files));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("daily_logger rotate", "[daily_file_sink]")
|
TEST_CASE("daily_logger rotate", "[daily_file_sink]")
|
||||||
|
19
third_party/spdlog/tests/test_errors.cpp
vendored
19
third_party/spdlog/tests/test_errors.cpp
vendored
@ -26,7 +26,7 @@ protected:
|
|||||||
TEST_CASE("default_error_handler", "[errors]]")
|
TEST_CASE("default_error_handler", "[errors]]")
|
||||||
{
|
{
|
||||||
prepare_logdir();
|
prepare_logdir();
|
||||||
std::string filename = "logs/simple_log.txt";
|
std::string filename = "test_logs/simple_log.txt";
|
||||||
|
|
||||||
auto logger = spdlog::create<spdlog::sinks::basic_file_sink_mt>("test-error", filename, true);
|
auto logger = spdlog::create<spdlog::sinks::basic_file_sink_mt>("test-error", filename, true);
|
||||||
logger->set_pattern("%v");
|
logger->set_pattern("%v");
|
||||||
@ -43,7 +43,7 @@ struct custom_ex
|
|||||||
TEST_CASE("custom_error_handler", "[errors]]")
|
TEST_CASE("custom_error_handler", "[errors]]")
|
||||||
{
|
{
|
||||||
prepare_logdir();
|
prepare_logdir();
|
||||||
std::string filename = "logs/simple_log.txt";
|
std::string filename = "test_logs/simple_log.txt";
|
||||||
auto logger = spdlog::create<spdlog::sinks::basic_file_sink_mt>("logger", filename, true);
|
auto logger = spdlog::create<spdlog::sinks::basic_file_sink_mt>("logger", filename, true);
|
||||||
logger->flush_on(spdlog::level::info);
|
logger->flush_on(spdlog::level::info);
|
||||||
logger->set_error_handler([=](const std::string &) { throw custom_ex(); });
|
logger->set_error_handler([=](const std::string &) { throw custom_ex(); });
|
||||||
@ -75,15 +75,15 @@ TEST_CASE("async_error_handler", "[errors]]")
|
|||||||
prepare_logdir();
|
prepare_logdir();
|
||||||
std::string err_msg("log failed with some msg");
|
std::string err_msg("log failed with some msg");
|
||||||
|
|
||||||
std::string filename = "logs/simple_async_log.txt";
|
std::string filename = "test_logs/simple_async_log.txt";
|
||||||
{
|
{
|
||||||
spdlog::init_thread_pool(128, 1);
|
spdlog::init_thread_pool(128, 1);
|
||||||
auto logger = spdlog::create_async<spdlog::sinks::basic_file_sink_mt>("logger", filename, true);
|
auto logger = spdlog::create_async<spdlog::sinks::basic_file_sink_mt>("logger", filename, true);
|
||||||
logger->set_error_handler([=](const std::string &) {
|
logger->set_error_handler([=](const std::string &) {
|
||||||
std::ofstream ofs("logs/custom_err.txt");
|
std::ofstream ofs("test_logs/custom_err.txt");
|
||||||
if (!ofs)
|
if (!ofs)
|
||||||
{
|
{
|
||||||
throw std::runtime_error("Failed open logs/custom_err.txt");
|
throw std::runtime_error("Failed open test_logs/custom_err.txt");
|
||||||
}
|
}
|
||||||
ofs << err_msg;
|
ofs << err_msg;
|
||||||
});
|
});
|
||||||
@ -94,7 +94,7 @@ TEST_CASE("async_error_handler", "[errors]]")
|
|||||||
}
|
}
|
||||||
spdlog::init_thread_pool(128, 1);
|
spdlog::init_thread_pool(128, 1);
|
||||||
REQUIRE(count_lines(filename) == 2);
|
REQUIRE(count_lines(filename) == 2);
|
||||||
REQUIRE(file_contents("logs/custom_err.txt") == err_msg);
|
REQUIRE(file_contents("test_logs/custom_err.txt") == err_msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure async error handler is executed
|
// Make sure async error handler is executed
|
||||||
@ -103,12 +103,13 @@ TEST_CASE("async_error_handler2", "[errors]]")
|
|||||||
prepare_logdir();
|
prepare_logdir();
|
||||||
std::string err_msg("This is async handler error message");
|
std::string err_msg("This is async handler error message");
|
||||||
{
|
{
|
||||||
|
spdlog::details::os::create_dir("test_logs");
|
||||||
spdlog::init_thread_pool(128, 1);
|
spdlog::init_thread_pool(128, 1);
|
||||||
auto logger = spdlog::create_async<failing_sink>("failed_logger");
|
auto logger = spdlog::create_async<failing_sink>("failed_logger");
|
||||||
logger->set_error_handler([=](const std::string &) {
|
logger->set_error_handler([=](const std::string &) {
|
||||||
std::ofstream ofs("logs/custom_err2.txt");
|
std::ofstream ofs("test_logs/custom_err2.txt");
|
||||||
if (!ofs)
|
if (!ofs)
|
||||||
throw std::runtime_error("Failed open logs/custom_err2.txt");
|
throw std::runtime_error("Failed open test_logs/custom_err2.txt");
|
||||||
ofs << err_msg;
|
ofs << err_msg;
|
||||||
});
|
});
|
||||||
logger->info("Hello failure");
|
logger->info("Hello failure");
|
||||||
@ -116,5 +117,5 @@ TEST_CASE("async_error_handler2", "[errors]]")
|
|||||||
}
|
}
|
||||||
|
|
||||||
spdlog::init_thread_pool(128, 1);
|
spdlog::init_thread_pool(128, 1);
|
||||||
REQUIRE(file_contents("logs/custom_err2.txt") == err_msg);
|
REQUIRE(file_contents("test_logs/custom_err2.txt") == err_msg);
|
||||||
}
|
}
|
||||||
|
11
third_party/spdlog/tests/test_file_helper.cpp
vendored
11
third_party/spdlog/tests/test_file_helper.cpp
vendored
@ -6,7 +6,7 @@
|
|||||||
using spdlog::details::file_helper;
|
using spdlog::details::file_helper;
|
||||||
using spdlog::details::log_msg;
|
using spdlog::details::log_msg;
|
||||||
|
|
||||||
static const std::string target_filename = "logs/file_helper_test.txt";
|
static const std::string target_filename = "test_logs/file_helper_test.txt";
|
||||||
|
|
||||||
static void write_with_helper(file_helper &helper, size_t howmany)
|
static void write_with_helper(file_helper &helper, size_t howmany)
|
||||||
{
|
{
|
||||||
@ -38,15 +38,6 @@ TEST_CASE("file_helper_size", "[file_helper::size()]]")
|
|||||||
REQUIRE(get_filesize(target_filename) == expected_size);
|
REQUIRE(get_filesize(target_filename) == expected_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("file_helper_exists", "[file_helper::file_exists()]]")
|
|
||||||
{
|
|
||||||
prepare_logdir();
|
|
||||||
REQUIRE(!file_helper::file_exists(target_filename));
|
|
||||||
file_helper helper;
|
|
||||||
helper.open(target_filename);
|
|
||||||
REQUIRE(file_helper::file_exists(target_filename));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("file_helper_reopen", "[file_helper::reopen()]]")
|
TEST_CASE("file_helper_reopen", "[file_helper::reopen()]]")
|
||||||
{
|
{
|
||||||
prepare_logdir();
|
prepare_logdir();
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
TEST_CASE("simple_file_logger", "[simple_logger]]")
|
TEST_CASE("simple_file_logger", "[simple_logger]]")
|
||||||
{
|
{
|
||||||
prepare_logdir();
|
prepare_logdir();
|
||||||
std::string filename = "logs/simple_log";
|
std::string filename = "test_logs/simple_log";
|
||||||
|
|
||||||
auto logger = spdlog::create<spdlog::sinks::basic_file_sink_mt>("logger", filename);
|
auto logger = spdlog::create<spdlog::sinks::basic_file_sink_mt>("logger", filename);
|
||||||
logger->set_pattern("%v");
|
logger->set_pattern("%v");
|
||||||
@ -22,7 +22,7 @@ TEST_CASE("simple_file_logger", "[simple_logger]]")
|
|||||||
TEST_CASE("flush_on", "[flush_on]]")
|
TEST_CASE("flush_on", "[flush_on]]")
|
||||||
{
|
{
|
||||||
prepare_logdir();
|
prepare_logdir();
|
||||||
std::string filename = "logs/simple_log";
|
std::string filename = "test_logs/simple_log";
|
||||||
|
|
||||||
auto logger = spdlog::create<spdlog::sinks::basic_file_sink_mt>("logger", filename);
|
auto logger = spdlog::create<spdlog::sinks::basic_file_sink_mt>("logger", filename);
|
||||||
logger->set_pattern("%v");
|
logger->set_pattern("%v");
|
||||||
@ -42,7 +42,7 @@ TEST_CASE("rotating_file_logger1", "[rotating_logger]]")
|
|||||||
{
|
{
|
||||||
prepare_logdir();
|
prepare_logdir();
|
||||||
size_t max_size = 1024 * 10;
|
size_t max_size = 1024 * 10;
|
||||||
std::string basename = "logs/rotating_log";
|
std::string basename = "test_logs/rotating_log";
|
||||||
auto logger = spdlog::rotating_logger_mt("logger", basename, max_size, 0);
|
auto logger = spdlog::rotating_logger_mt("logger", basename, max_size, 0);
|
||||||
|
|
||||||
for (int i = 0; i < 10; ++i)
|
for (int i = 0; i < 10; ++i)
|
||||||
@ -59,7 +59,7 @@ TEST_CASE("rotating_file_logger2", "[rotating_logger]]")
|
|||||||
{
|
{
|
||||||
prepare_logdir();
|
prepare_logdir();
|
||||||
size_t max_size = 1024 * 10;
|
size_t max_size = 1024 * 10;
|
||||||
std::string basename = "logs/rotating_log";
|
std::string basename = "test_logs/rotating_log";
|
||||||
|
|
||||||
{
|
{
|
||||||
// make an initial logger to create the first output file
|
// make an initial logger to create the first output file
|
||||||
|
20
third_party/spdlog/tests/test_macros.cpp
vendored
20
third_party/spdlog/tests/test_macros.cpp
vendored
@ -12,7 +12,7 @@ TEST_CASE("debug and trace w/o format string", "[macros]]")
|
|||||||
{
|
{
|
||||||
|
|
||||||
prepare_logdir();
|
prepare_logdir();
|
||||||
std::string filename = "logs/simple_log";
|
std::string filename = "test_logs/simple_log";
|
||||||
|
|
||||||
auto logger = spdlog::create<spdlog::sinks::basic_file_sink_mt>("logger", filename);
|
auto logger = spdlog::create<spdlog::sinks::basic_file_sink_mt>("logger", filename);
|
||||||
logger->set_pattern("%v");
|
logger->set_pattern("%v");
|
||||||
@ -39,3 +39,21 @@ TEST_CASE("disable param evaluation", "[macros]")
|
|||||||
{
|
{
|
||||||
SPDLOG_TRACE("Test message {}", throw std::runtime_error("Should not be evaluated"));
|
SPDLOG_TRACE("Test message {}", throw std::runtime_error("Should not be evaluated"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE("pass logger pointer", "[macros]")
|
||||||
|
{
|
||||||
|
auto logger = spdlog::create<spdlog::sinks::null_sink_mt>("refmacro");
|
||||||
|
auto &ref = *logger;
|
||||||
|
SPDLOG_LOGGER_TRACE(&ref, "Test message 1");
|
||||||
|
SPDLOG_LOGGER_DEBUG(&ref, "Test message 2");
|
||||||
|
}
|
||||||
|
|
||||||
|
// ensure that even if right macro level is on- don't evaluate if the logger's level is not high enough
|
||||||
|
// TEST_CASE("disable param evaluation2", "[macros]")
|
||||||
|
//{
|
||||||
|
// auto logger = std::make_shared<spdlog::logger>("test-macro");
|
||||||
|
// logger->set_level(spdlog::level::off);
|
||||||
|
// int x = 0;
|
||||||
|
// SPDLOG_LOGGER_DEBUG(logger, "Test message {}", ++x);
|
||||||
|
// REQUIRE(x == 0);
|
||||||
|
//}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
#include "includes.h"
|
#include "includes.h"
|
||||||
|
#include "test_sink.h"
|
||||||
|
|
||||||
using spdlog::memory_buf_t;
|
using spdlog::memory_buf_t;
|
||||||
|
|
||||||
@ -138,58 +139,111 @@ TEST_CASE("color range test6", "[pattern_formatter]")
|
|||||||
TEST_CASE("level_left_padded", "[pattern_formatter]")
|
TEST_CASE("level_left_padded", "[pattern_formatter]")
|
||||||
{
|
{
|
||||||
REQUIRE(log_to_str("Some message", "[%8l] %v", spdlog::pattern_time_type::local, "\n") == "[ info] Some message\n");
|
REQUIRE(log_to_str("Some message", "[%8l] %v", spdlog::pattern_time_type::local, "\n") == "[ info] Some message\n");
|
||||||
|
REQUIRE(log_to_str("Some message", "[%8!l] %v", spdlog::pattern_time_type::local, "\n") == "[ info] Some message\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("level_right_padded", "[pattern_formatter]")
|
TEST_CASE("level_right_padded", "[pattern_formatter]")
|
||||||
{
|
{
|
||||||
REQUIRE(log_to_str("Some message", "[%-8l] %v", spdlog::pattern_time_type::local, "\n") == "[info ] Some message\n");
|
REQUIRE(log_to_str("Some message", "[%-8l] %v", spdlog::pattern_time_type::local, "\n") == "[info ] Some message\n");
|
||||||
|
REQUIRE(log_to_str("Some message", "[%-8!l] %v", spdlog::pattern_time_type::local, "\n") == "[info ] Some message\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("level_center_padded", "[pattern_formatter]")
|
TEST_CASE("level_center_padded", "[pattern_formatter]")
|
||||||
{
|
{
|
||||||
REQUIRE(log_to_str("Some message", "[%=8l] %v", spdlog::pattern_time_type::local, "\n") == "[ info ] Some message\n");
|
REQUIRE(log_to_str("Some message", "[%=8l] %v", spdlog::pattern_time_type::local, "\n") == "[ info ] Some message\n");
|
||||||
|
REQUIRE(log_to_str("Some message", "[%=8!l] %v", spdlog::pattern_time_type::local, "\n") == "[ info ] Some message\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("short level_left_padded", "[pattern_formatter]")
|
TEST_CASE("short level_left_padded", "[pattern_formatter]")
|
||||||
{
|
{
|
||||||
REQUIRE(log_to_str("Some message", "[%3L] %v", spdlog::pattern_time_type::local, "\n") == "[ I] Some message\n");
|
REQUIRE(log_to_str("Some message", "[%3L] %v", spdlog::pattern_time_type::local, "\n") == "[ I] Some message\n");
|
||||||
|
REQUIRE(log_to_str("Some message", "[%3!L] %v", spdlog::pattern_time_type::local, "\n") == "[ I] Some message\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("short level_right_padded", "[pattern_formatter]")
|
TEST_CASE("short level_right_padded", "[pattern_formatter]")
|
||||||
{
|
{
|
||||||
REQUIRE(log_to_str("Some message", "[%-3L] %v", spdlog::pattern_time_type::local, "\n") == "[I ] Some message\n");
|
REQUIRE(log_to_str("Some message", "[%-3L] %v", spdlog::pattern_time_type::local, "\n") == "[I ] Some message\n");
|
||||||
|
REQUIRE(log_to_str("Some message", "[%-3!L] %v", spdlog::pattern_time_type::local, "\n") == "[I ] Some message\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("short level_center_padded", "[pattern_formatter]")
|
TEST_CASE("short level_center_padded", "[pattern_formatter]")
|
||||||
{
|
{
|
||||||
REQUIRE(log_to_str("Some message", "[%=3L] %v", spdlog::pattern_time_type::local, "\n") == "[ I ] Some message\n");
|
REQUIRE(log_to_str("Some message", "[%=3L] %v", spdlog::pattern_time_type::local, "\n") == "[ I ] Some message\n");
|
||||||
|
REQUIRE(log_to_str("Some message", "[%=3!L] %v", spdlog::pattern_time_type::local, "\n") == "[ I ] Some message\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("left_padded_short", "[pattern_formatter]")
|
TEST_CASE("left_padded_short", "[pattern_formatter]")
|
||||||
{
|
{
|
||||||
REQUIRE(log_to_str("Some message", "[%3n] %v", spdlog::pattern_time_type::local, "\n") == "[pattern_tester] Some message\n");
|
REQUIRE(log_to_str("Some message", "[%3n] %v", spdlog::pattern_time_type::local, "\n") == "[pattern_tester] Some message\n");
|
||||||
|
REQUIRE(log_to_str("Some message", "[%3!n] %v", spdlog::pattern_time_type::local, "\n") == "[pat] Some message\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("right_padded_short", "[pattern_formatter]")
|
TEST_CASE("right_padded_short", "[pattern_formatter]")
|
||||||
{
|
{
|
||||||
REQUIRE(log_to_str("Some message", "[%-3n] %v", spdlog::pattern_time_type::local, "\n") == "[pattern_tester] Some message\n");
|
REQUIRE(log_to_str("Some message", "[%-3n] %v", spdlog::pattern_time_type::local, "\n") == "[pattern_tester] Some message\n");
|
||||||
|
REQUIRE(log_to_str("Some message", "[%-3!n] %v", spdlog::pattern_time_type::local, "\n") == "[pat] Some message\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("center_padded_short", "[pattern_formatter]")
|
TEST_CASE("center_padded_short", "[pattern_formatter]")
|
||||||
{
|
{
|
||||||
REQUIRE(log_to_str("Some message", "[%=3n] %v", spdlog::pattern_time_type::local, "\n") == "[pattern_tester] Some message\n");
|
REQUIRE(log_to_str("Some message", "[%=3n] %v", spdlog::pattern_time_type::local, "\n") == "[pattern_tester] Some message\n");
|
||||||
|
REQUIRE(log_to_str("Some message", "[%=3!n] %v", spdlog::pattern_time_type::local, "\n") == "[pat] Some message\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("left_padded_huge", "[pattern_formatter]")
|
TEST_CASE("left_padded_huge", "[pattern_formatter]")
|
||||||
{
|
{
|
||||||
REQUIRE(log_to_str("Some message", "[%-300n] %v", spdlog::pattern_time_type::local, "\n") ==
|
REQUIRE(log_to_str("Some message", "[%-300n] %v", spdlog::pattern_time_type::local, "\n") ==
|
||||||
"[pattern_tester ] Some message\n");
|
"[pattern_tester ] Some message\n");
|
||||||
|
|
||||||
|
REQUIRE(log_to_str("Some message", "[%-300!n] %v", spdlog::pattern_time_type::local, "\n") ==
|
||||||
|
"[pattern_tester ] Some message\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("left_padded_max", "[pattern_formatter]")
|
TEST_CASE("left_padded_max", "[pattern_formatter]")
|
||||||
{
|
{
|
||||||
REQUIRE(log_to_str("Some message", "[%-64n] %v", spdlog::pattern_time_type::local, "\n") ==
|
REQUIRE(log_to_str("Some message", "[%-64n] %v", spdlog::pattern_time_type::local, "\n") ==
|
||||||
"[pattern_tester ] Some message\n");
|
"[pattern_tester ] Some message\n");
|
||||||
|
|
||||||
|
REQUIRE(log_to_str("Some message", "[%-64!n] %v", spdlog::pattern_time_type::local, "\n") ==
|
||||||
|
"[pattern_tester ] Some message\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test padding + truncate flag
|
||||||
|
|
||||||
|
TEST_CASE("paddinng_truncate", "[pattern_formatter]")
|
||||||
|
{
|
||||||
|
REQUIRE(log_to_str("123456", "%6!v", spdlog::pattern_time_type::local, "\n") == "123456\n");
|
||||||
|
REQUIRE(log_to_str("123456", "%5!v", spdlog::pattern_time_type::local, "\n") == "12345\n");
|
||||||
|
REQUIRE(log_to_str("123456", "%7!v", spdlog::pattern_time_type::local, "\n") == " 123456\n");
|
||||||
|
|
||||||
|
REQUIRE(log_to_str("123456", "%-6!v", spdlog::pattern_time_type::local, "\n") == "123456\n");
|
||||||
|
REQUIRE(log_to_str("123456", "%-5!v", spdlog::pattern_time_type::local, "\n") == "12345\n");
|
||||||
|
REQUIRE(log_to_str("123456", "%-7!v", spdlog::pattern_time_type::local, "\n") == "123456 \n");
|
||||||
|
|
||||||
|
REQUIRE(log_to_str("123456", "%=6!v", spdlog::pattern_time_type::local, "\n") == "123456\n");
|
||||||
|
REQUIRE(log_to_str("123456", "%=5!v", spdlog::pattern_time_type::local, "\n") == "12345\n");
|
||||||
|
REQUIRE(log_to_str("123456", "%=7!v", spdlog::pattern_time_type::local, "\n") == "123456 \n");
|
||||||
|
|
||||||
|
REQUIRE(log_to_str("123456", "%0!v", spdlog::pattern_time_type::local, "\n") == "\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("paddinng_truncate_funcname", "[pattern_formatter]")
|
||||||
|
{
|
||||||
|
spdlog::sinks::test_sink_st test_sink;
|
||||||
|
|
||||||
|
const char *pattern = "%v [%5!!]";
|
||||||
|
auto formatter = std::unique_ptr<spdlog::formatter>(new spdlog::pattern_formatter(pattern));
|
||||||
|
test_sink.set_formatter(std::move(formatter));
|
||||||
|
|
||||||
|
spdlog::details::log_msg msg1{spdlog::source_loc{"ignored", 1, "func"}, "test_logger", spdlog::level::info, "message"};
|
||||||
|
test_sink.log(msg1);
|
||||||
|
|
||||||
|
spdlog::details::log_msg msg2{spdlog::source_loc{"ignored", 1, "function"}, "test_logger", spdlog::level::info, "message"};
|
||||||
|
test_sink.log(msg2);
|
||||||
|
|
||||||
|
auto lines = test_sink.lines();
|
||||||
|
REQUIRE(lines[0] == "message [ func]");
|
||||||
|
REQUIRE(lines[1] == "message [funct]");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("clone-default-formatter", "[pattern_formatter]")
|
TEST_CASE("clone-default-formatter", "[pattern_formatter]")
|
||||||
|
4
third_party/spdlog/tests/test_registry.cpp
vendored
4
third_party/spdlog/tests/test_registry.cpp
vendored
@ -9,7 +9,7 @@ TEST_CASE("register_drop", "[registry]")
|
|||||||
spdlog::drop_all();
|
spdlog::drop_all();
|
||||||
spdlog::create<spdlog::sinks::null_sink_mt>(tested_logger_name);
|
spdlog::create<spdlog::sinks::null_sink_mt>(tested_logger_name);
|
||||||
REQUIRE(spdlog::get(tested_logger_name) != nullptr);
|
REQUIRE(spdlog::get(tested_logger_name) != nullptr);
|
||||||
// Throw if registring existing name
|
// Throw if registering existing name
|
||||||
REQUIRE_THROWS_AS(spdlog::create<spdlog::sinks::null_sink_mt>(tested_logger_name), spdlog::spdlog_ex);
|
REQUIRE_THROWS_AS(spdlog::create<spdlog::sinks::null_sink_mt>(tested_logger_name), spdlog::spdlog_ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -19,7 +19,7 @@ TEST_CASE("explicit register", "[registry]")
|
|||||||
auto logger = std::make_shared<spdlog::logger>(tested_logger_name, std::make_shared<spdlog::sinks::null_sink_st>());
|
auto logger = std::make_shared<spdlog::logger>(tested_logger_name, std::make_shared<spdlog::sinks::null_sink_st>());
|
||||||
spdlog::register_logger(logger);
|
spdlog::register_logger(logger);
|
||||||
REQUIRE(spdlog::get(tested_logger_name) != nullptr);
|
REQUIRE(spdlog::get(tested_logger_name) != nullptr);
|
||||||
// Throw if registring existing name
|
// Throw if registering existing name
|
||||||
REQUIRE_THROWS_AS(spdlog::create<spdlog::sinks::null_sink_mt>(tested_logger_name), spdlog::spdlog_ex);
|
REQUIRE_THROWS_AS(spdlog::create<spdlog::sinks::null_sink_mt>(tested_logger_name), spdlog::spdlog_ex);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
12
third_party/spdlog/tests/utils.cpp
vendored
12
third_party/spdlog/tests/utils.cpp
vendored
@ -9,18 +9,12 @@ void prepare_logdir()
|
|||||||
{
|
{
|
||||||
spdlog::drop_all();
|
spdlog::drop_all();
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
system("if not exist logs mkdir logs");
|
system("rmdir /S /Q test_logs");
|
||||||
system("del /F /Q logs\\*");
|
|
||||||
#else
|
#else
|
||||||
auto rv = system("mkdir -p logs");
|
auto rv = system("rm -rf test_logs");
|
||||||
if (rv != 0)
|
if (rv != 0)
|
||||||
{
|
{
|
||||||
throw std::runtime_error("Failed to mkdir -p logs");
|
throw std::runtime_error("Failed to rm -rf test_logs");
|
||||||
}
|
|
||||||
rv = system("rm -f logs/*");
|
|
||||||
if (rv != 0)
|
|
||||||
{
|
|
||||||
throw std::runtime_error("Failed to rm -f logs/*");
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user