update and change how we build with spdlog
This commit is contained in:
		| @@ -218,6 +218,8 @@ if (USE_WS OR USE_TEST) | |||||||
|   add_subdirectory(ixcobra) |   add_subdirectory(ixcobra) | ||||||
|   add_subdirectory(ixsnake) |   add_subdirectory(ixsnake) | ||||||
|  |  | ||||||
|  |   add_subdirectory(third_party/spdlog spdlog) | ||||||
|  |  | ||||||
|   if (USE_WS) |   if (USE_WS) | ||||||
|       add_subdirectory(ws) |       add_subdirectory(ws) | ||||||
|   endif() |   endif() | ||||||
|   | |||||||
							
								
								
									
										1
									
								
								third_party/spdlog/.gitattributes
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								third_party/spdlog/.gitattributes
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | |||||||
|  | * text=false | ||||||
							
								
								
									
										15
									
								
								third_party/spdlog/.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										15
									
								
								third_party/spdlog/.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -34,6 +34,9 @@ build/* | |||||||
| # Codelite | # Codelite | ||||||
| .codelite | .codelite | ||||||
|  |  | ||||||
|  | # KDevelop | ||||||
|  | *.kdev4 | ||||||
|  |  | ||||||
| # .orig files | # .orig files | ||||||
| *.orig | *.orig | ||||||
|  |  | ||||||
| @@ -46,6 +49,7 @@ example/* | |||||||
| !example/example.sln | !example/example.sln | ||||||
| !example/example.vcxproj | !example/example.vcxproj | ||||||
| !example/CMakeLists.txt | !example/CMakeLists.txt | ||||||
|  | !example/meson.build | ||||||
| !example/multisink.cpp | !example/multisink.cpp | ||||||
| !example/jni | !example/jni | ||||||
|  |  | ||||||
| @@ -66,3 +70,14 @@ install_manifest.txt | |||||||
|  |  | ||||||
| # idea | # idea | ||||||
| .idea/ | .idea/ | ||||||
|  | cmake-build-*/ | ||||||
|  | *.db | ||||||
|  | *.ipch | ||||||
|  | *.filters | ||||||
|  | *.db-wal | ||||||
|  | *.opendb | ||||||
|  | *.db-shm | ||||||
|  | *.vcxproj | ||||||
|  | *.tcl | ||||||
|  | *.user | ||||||
|  | *.sln | ||||||
|   | |||||||
							
								
								
									
										41
									
								
								third_party/spdlog/.travis.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										41
									
								
								third_party/spdlog/.travis.yml
									
									
									
									
										vendored
									
									
								
							| @@ -5,6 +5,7 @@ | |||||||
| sudo: required | sudo: required | ||||||
| language: cpp | language: cpp | ||||||
|  |  | ||||||
|  | # gcc 4.8 | ||||||
| addons: &gcc48 | addons: &gcc48 | ||||||
|   apt: |   apt: | ||||||
|     packages: |     packages: | ||||||
| @@ -12,6 +13,7 @@ addons: &gcc48 | |||||||
|     sources: |     sources: | ||||||
|       - ubuntu-toolchain-r-test |       - ubuntu-toolchain-r-test | ||||||
|  |  | ||||||
|  | # gcc 7.0 | ||||||
| addons: &gcc7 | addons: &gcc7 | ||||||
|   apt: |   apt: | ||||||
|     packages: |     packages: | ||||||
| @@ -19,6 +21,7 @@ addons: &gcc7 | |||||||
|     sources: |     sources: | ||||||
|       - ubuntu-toolchain-r-test |       - ubuntu-toolchain-r-test | ||||||
|  |  | ||||||
|  | # Clang 3.5 | ||||||
| addons: &clang35 | addons: &clang35 | ||||||
|   apt: |   apt: | ||||||
|     packages: |     packages: | ||||||
| @@ -27,13 +30,15 @@ addons: &clang35 | |||||||
|       - ubuntu-toolchain-r-test |       - ubuntu-toolchain-r-test | ||||||
|       - llvm-toolchain-precise-3.5 |       - llvm-toolchain-precise-3.5 | ||||||
|        |        | ||||||
| addons: &clang6 | # Clang 7.0 | ||||||
|  | addons: &clang70 | ||||||
|   apt: |   apt: | ||||||
|     packages: |     packages: | ||||||
|       - clang-6.0 |       - clang-7       | ||||||
|     sources: |     sources: | ||||||
|       - ubuntu-toolchain-r-test |       - ubuntu-toolchain-r-test | ||||||
|       - llvm-toolchain-trusty-6.0 |       - llvm-toolchain-trusty-7 | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| matrix: | matrix: | ||||||
| @@ -60,23 +65,12 @@ matrix: | |||||||
|       os: linux |       os: linux | ||||||
|       addons: *clang35 |       addons: *clang35 | ||||||
|  |  | ||||||
|       # Test clang-6.0: C++11, Build=Debug, ASAN=On |       # Test clang-7.0: C++11, Build=Debug, ASAN=On | ||||||
|     - env: CLANG_VERSION=6.0 BUILD_TYPE=Debug CPP=11 ASAN=On TSAN=Off |     - env: CLANG_VERSION=7 BUILD_TYPE=Debug CPP=11 ASAN=On TSAN=Off | ||||||
|       os: linux |       dist: bionic       | ||||||
|       addons: *clang6 |  | ||||||
|  |  | ||||||
|     - env: CLANG_VERSION=6.0 BUILD_TYPE=Release CPP=11 ASAN=On TSAN=Off |     - env: CLANG_VERSION=7 BUILD_TYPE=Release CPP=11 ASAN=On TSAN=Off | ||||||
|       os: linux |       dist: bionic | ||||||
|       addons: *clang6 |  | ||||||
|        |  | ||||||
|       # Test clang-6.0: C++11, Build=Debug, TSAN=On |  | ||||||
|     - env: CLANG_VERSION=6.0 BUILD_TYPE=Debug CPP=11 ASAN=Off TSAN=On |  | ||||||
|       os: linux |  | ||||||
|       addons: *clang6 |  | ||||||
|        |  | ||||||
|     - env: CLANG_VERSION=6.0 BUILD_TYPE=Release CPP=11 ASAN=Off TSAN=On |  | ||||||
|       os: linux |  | ||||||
|       addons: *clang6 |  | ||||||
|        |        | ||||||
|       # osx |       # osx | ||||||
|     - env: BUILD_TYPE=Release CPP=11 ASAN=Off TSAN=Off |     - env: BUILD_TYPE=Release CPP=11 ASAN=Off TSAN=Off | ||||||
| @@ -84,7 +78,6 @@ matrix: | |||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| before_script: | before_script: | ||||||
|   - if [ -n "$GCC_VERSION" ]; then export CXX="g++-${GCC_VERSION}" CC="gcc-${GCC_VERSION}"; fi |   - if [ -n "$GCC_VERSION" ]; then export CXX="g++-${GCC_VERSION}" CC="gcc-${GCC_VERSION}"; fi | ||||||
|   - if [ -n "$CLANG_VERSION" ]; then export CXX="clang++-${CLANG_VERSION}" CC="clang-${CLANG_VERSION}"; fi |   - if [ -n "$CLANG_VERSION" ]; then export CXX="clang++-${CLANG_VERSION}" CC="clang-${CLANG_VERSION}"; fi | ||||||
| @@ -102,11 +95,13 @@ script: | |||||||
|       --warn-uninitialized \ |       --warn-uninitialized \ | ||||||
|       -DCMAKE_BUILD_TYPE=$BUILD_TYPE \ |       -DCMAKE_BUILD_TYPE=$BUILD_TYPE \ | ||||||
|       -DCMAKE_CXX_STANDARD=$CPP \ |       -DCMAKE_CXX_STANDARD=$CPP \ | ||||||
|       -DSPDLOG_BUILD_EXAMPLES=ON \ |       -DSPDLOG_BUILD_EXAMPLE=ON \ | ||||||
|  |       -DSPDLOG_BUILD_EXAMPLE_HO=ON \ | ||||||
|       -DSPDLOG_BUILD_BENCH=OFF \ |       -DSPDLOG_BUILD_BENCH=OFF \ | ||||||
|       -DSPDLOG_BUILD_TESTS=ON \ |       -DSPDLOG_BUILD_TESTS=ON \ | ||||||
|       -DSPDLOG_SANITIZE_ADDRESS=$ASAN \ |       -DSPDLOG_BUILD_TESTS_HO=OFf \ | ||||||
|       -DSPDLOG_SANITIZE_THREAD=$TSAN |       -DSPDLOG_SANITIZE_ADDRESS=$ASAN  | ||||||
|  |        | ||||||
|   - make VERBOSE=1 -j2 |   - make VERBOSE=1 -j2 | ||||||
|   - ctest -j2 --output-on-failure |   - ctest -j2 --output-on-failure | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										290
									
								
								third_party/spdlog/CMakeLists.txt
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										290
									
								
								third_party/spdlog/CMakeLists.txt
									
									
									
									
										vendored
									
									
								
							| @@ -1,157 +1,229 @@ | |||||||
| # | # Copyright(c) 2019 spdlog authors | ||||||
| # Copyright(c) 2015 Ruslan Baratov. |  | ||||||
| # Distributed under the MIT License (http://opensource.org/licenses/MIT) | # Distributed under the MIT License (http://opensource.org/licenses/MIT) | ||||||
| # |  | ||||||
|  |  | ||||||
| cmake_minimum_required(VERSION 3.1) | cmake_minimum_required(VERSION 3.2) | ||||||
| project(spdlog VERSION 1.3.1 LANGUAGES CXX) |  | ||||||
| include(CMakeDependentOption) |  | ||||||
| include(GNUInstallDirs) |  | ||||||
|  |  | ||||||
| #--------------------------------------------------------------------------------------- | #--------------------------------------------------------------------------------------- | ||||||
| # set default build to release | # Start spdlog project | ||||||
|  | #--------------------------------------------------------------------------------------- | ||||||
|  | include(GNUInstallDirs) | ||||||
|  | include(cmake/utils.cmake) | ||||||
|  | include(cmake/ide.cmake) | ||||||
|  |  | ||||||
|  | spdlog_extract_version() | ||||||
|  |  | ||||||
|  | #--------------------------------------------------------------------------------------- | ||||||
|  | # Set default build to release | ||||||
| #--------------------------------------------------------------------------------------- | #--------------------------------------------------------------------------------------- | ||||||
| if(NOT CMAKE_BUILD_TYPE) | if(NOT CMAKE_BUILD_TYPE) | ||||||
|     set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Choose Release or Debug" FORCE) |     set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Choose Release or Debug" FORCE) | ||||||
| endif() | endif() | ||||||
|  |  | ||||||
| message(STATUS "Build type: " ${CMAKE_BUILD_TYPE}) | project(spdlog VERSION ${SPDLOG_VERSION} LANGUAGES CXX) | ||||||
|  | message(STATUS "Build spdlog: ${SPDLOG_VERSION}") | ||||||
|  |  | ||||||
| #--------------------------------------------------------------------------------------- | #--------------------------------------------------------------------------------------- | ||||||
| # compiler config | # Compiler config | ||||||
| #--------------------------------------------------------------------------------------- | #--------------------------------------------------------------------------------------- | ||||||
| set(CMAKE_CXX_STANDARD 11) | set(CMAKE_CXX_STANDARD 11) | ||||||
| set(CMAKE_CXX_STANDARD_REQUIRED ON) | set(CMAKE_CXX_STANDARD_REQUIRED ON) | ||||||
| set(CMAKE_CXX_EXTENSIONS OFF) | set(CMAKE_CXX_EXTENSIONS OFF) | ||||||
|  |  | ||||||
| if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") | #--------------------------------------------------------------------------------------- | ||||||
|     add_compile_options("-Wall") | # Set SPDLOG_MASTER_PROJECT to ON if we are building spdlog | ||||||
|     add_compile_options("-Wextra") | #--------------------------------------------------------------------------------------- | ||||||
|     add_compile_options("-Wconversion") | # Check if spdlog is being used directly or via add_subdirectory, but allow overriding | ||||||
|     add_compile_options("-pedantic") | if (NOT DEFINED SPDLOG_MASTER_PROJECT) | ||||||
|     add_compile_options("-Wfatal-errors") |     if (CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR) | ||||||
|  |         set(SPDLOG_MASTER_PROJECT ON) | ||||||
|  |     else() | ||||||
|  |         set(SPDLOG_MASTER_PROJECT OFF) | ||||||
|  |     endif() | ||||||
|  | endif () | ||||||
|  |  | ||||||
|  | # build shared option | ||||||
|  | if(NOT WIN32) | ||||||
|  |     option(SPDLOG_BUILD_SHARED "Build shared library" OFF) | ||||||
| endif() | endif() | ||||||
|  |  | ||||||
| #--------------------------------------------------------------------------------------- | # example options | ||||||
| # address sanitizers check | option(SPDLOG_BUILD_EXAMPLE "Build example" ${SPDLOG_MASTER_PROJECT}) | ||||||
| #--------------------------------------------------------------------------------------- | option(SPDLOG_BUILD_EXAMPLE_HO "Build header only example" OFF) | ||||||
| include(cmake/sanitizers.cmake) |  | ||||||
|  |  | ||||||
| #--------------------------------------------------------------------------------------- | # testing options | ||||||
| # spdlog target |  | ||||||
| #--------------------------------------------------------------------------------------- |  | ||||||
| add_library(spdlog INTERFACE) |  | ||||||
| add_library(spdlog::spdlog ALIAS spdlog) |  | ||||||
|  |  | ||||||
| # Check if spdlog is being used directly or via add_subdirectory |  | ||||||
| set(SPDLOG_MASTER_PROJECT OFF) |  | ||||||
| if (CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR) |  | ||||||
|   set(SPDLOG_MASTER_PROJECT ON) |  | ||||||
| endif() |  | ||||||
|  |  | ||||||
| option(SPDLOG_BUILD_EXAMPLES "Build examples" ${SPDLOG_MASTER_PROJECT}) |  | ||||||
| option(SPDLOG_BUILD_BENCH "Build benchmarks" ${SPDLOG_MASTER_PROJECT}) |  | ||||||
| option(SPDLOG_BUILD_TESTS "Build tests" ${SPDLOG_MASTER_PROJECT}) | option(SPDLOG_BUILD_TESTS "Build tests" ${SPDLOG_MASTER_PROJECT}) | ||||||
|  | option(SPDLOG_BUILD_TESTS_HO "Build tests using the header only version" OFF) | ||||||
|  |  | ||||||
|  | # bench options | ||||||
|  | option(SPDLOG_BUILD_BENCH "Build benchmarks (Requires https://github.com/google/benchmark.git to be installed)" OFF) | ||||||
|  |  | ||||||
|  | # sanitizer options | ||||||
|  | option(SPDLOG_SANITIZE_ADDRESS "Enable address sanitizer in tests" OFF) | ||||||
|  |  | ||||||
|  | # install options | ||||||
|  | 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) | ||||||
|  |  | ||||||
| if(SPDLOG_FMT_EXTERNAL) | if(WIN32) | ||||||
|     find_package(fmt REQUIRED CONFIG) | 	option(SPDLOG_WCHAR_SUPPORT "Support wchar api" OFF) | ||||||
|  |     option(SPDLOG_WCHAR_FILENAMES "Support wchar filenames" OFF)     | ||||||
| endif() | endif() | ||||||
|  |  | ||||||
| target_include_directories( | option(SPDLOG_NO_EXCEPTIONS "Compile with -fno-exceptions. Call abort() on any spdlog exceptions" OFF) | ||||||
|     spdlog |  | ||||||
|     INTERFACE |  | ||||||
|     "$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/include>" |  | ||||||
|     "$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>" |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| if(SPDLOG_FMT_EXTERNAL) |  | ||||||
|     target_compile_definitions(spdlog INTERFACE SPDLOG_FMT_EXTERNAL) | find_package(Threads REQUIRED) | ||||||
|     target_link_libraries(spdlog INTERFACE fmt::fmt) |  | ||||||
|  | message(STATUS "Build type: " ${CMAKE_BUILD_TYPE}) | ||||||
|  |  | ||||||
|  | #--------------------------------------------------------------------------------------- | ||||||
|  | # Static/Shared library (shared not supported in windows yet) | ||||||
|  | #--------------------------------------------------------------------------------------- | ||||||
|  | set(SPDLOG_SRCS | ||||||
|  |         src/spdlog.cpp | ||||||
|  |         src/stdout_sinks.cpp | ||||||
|  |         src/fmt.cpp | ||||||
|  |         src/color_sinks.cpp | ||||||
|  |         src/file_sinks.cpp | ||||||
|  |         src/async.cpp) | ||||||
|  |  | ||||||
|  | set(SPDLOG_CFLAGS "${PROJECT_NAME}") | ||||||
|  |  | ||||||
|  | if (SPDLOG_BUILD_SHARED) | ||||||
|  |     if(WIN32) | ||||||
|  |         message(FATAL_ERROR "spdlog shared lib is not yet supported under windows") | ||||||
|  |     endif() | ||||||
|  |     add_library(spdlog SHARED ${SPDLOG_SRCS} ${SPDLOG_ALL_HEADERS}) | ||||||
|  | else() | ||||||
|  |     add_library(spdlog STATIC ${SPDLOG_SRCS} ${SPDLOG_ALL_HEADERS}) | ||||||
| endif() | endif() | ||||||
|  |  | ||||||
| set(HEADER_BASE "${CMAKE_CURRENT_SOURCE_DIR}/include") | add_library(spdlog::spdlog ALIAS spdlog) | ||||||
|  |  | ||||||
| if(SPDLOG_BUILD_EXAMPLES) | target_compile_definitions(spdlog PUBLIC SPDLOG_COMPILED_LIB) | ||||||
|  | target_include_directories(spdlog PUBLIC | ||||||
|  |         "$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/include>" | ||||||
|  |         "$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>") | ||||||
|  | target_link_libraries(spdlog PUBLIC Threads::Threads) | ||||||
|  | spdlog_enable_warnings(spdlog) | ||||||
|  |  | ||||||
|  | set_target_properties(spdlog PROPERTIES VERSION ${SPDLOG_VERSION} SOVERSION ${SPDLOG_VERSION_MAJOR}) | ||||||
|  | set_target_properties(spdlog PROPERTIES DEBUG_POSTFIX d) | ||||||
|  |  | ||||||
|  | #--------------------------------------------------------------------------------------- | ||||||
|  | # Header only version | ||||||
|  | #--------------------------------------------------------------------------------------- | ||||||
|  | add_library(spdlog_header_only INTERFACE) | ||||||
|  | add_library(spdlog::spdlog_header_only ALIAS spdlog_header_only) | ||||||
|  |  | ||||||
|  | target_include_directories(spdlog_header_only INTERFACE | ||||||
|  |         "$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/include>" | ||||||
|  |         "$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>") | ||||||
|  | target_link_libraries(spdlog_header_only INTERFACE Threads::Threads) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | #--------------------------------------------------------------------------------------- | ||||||
|  | # Use fmt package if using exertnal fmt | ||||||
|  | #--------------------------------------------------------------------------------------- | ||||||
|  | if(SPDLOG_FMT_EXTERNAL) | ||||||
|  |     if (NOT TARGET fmt::fmt) | ||||||
|  |         find_package(fmt REQUIRED) | ||||||
|  |     endif () | ||||||
|  |  | ||||||
|  |     set(SPDLOG_CFLAGS "${SPDLOG_CFLAGS} -DSPDLOG_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_link_libraries(spdlog_header_only INTERFACE fmt::fmt) | ||||||
|  | endif() | ||||||
|  |  | ||||||
|  | if(SPDLOG_WCHAR_SUPPORT) | ||||||
|  | 	target_compile_definitions(spdlog PUBLIC SPDLOG_WCHAR_TO_UTF8_SUPPORT) | ||||||
|  | 	target_compile_definitions(spdlog_header_only INTERFACE SPDLOG_WCHAR_TO_UTF8_SUPPORT) | ||||||
|  |  endif() | ||||||
|  |  | ||||||
|  |  if(SPDLOG_WCHAR_FILENAMES) | ||||||
|  | 	target_compile_definitions(spdlog PUBLIC SPDLOG_WCHAR_FILENAMES) | ||||||
|  | 	target_compile_definitions(spdlog_header_only INTERFACE SPDLOG_WCHAR_FILENAMES) | ||||||
|  |  endif() | ||||||
|  |  | ||||||
|  |  if(SPDLOG_NO_EXCEPTIONS) | ||||||
|  | 	target_compile_definitions(spdlog PUBLIC SPDLOG_NO_EXCEPTIONS)	 | ||||||
|  |  | ||||||
|  | 	target_compile_definitions(spdlog_header_only INTERFACE SPDLOG_NO_EXCEPTIONS) | ||||||
|  |  | ||||||
|  |     if(NOT MSVC) | ||||||
|  |         target_compile_options(spdlog PRIVATE -fno-exceptions) | ||||||
|  |     endif() | ||||||
|  | endif() | ||||||
|  |  | ||||||
|  |  | ||||||
|  | #--------------------------------------------------------------------------------------- | ||||||
|  | # Build binaries | ||||||
|  | #--------------------------------------------------------------------------------------- | ||||||
|  | if(SPDLOG_BUILD_EXAMPLE OR SPDLOG_BUILD_EXAMPLE_HO) | ||||||
|  |     message(STATUS "Generating examples") | ||||||
|     add_subdirectory(example) |     add_subdirectory(example) | ||||||
| endif() | endif() | ||||||
|  |  | ||||||
| if(SPDLOG_BUILD_TESTS) | if(SPDLOG_BUILD_TESTS OR SPDLOG_BUILD_TESTS_HO) | ||||||
|     include(CTest) |     message(STATUS "Generating tests") | ||||||
|  |     enable_testing() | ||||||
|     add_subdirectory(tests) |     add_subdirectory(tests) | ||||||
| endif() | endif() | ||||||
|  |  | ||||||
| if(SPDLOG_BUILD_BENCH) | if(SPDLOG_BUILD_BENCH) | ||||||
|  |     message(STATUS "Generating benchmarks") | ||||||
|     add_subdirectory(bench) |     add_subdirectory(bench) | ||||||
| endif() | endif() | ||||||
|  |  | ||||||
| #--------------------------------------------------------------------------------------- | #--------------------------------------------------------------------------------------- | ||||||
| # Install/export targets and files | # Install | ||||||
| #--------------------------------------------------------------------------------------- | #--------------------------------------------------------------------------------------- | ||||||
| # set files and directories | if (SPDLOG_INSTALL) | ||||||
| set(config_install_dir "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}") |     message(STATUS "Generating install") | ||||||
| set(include_install_dir "${CMAKE_INSTALL_INCLUDEDIR}") |     set(project_config_in "${CMAKE_CURRENT_LIST_DIR}/cmake/spdlogConfig.cmake.in") | ||||||
| set(pkgconfig_install_dir "${CMAKE_INSTALL_LIBDIR}/pkgconfig") |     set(project_config_out "${CMAKE_CURRENT_BINARY_DIR}/spdlogConfig.cmake") | ||||||
| set(version_config "${CMAKE_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake") |     set(config_targets_file "spdlogConfigTargets.cmake") | ||||||
| set(project_config "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake") |     set(version_config_file "${CMAKE_CURRENT_BINARY_DIR}/spdlogConfigVersion.cmake") | ||||||
| set(targets_config "${PROJECT_NAME}Targets.cmake") |     set(export_dest_dir "${CMAKE_INSTALL_LIBDIR}/spdlog/cmake") | ||||||
| set(pkg_config "${CMAKE_BINARY_DIR}/${PROJECT_NAME}.pc") |     set(pkgconfig_install_dir "${CMAKE_INSTALL_LIBDIR}/pkgconfig") | ||||||
| set(targets_export_name "${PROJECT_NAME}Targets") |     set(pkg_config "${CMAKE_BINARY_DIR}/${PROJECT_NAME}.pc") | ||||||
| set(namespace "${PROJECT_NAME}::") |  | ||||||
|  |  | ||||||
| # generate package version file |     #--------------------------------------------------------------------------------------- | ||||||
| include(CMakePackageConfigHelpers) |     # Include files | ||||||
| write_basic_package_version_file( |     #--------------------------------------------------------------------------------------- | ||||||
|     "${version_config}" COMPATIBILITY SameMajorVersion |     install(DIRECTORY include/ DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}" PATTERN "fmt/bundled" EXCLUDE) | ||||||
| ) |     install(TARGETS spdlog spdlog_header_only EXPORT spdlog DESTINATION "${CMAKE_INSTALL_LIBDIR}/spdlog") | ||||||
|  |  | ||||||
| # configure pkg config file |     if(NOT SPDLOG_FMT_EXTERNAL) | ||||||
| configure_file("cmake/spdlog.pc.in" "${pkg_config}" @ONLY) |         install(DIRECTORY include/${PROJECT_NAME}/fmt/bundled/ | ||||||
| # configure spdlogConfig.cmake file |                 DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME}/fmt/bundled/") | ||||||
| configure_file("cmake/Config.cmake.in" "${project_config}" @ONLY) |     endif() | ||||||
|  |  | ||||||
| # install targets |     #--------------------------------------------------------------------------------------- | ||||||
| install( |     # Package and version files | ||||||
|     TARGETS spdlog |     #--------------------------------------------------------------------------------------- | ||||||
|     EXPORT "${targets_export_name}" |     configure_file("cmake/${PROJECT_NAME}.pc.in" "${pkg_config}" @ONLY) | ||||||
| ) |     install(FILES "${pkg_config}" DESTINATION "${pkgconfig_install_dir}") | ||||||
|  |  | ||||||
| # install headers |     install(EXPORT spdlog | ||||||
| install( |             DESTINATION ${export_dest_dir} | ||||||
|     DIRECTORY "${HEADER_BASE}/${PROJECT_NAME}" |             NAMESPACE spdlog:: | ||||||
|     DESTINATION "${include_install_dir}" |             FILE ${config_targets_file}) | ||||||
| ) |  | ||||||
|  |  | ||||||
| # install project config and version file |     include(CMakePackageConfigHelpers) | ||||||
| install( |     configure_file("${project_config_in}" "${project_config_out}" @ONLY) | ||||||
|     FILES "${project_config}" "${version_config}" |     write_basic_package_version_file("${version_config_file}" COMPATIBILITY SameMajorVersion) | ||||||
|     DESTINATION "${config_install_dir}" |     install(FILES | ||||||
| ) |             "${project_config_out}" | ||||||
|  |             "${version_config_file}" DESTINATION "${export_dest_dir}") | ||||||
|  |  | ||||||
| # install pkg config file |     #--------------------------------------------------------------------------------------- | ||||||
| install( |     # Support creation of installable packages | ||||||
|     FILES "${pkg_config}" |     #--------------------------------------------------------------------------------------- | ||||||
|     DESTINATION "${pkgconfig_install_dir}" |     include(cmake/spdlogCPack.cmake) | ||||||
| ) |  | ||||||
|  |  | ||||||
| # install targets config file | endif () | ||||||
| install( |  | ||||||
|     EXPORT "${targets_export_name}" |  | ||||||
|     NAMESPACE "${namespace}" |  | ||||||
|     DESTINATION "${config_install_dir}" |  | ||||||
|     FILE ${targets_config} |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| # export build directory targets file |  | ||||||
| export( |  | ||||||
|     EXPORT ${targets_export_name} |  | ||||||
|     NAMESPACE "${namespace}" |  | ||||||
|     FILE ${targets_config} |  | ||||||
| ) |  | ||||||
|  |  | ||||||
| # register project in CMake user registry |  | ||||||
| export(PACKAGE ${PROJECT_NAME}) |  | ||||||
|  |  | ||||||
| file(GLOB_RECURSE spdlog_include_SRCS "${HEADER_BASE}/*.h") |  | ||||||
| add_custom_target(spdlog_headers_for_ide SOURCES ${spdlog_include_SRCS}) |  | ||||||
|   | |||||||
							
								
								
									
										21
									
								
								third_party/spdlog/INSTALL
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										21
									
								
								third_party/spdlog/INSTALL
									
									
									
									
										vendored
									
									
								
							| @@ -1,13 +1,24 @@ | |||||||
| spdlog is header only library. | Header only version: | ||||||
| Just copy the files to your build tree and use a C++11 compiler | ================================================================== | ||||||
|  | Just copy the files to your build tree and use a C++11 compiler. | ||||||
|  | Or use CMake: | ||||||
|  |   add_executable(example_header_only example.cpp) | ||||||
|  |   target_link_libraries(example_header_only spdlog::spdlog_header_only) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | Compiled library version: | ||||||
|  | ================================================================== | ||||||
|  | CMake: | ||||||
|  |   add_executable(example example.cpp) | ||||||
|  |   target_link_libraries(example spdlog::spdlog) | ||||||
|  |  | ||||||
|  | Or copy src/spdlog.cpp to your build tree and pass the -DSPDLOG_COMPILED_LIB to the compiler. | ||||||
|  |  | ||||||
| Tested on: | Tested on: | ||||||
| gcc 4.8.1 and above | gcc 4.8.1 and above | ||||||
| clang 3.5 | clang 3.5 | ||||||
| Visual Studio 2013 | Visual Studio 2013 | ||||||
|  |  | ||||||
| gcc 4.8 flags: --std==c++11 -pthread -O3 -flto -Wl,--no-as-needed |  | ||||||
| gcc 4.9 flags: --std=c++11 -pthread -O3 -flto |  | ||||||
|  |  | ||||||
|  |  | ||||||
| see the makefile in the example folder |  | ||||||
|   | |||||||
							
								
								
									
										147
									
								
								third_party/spdlog/README.md
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										147
									
								
								third_party/spdlog/README.md
									
									
									
									
										vendored
									
									
								
							| @@ -1,24 +1,21 @@ | |||||||
| # spdlog | # spdlog | ||||||
|  |  | ||||||
| Very fast, header only, C++ logging library. [](https://travis-ci.org/gabime/spdlog)  [](https://ci.appveyor.com/project/gabime/spdlog) | Very fast, header-only/compiled, C++ logging library. [](https://travis-ci.org/gabime/spdlog)  [](https://ci.appveyor.com/project/gabime/spdlog) | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| ## Install  | ## Install  | ||||||
| #### Just copy the headers: | #### Header only version | ||||||
|  | Copy the source [folder](https://github.com/gabime/spdlog/tree/v1.x/include/spdlog) to your build tree and use a C++11 compiler. | ||||||
|  |  | ||||||
| * Copy the source [folder](https://github.com/gabime/spdlog/tree/v1.x/include/spdlog) to your build tree and use a C++11 compiler. | #### Static lib version (recommended - much faster compile times) | ||||||
|  | ```console | ||||||
| #### Or use your favorite package manager: | $ git clone https://github.com/gabime/spdlog.git | ||||||
|  | $ cd spdlog && mkdir build && cd build | ||||||
| * Ubuntu: `apt-get install libspdlog-dev` | $ cmake .. && make -j | ||||||
| * Homebrew: `brew install spdlog` | ``` | ||||||
| * FreeBSD:  `cd /usr/ports/devel/spdlog/ && make install clean` |  | ||||||
| * Fedora: `yum install spdlog` |  | ||||||
| * Gentoo: `emerge dev-libs/spdlog` |  | ||||||
| * Arch Linux: `yaourt -S spdlog-git` |  | ||||||
| * vcpkg: `vcpkg install spdlog` |  | ||||||
|        |        | ||||||
|  |    see example [CMakeLists.txt](https://github.com/gabime/spdlog/blob/v1.x/example/CMakeLists.txt) on how to use. | ||||||
|  |  | ||||||
| ## Platforms | ## Platforms | ||||||
|  * Linux, FreeBSD, OpenBSD, Solaris, AIX |  * Linux, FreeBSD, OpenBSD, Solaris, AIX | ||||||
| @@ -26,10 +23,19 @@ Very fast, header only, C++ logging library. [ |  * macOS (clang 3.5+) | ||||||
|  * Android |  * Android | ||||||
|  |  | ||||||
|  | ## Package managers: | ||||||
|  | * Homebrew: `brew install spdlog` | ||||||
|  | * FreeBSD:  `cd /usr/ports/devel/spdlog/ && make install clean` | ||||||
|  | * Fedora: `yum install spdlog` | ||||||
|  | * Gentoo: `emerge dev-libs/spdlog` | ||||||
|  | * Arch Linux: `yaourt -S spdlog-git` | ||||||
|  | * vcpkg: `vcpkg install spdlog` | ||||||
|  |  | ||||||
| ## Features | ## Features | ||||||
| * Very fast (see [benchmarks](#benchmarks) below). | * Very fast (see [benchmarks](#benchmarks) below). | ||||||
| * Headers only, just copy and use. | * Headers only, just copy and use. Or use as a compiled library. | ||||||
| * Feature rich formatting, using the excellent [fmt](https://github.com/fmtlib/fmt) library. | * Feature rich formatting, using the excellent [fmt](https://github.com/fmtlib/fmt) library. | ||||||
|  | * **New!** [Backtrace](#backtrace-support) support - store debug or other messages in a ring buffer and display later on demand. | ||||||
| * Fast asynchronous mode (optional) | * Fast asynchronous mode (optional) | ||||||
| * [Custom](https://github.com/gabime/spdlog/wiki/3.-Custom-formatting) formatting. | * [Custom](https://github.com/gabime/spdlog/wiki/3.-Custom-formatting) formatting. | ||||||
| * Multi/Single threaded loggers. | * Multi/Single threaded loggers. | ||||||
| @@ -41,45 +47,15 @@ Very fast, header only, C++ logging library. [```) |     * Windows debugger (```OutputDebugString(..)```) | ||||||
|     * Easily extendable with custom log targets  (just implement a single function in the [sink](include/spdlog/sinks/sink.h) interface). |     * Easily extendable with custom log targets  (just implement a single function in the [sink](include/spdlog/sinks/sink.h) interface). | ||||||
| * Severity based filtering - threshold levels can be modified in runtime as well as in compile time. | * Severity based filtering - threshold levels can be modified in runtime as well as in compile time. | ||||||
| * Binary data logging. |  | ||||||
|  |  | ||||||
|   |   | ||||||
| ## Benchmarks |  | ||||||
|  |  | ||||||
| Below are some [benchmarks](https://github.com/gabime/spdlog/blob/v1.x/bench/bench.cpp) done in Ubuntu 64 bit, Intel i7-4770 CPU @ 3.40GHz |  | ||||||
|  |  | ||||||
| #### Synchronous mode |  | ||||||
| ``` |  | ||||||
| ******************************************************************************* |  | ||||||
| Single thread, 1,000,000 iterations |  | ||||||
| ******************************************************************************* |  | ||||||
| basic_st...             Elapsed: 0.181652       5,505,042/sec |  | ||||||
| rotating_st...          Elapsed: 0.181781       5,501,117/sec |  | ||||||
| daily_st...             Elapsed: 0.187595       5,330,630/sec |  | ||||||
| null_st...              Elapsed: 0.0504704      19,813,602/sec |  | ||||||
| ******************************************************************************* |  | ||||||
| 10 threads sharing same logger, 1,000,000 iterations |  | ||||||
| ******************************************************************************* |  | ||||||
| basic_mt...             Elapsed: 0.616035       1,623,284/sec |  | ||||||
| rotating_mt...          Elapsed: 0.620344       1,612,008/sec |  | ||||||
| daily_mt...             Elapsed: 0.648353       1,542,369/sec |  | ||||||
| null_mt...              Elapsed: 0.151972       6,580,166/sec |  | ||||||
| ``` |  | ||||||
| #### Asynchronous mode |  | ||||||
| ``` |  | ||||||
| ******************************************************************************* |  | ||||||
| 10 threads sharing same logger, 1,000,000 iterations |  | ||||||
| ******************************************************************************* |  | ||||||
| async...                Elapsed: 0.350066       2,856,606/sec |  | ||||||
| async...                Elapsed: 0.314865       3,175,960/sec |  | ||||||
| async...                Elapsed: 0.349851       2,858,358/sec |  | ||||||
| ``` |  | ||||||
|  |  | ||||||
| ## Usage samples | ## Usage samples | ||||||
|  |  | ||||||
| #### Basic usage | #### Basic usage | ||||||
| ```c++ | ```c++ | ||||||
| #include "spdlog/spdlog.h" | #include "spdlog/spdlog.h" | ||||||
|  | #include "spdlog/sinks/basic_file_sink.h" | ||||||
|  |  | ||||||
| int main()  | int main()  | ||||||
| { | { | ||||||
|     spdlog::info("Welcome to spdlog!"); |     spdlog::info("Welcome to spdlog!"); | ||||||
| @@ -102,6 +78,9 @@ int main() | |||||||
|     SPDLOG_TRACE("Some trace message with param {}", {}); |     SPDLOG_TRACE("Some trace message with param {}", {}); | ||||||
|     SPDLOG_DEBUG("Some debug message"); |     SPDLOG_DEBUG("Some debug message"); | ||||||
|      |      | ||||||
|  |     // Set the default logger to file logger | ||||||
|  |     auto file_logger = spdlog::basic_logger_mt("basic_logger", "logs/basic.txt"); | ||||||
|  |     spdlog::set_default_logger(file_logger);             | ||||||
| } | } | ||||||
| ``` | ``` | ||||||
| #### create stdout/stderr logger object | #### create stdout/stderr logger object | ||||||
| @@ -157,15 +136,20 @@ void daily_example() | |||||||
| ``` | ``` | ||||||
|  |  | ||||||
| --- | --- | ||||||
| #### Cloning loggers | #### Backtrace support | ||||||
| ```c++ | ```c++ | ||||||
| // clone a logger and give it new name. | // Loggers can store in a ring buffer all messages (including debug/trace) and display later on demand. | ||||||
| // Useful for creating subsystem loggers from some "root" logger | // When needed, call dump_backtrace() to see them | ||||||
| void clone_example() | spdlog::enable_backtrace(32); // create ring buffer with capacity of 32  messages | ||||||
|  | // or my_logger->enable_backtrace(32).. | ||||||
|  | for(int i = 0; i < 100; i++) | ||||||
| { | { | ||||||
|     auto network_logger = spdlog::get("root")->clone("network"); |   spdlog::debug("Backtrace message {}", i); // not logged yet.. | ||||||
|     network_logger->info("Logging network stuff.."); |  | ||||||
| } | } | ||||||
|  | // e.g. if some error happened: | ||||||
|  | spdlog::dump_backtrace(); // log them now! show the last 32 messages | ||||||
|  |  | ||||||
|  | // or my_logger->dump_backtrace(32).. | ||||||
| ``` | ``` | ||||||
|  |  | ||||||
| --- | --- | ||||||
| @@ -178,9 +162,8 @@ spdlog::flush_every(std::chrono::seconds(3)); | |||||||
| ``` | ``` | ||||||
|  |  | ||||||
| --- | --- | ||||||
| #### Binary logging | #### Log binary data in hex | ||||||
| ```c++ | ```c++ | ||||||
| // log binary data as hex. |  | ||||||
| // many types of std::container<char> types can be used. | // many types of std::container<char> types can be used. | ||||||
| // ranges are supported too. | // ranges are supported too. | ||||||
| // format flags: | // format flags: | ||||||
| @@ -310,10 +293,64 @@ void syslog_example() | |||||||
| void android_example() | void android_example() | ||||||
| { | { | ||||||
|     std::string tag = "spdlog-android"; |     std::string tag = "spdlog-android"; | ||||||
|     auto android_logger = spdlog::android_logger("android", tag); |     auto android_logger = spdlog::android_logger_mt("android", tag); | ||||||
|     android_logger->critical("Use \"adb shell logcat\" to view this message."); |     android_logger->critical("Use \"adb shell logcat\" to view this message."); | ||||||
| } | } | ||||||
| ``` | ``` | ||||||
|  |  | ||||||
|  | ## Benchmarks | ||||||
|  |  | ||||||
|  | Below are some [benchmarks](https://github.com/gabime/spdlog/blob/v1.x/bench/bench.cpp) done in Ubuntu 64 bit, Intel i7-4770 CPU @ 3.40GHz | ||||||
|  |  | ||||||
|  | #### Synchronous mode | ||||||
|  | ``` | ||||||
|  | [info] ************************************************************** | ||||||
|  | [info] Single thread, 1,000,000 iterations | ||||||
|  | [info] ************************************************************** | ||||||
|  | [info] basic_st         Elapsed: 0.17 secs        5,777,626/sec | ||||||
|  | [info] rotating_st      Elapsed: 0.18 secs        5,475,894/sec | ||||||
|  | [info] daily_st         Elapsed: 0.20 secs        5,062,659/sec | ||||||
|  | [info] empty_logger     Elapsed: 0.07 secs       14,127,300/sec | ||||||
|  | [info] ************************************************************** | ||||||
|  | [info] C-string (400 bytes). Single thread, 1,000,000 iterations | ||||||
|  | [info] ************************************************************** | ||||||
|  | [info] basic_st         Elapsed: 0.41 secs        2,412,483/sec | ||||||
|  | [info] rotating_st      Elapsed: 0.72 secs        1,389,196/sec | ||||||
|  | [info] daily_st         Elapsed: 0.42 secs        2,393,298/sec | ||||||
|  | [info] null_st          Elapsed: 0.04 secs       27,446,957/sec | ||||||
|  | [info] ************************************************************** | ||||||
|  | [info] 10 threads sharing same logger, 1,000,000 iterations | ||||||
|  | [info] ************************************************************** | ||||||
|  | [info] basic_mt         Elapsed: 0.60 secs        1,659,613/sec | ||||||
|  | [info] rotating_mt      Elapsed: 0.62 secs        1,612,493/sec | ||||||
|  | [info] daily_mt         Elapsed: 0.61 secs        1,638,305/sec | ||||||
|  | [info] null_mt          Elapsed: 0.16 secs        6,272,758/sec | ||||||
|  | ``` | ||||||
|  | #### ASynchronous mode | ||||||
|  | ``` | ||||||
|  | [info] ------------------------------------------------- | ||||||
|  | [info] Messages     : 1,000,000 | ||||||
|  | [info] Threads      : 10 | ||||||
|  | [info] Queue        : 8,192 slots | ||||||
|  | [info] Queue memory : 8,192 x 272 = 2,176 KB  | ||||||
|  | [info] Total iters  : 3 | ||||||
|  | [info] ------------------------------------------------- | ||||||
|  | [info]  | ||||||
|  | [info] ********************************* | ||||||
|  | [info] Queue Overflow Policy: block | ||||||
|  | [info] ********************************* | ||||||
|  | [info] Elapsed: 1.70784 secs     585,535/sec | ||||||
|  | [info] Elapsed: 1.69805 secs     588,910/sec | ||||||
|  | [info] Elapsed: 1.7026 secs      587,337/sec | ||||||
|  | [info]  | ||||||
|  | [info] ********************************* | ||||||
|  | [info] Queue Overflow Policy: overrun | ||||||
|  | [info] ********************************* | ||||||
|  | [info] Elapsed: 0.372816 secs    2,682,285/sec | ||||||
|  | [info] Elapsed: 0.379758 secs    2,633,255/sec | ||||||
|  | [info] Elapsed: 0.373532 secs    2,677,147/sec | ||||||
|  |  | ||||||
|  | ``` | ||||||
|  |  | ||||||
| ## Documentation | ## Documentation | ||||||
| Documentation can be found in the [wiki](https://github.com/gabime/spdlog/wiki/1.-QuickStart) pages. | Documentation can be found in the [wiki](https://github.com/gabime/spdlog/wiki/1.-QuickStart) pages. | ||||||
|   | |||||||
							
								
								
									
										2
									
								
								third_party/spdlog/appveyor.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								third_party/spdlog/appveyor.yml
									
									
									
									
										vendored
									
									
								
							| @@ -26,7 +26,7 @@ build_script: | |||||||
|  |  | ||||||
|     set PATH=C:\mingw-w64\i686-5.3.0-posix-dwarf-rt_v4-rev0\mingw32\bin;%PATH% |     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_BUILD_BENCH=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% | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										36
									
								
								third_party/spdlog/bench/CMakeLists.txt
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										36
									
								
								third_party/spdlog/bench/CMakeLists.txt
									
									
									
									
										vendored
									
									
								
							| @@ -1,28 +1,8 @@ | |||||||
| # *************************************************************************/ | # Copyright(c) 2019 spdlog authors | ||||||
| # * Copyright (c) 2015 Ruslan Baratov.                                    */ | # Distributed under the MIT License (http://opensource.org/licenses/MIT) | ||||||
| # *                                                                       */ |  | ||||||
| # * Permission is hereby granted, free of charge, to any person obtaining */ |  | ||||||
| # * a copy of this software and associated documentation files (the       */ |  | ||||||
| # * "Software"), to deal in the Software without restriction, including   */ |  | ||||||
| # * without limitation the rights to use, copy, modify, merge, publish,   */ |  | ||||||
| # * distribute, sublicense, and/or sell copies of the Software, and to    */ |  | ||||||
| # * permit persons to whom the Software is furnished to do so, subject to */ |  | ||||||
| # * the following conditions:                                             */ |  | ||||||
| # *                                                                       */ |  | ||||||
| # * The above copyright notice and this permission notice shall be        */ |  | ||||||
| # * included in all copies or substantial portions of the Software.       */ |  | ||||||
| # *                                                                       */ |  | ||||||
| # * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */ |  | ||||||
| # * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */ |  | ||||||
| # * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ |  | ||||||
| # * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */ |  | ||||||
| # * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */ |  | ||||||
| # * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */ |  | ||||||
| # * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */ |  | ||||||
| # *************************************************************************/ |  | ||||||
|  |  | ||||||
| cmake_minimum_required(VERSION 3.1) | cmake_minimum_required(VERSION 3.1) | ||||||
| project(SpdlogBench CXX) | project(spdlog_bench CXX) | ||||||
|  |  | ||||||
| if(NOT TARGET spdlog) | if(NOT TARGET spdlog) | ||||||
|   # Stand-alone build |   # Stand-alone build | ||||||
| @@ -33,16 +13,16 @@ find_package(Threads REQUIRED) | |||||||
| find_package(benchmark CONFIG REQUIRED) | find_package(benchmark CONFIG REQUIRED) | ||||||
|  |  | ||||||
| add_executable(bench bench.cpp) | add_executable(bench bench.cpp) | ||||||
| target_link_libraries(bench PRIVATE spdlog::spdlog Threads::Threads) | spdlog_enable_warnings(bench) | ||||||
|  | target_link_libraries(bench PRIVATE spdlog::spdlog) | ||||||
|  |  | ||||||
| add_executable(async_bench async_bench.cpp) | add_executable(async_bench async_bench.cpp) | ||||||
| target_link_libraries(async_bench PRIVATE spdlog::spdlog Threads::Threads) | target_link_libraries(async_bench PRIVATE spdlog::spdlog) | ||||||
|  |  | ||||||
| add_executable(latency latency.cpp) | add_executable(latency latency.cpp) | ||||||
| target_link_libraries(latency PRIVATE benchmark::benchmark spdlog::spdlog Threads::Threads) | 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 Threads::Threads) | target_link_libraries(formatter-bench PRIVATE benchmark::benchmark spdlog::spdlog) | ||||||
|  |  | ||||||
| file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/logs") | file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/logs") | ||||||
|   | |||||||
							
								
								
									
										74
									
								
								third_party/spdlog/bench/async_bench.cpp
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										74
									
								
								third_party/spdlog/bench/async_bench.cpp
									
									
									
									
										vendored
									
									
								
							| @@ -26,6 +26,11 @@ using namespace utils; | |||||||
|  |  | ||||||
| void bench_mt(int howmany, std::shared_ptr<spdlog::logger> log, int thread_count); | void bench_mt(int howmany, std::shared_ptr<spdlog::logger> log, int thread_count); | ||||||
|  |  | ||||||
|  | #ifdef _MSC_VER | ||||||
|  | #pragma warning(push) | ||||||
|  | #pragma warning(disable : 4996) // disable fopen warning under msvc | ||||||
|  | #endif                          // _MSC_VER | ||||||
|  |  | ||||||
| int count_lines(const char *filename) | int count_lines(const char *filename) | ||||||
| { | { | ||||||
|     int counter = 0; |     int counter = 0; | ||||||
| @@ -40,19 +45,36 @@ int count_lines(const char *filename) | |||||||
|  |  | ||||||
|     return counter; |     return counter; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | void verify_file(const char *filename, int expected_count) | ||||||
|  | { | ||||||
|  |     spdlog::info("Verifying {} to contain {:n} line..", filename, expected_count); | ||||||
|  |     auto count = count_lines(filename); | ||||||
|  |     if (count != expected_count) | ||||||
|  |     { | ||||||
|  |         spdlog::error("Test failed. {} has {:n} lines instead of {:n}", filename, count, expected_count); | ||||||
|  |         exit(1); | ||||||
|  |     } | ||||||
|  |     spdlog::info("Line count OK ({:n})\n", count); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #ifdef _MSC_VER | ||||||
|  | #pragma warning(pop) | ||||||
|  | #endif | ||||||
|  |  | ||||||
| int main(int argc, char *argv[]) | int main(int argc, char *argv[]) | ||||||
| { | { | ||||||
|  |  | ||||||
|     int howmany = 1000000; |     int howmany = 1000000; | ||||||
|     int queue_size = howmany + 2; |     int queue_size = std::min(howmany + 2, 8192); | ||||||
|     int threads = 10; |     int threads = 10; | ||||||
|     int iters = 3; |     int iters = 3; | ||||||
|  |  | ||||||
|     try |     try | ||||||
|     { |     { | ||||||
|  |         spdlog::set_pattern("[%^%l%$] %v"); | ||||||
|         if (argc == 1) |         if (argc == 1) | ||||||
|         { |         { | ||||||
|             spdlog::set_pattern("%v"); |  | ||||||
|             spdlog::info("Usage: {} <message_count> <threads> <q_size> <iterations>", argv[0]); |             spdlog::info("Usage: {} <message_count> <threads> <q_size> <iterations>", argv[0]); | ||||||
|             return 0; |             return 0; | ||||||
|         } |         } | ||||||
| @@ -62,37 +84,54 @@ int main(int argc, char *argv[]) | |||||||
|         if (argc > 2) |         if (argc > 2) | ||||||
|             threads = atoi(argv[2]); |             threads = atoi(argv[2]); | ||||||
|         if (argc > 3) |         if (argc > 3) | ||||||
|  |         { | ||||||
|             queue_size = atoi(argv[3]); |             queue_size = atoi(argv[3]); | ||||||
|  |             if (queue_size > 500000) | ||||||
|  |             { | ||||||
|  |                 spdlog::error("Max queue size allowed: 500,000"); | ||||||
|  |                 exit(1); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |  | ||||||
|         if (argc > 4) |         if (argc > 4) | ||||||
|             iters = atoi(argv[4]); |             iters = atoi(argv[4]); | ||||||
|  |  | ||||||
|  |         auto slot_size = sizeof(spdlog::details::async_msg); | ||||||
|         spdlog::info("-------------------------------------------------"); |         spdlog::info("-------------------------------------------------"); | ||||||
|         spdlog::info("Messages: {:14n}", howmany); |         spdlog::info("Messages     : {:n}", howmany); | ||||||
|         spdlog::info("Threads : {:14n}", threads); |         spdlog::info("Threads      : {:n}", threads); | ||||||
|         spdlog::info("Queue   : {:14n}", queue_size); |         spdlog::info("Queue        : {:n} slots", queue_size); | ||||||
|         spdlog::info("Iters   : {:>14n}", iters); |         spdlog::info("Queue memory : {:n} x {} = {:n} KB ", queue_size, slot_size, (queue_size * slot_size) / 1024); | ||||||
|  |         spdlog::info("Total iters  : {:n}", iters); | ||||||
|         spdlog::info("-------------------------------------------------"); |         spdlog::info("-------------------------------------------------"); | ||||||
|  |  | ||||||
|         const char *filename = "logs/basic_async.log"; |         const char *filename = "logs/basic_async.log"; | ||||||
|  |         spdlog::info(""); | ||||||
|  |         spdlog::info("*********************************"); | ||||||
|  |         spdlog::info("Queue Overflow Policy: block"); | ||||||
|  |         spdlog::info("*********************************"); | ||||||
|         for (int i = 0; i < iters; i++) |         for (int i = 0; i < iters; i++) | ||||||
|         { |         { | ||||||
|             auto tp = std::make_shared<details::thread_pool>(queue_size, 1); |             auto tp = std::make_shared<details::thread_pool>(queue_size, 1); | ||||||
|             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 logger = std::make_shared<async_logger>("async_logger", std::move(file_sink), std::move(tp), async_overflow_policy::block); |             auto logger = std::make_shared<async_logger>("async_logger", std::move(file_sink), std::move(tp), async_overflow_policy::block); | ||||||
|             bench_mt(howmany, std::move(logger), threads); |             bench_mt(howmany, std::move(logger), threads); | ||||||
|             auto count = count_lines(filename); |             // verify_file(filename, howmany); | ||||||
|  |         } | ||||||
|  |  | ||||||
|             if (count != howmany) |         spdlog::info(""); | ||||||
|             { |         spdlog::info("*********************************"); | ||||||
|                 spdlog::error("Test failed. {} has {:n} lines instead of {:n}", filename, count, howmany); |         spdlog::info("Queue Overflow Policy: overrun"); | ||||||
|                 exit(1); |         spdlog::info("*********************************"); | ||||||
|             } |         // do same test but discard oldest if queue is full instead of blocking | ||||||
|             else |         filename = "logs/basic_async-overrun.log"; | ||||||
|             { |         for (int i = 0; i < iters; i++) | ||||||
|                 spdlog::info("Line count OK ({:n})\n", count); |         { | ||||||
|             } |             auto tp = std::make_shared<details::thread_pool>(queue_size, 1); | ||||||
|  |             auto file_sink = std::make_shared<spdlog::sinks::basic_file_sink_mt>(filename, true); | ||||||
|  |             auto logger = | ||||||
|  |                 std::make_shared<async_logger>("async_logger", std::move(file_sink), std::move(tp), async_overflow_policy::overrun_oldest); | ||||||
|  |             bench_mt(howmany, std::move(logger), threads); | ||||||
|         } |         } | ||||||
|         spdlog::shutdown(); |         spdlog::shutdown(); | ||||||
|     } |     } | ||||||
| @@ -102,7 +141,6 @@ int main(int argc, char *argv[]) | |||||||
|         perror("Last error"); |         perror("Last error"); | ||||||
|         return 1; |         return 1; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										157
									
								
								third_party/spdlog/bench/bench.cpp
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										157
									
								
								third_party/spdlog/bench/bench.cpp
									
									
									
									
										vendored
									
									
								
							| @@ -7,7 +7,6 @@ | |||||||
| // bench.cpp : spdlog benchmarks | // bench.cpp : spdlog benchmarks | ||||||
| // | // | ||||||
| #include "spdlog/spdlog.h" | #include "spdlog/spdlog.h" | ||||||
| #include "spdlog/async.h" |  | ||||||
| #include "spdlog/sinks/basic_file_sink.h" | #include "spdlog/sinks/basic_file_sink.h" | ||||||
| #include "spdlog/sinks/daily_file_sink.h" | #include "spdlog/sinks/daily_file_sink.h" | ||||||
| #include "spdlog/sinks/null_sink.h" | #include "spdlog/sinks/null_sink.h" | ||||||
| @@ -31,81 +30,99 @@ void bench_mt(int howmany, std::shared_ptr<spdlog::logger> log, int thread_count | |||||||
| void bench_default_api(int howmany, std::shared_ptr<spdlog::logger> log); | void bench_default_api(int howmany, std::shared_ptr<spdlog::logger> log); | ||||||
| void bench_c_string(int howmany, std::shared_ptr<spdlog::logger> log); | void bench_c_string(int howmany, std::shared_ptr<spdlog::logger> log); | ||||||
|  |  | ||||||
|  | static size_t file_size = 30 * 1024 * 1024; | ||||||
|  | static size_t rotating_files = 5; | ||||||
|  |  | ||||||
|  | void bench_threaded_logging(int threads, int iters) | ||||||
|  | { | ||||||
|  |     spdlog::info("**************************************************************"); | ||||||
|  |     spdlog::info("Multi threaded: {:n} threads, {:n} messages", threads, iters); | ||||||
|  |     spdlog::info("**************************************************************"); | ||||||
|  |  | ||||||
|  |     auto basic_mt = spdlog::basic_logger_mt("basic_mt", "logs/basic_mt.log", true); | ||||||
|  |     bench_mt(iters, std::move(basic_mt), threads); | ||||||
|  |     auto basic_mt_tracing = spdlog::basic_logger_mt("basic_mt/backtrace-on", "logs/basic_mt.log", true); | ||||||
|  |     basic_mt_tracing->enable_backtrace(32); | ||||||
|  |     bench_mt(iters, std::move(basic_mt_tracing), threads); | ||||||
|  |  | ||||||
|  |     spdlog::info(""); | ||||||
|  |     auto rotating_mt = spdlog::rotating_logger_mt("rotating_mt", "logs/rotating_mt.log", file_size, rotating_files); | ||||||
|  |     bench_mt(iters, std::move(rotating_mt), threads); | ||||||
|  |     auto rotating_mt_tracing = spdlog::rotating_logger_mt("rotating_mt/backtrace-on", "logs/rotating_mt.log", file_size, rotating_files); | ||||||
|  |     rotating_mt_tracing->enable_backtrace(32); | ||||||
|  |     bench_mt(iters, std::move(rotating_mt_tracing), threads); | ||||||
|  |  | ||||||
|  |     spdlog::info(""); | ||||||
|  |     auto daily_mt = spdlog::daily_logger_mt("daily_mt", "logs/daily_mt.log"); | ||||||
|  |     bench_mt(iters, std::move(daily_mt), threads); | ||||||
|  |     auto daily_mt_tracing = spdlog::daily_logger_mt("daily_mt/backtrace-on", "logs/daily_mt.log"); | ||||||
|  |     daily_mt_tracing->enable_backtrace(32); | ||||||
|  |     bench_mt(iters, std::move(daily_mt_tracing), threads); | ||||||
|  |  | ||||||
|  |     spdlog::info(""); | ||||||
|  |     auto empty_logger = std::make_shared<spdlog::logger>("level-off"); | ||||||
|  |     empty_logger->set_level(spdlog::level::off); | ||||||
|  |     bench(iters, empty_logger); | ||||||
|  |     auto empty_logger_tracing = std::make_shared<spdlog::logger>("level-off/backtrace-on"); | ||||||
|  |     empty_logger_tracing->set_level(spdlog::level::off); | ||||||
|  |     empty_logger_tracing->enable_backtrace(32); | ||||||
|  |     bench(iters, empty_logger_tracing); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void bench_single_threaded(int iters) | ||||||
|  | { | ||||||
|  |     spdlog::info("**************************************************************"); | ||||||
|  |     spdlog::info("Single threaded: {:n} messages", iters); | ||||||
|  |     spdlog::info("**************************************************************"); | ||||||
|  |  | ||||||
|  |     auto basic_st = spdlog::basic_logger_st("basic_st", "logs/basic_st.log", true); | ||||||
|  |     bench(iters, std::move(basic_st)); | ||||||
|  |  | ||||||
|  |     auto basic_st_tracing = spdlog::basic_logger_st("basic_st/backtrace-on", "logs/basic_st.log", true); | ||||||
|  |     bench(iters, std::move(basic_st_tracing)); | ||||||
|  |  | ||||||
|  |     spdlog::info(""); | ||||||
|  |     auto rotating_st = spdlog::rotating_logger_st("rotating_st", "logs/rotating_st.log", file_size, rotating_files); | ||||||
|  |     bench(iters, std::move(rotating_st)); | ||||||
|  |     auto rotating_st_tracing = spdlog::rotating_logger_st("rotating_st/backtrace-on", "logs/rotating_st.log", file_size, rotating_files); | ||||||
|  |     rotating_st_tracing->enable_backtrace(32); | ||||||
|  |     bench(iters, std::move(rotating_st_tracing)); | ||||||
|  |  | ||||||
|  |     spdlog::info(""); | ||||||
|  |     auto daily_st = spdlog::daily_logger_st("daily_st", "logs/daily_st.log"); | ||||||
|  |     bench(iters, std::move(daily_st)); | ||||||
|  |     auto daily_st_tracing = spdlog::daily_logger_st("daily_st/backtrace-on", "logs/daily_st.log"); | ||||||
|  |     daily_st_tracing->enable_backtrace(32); | ||||||
|  |     bench(iters, std::move(daily_st_tracing)); | ||||||
|  |  | ||||||
|  |     spdlog::info(""); | ||||||
|  |     auto empty_logger = std::make_shared<spdlog::logger>("level-off"); | ||||||
|  |     empty_logger->set_level(spdlog::level::off); | ||||||
|  |     bench(iters, empty_logger); | ||||||
|  |  | ||||||
|  |     auto empty_logger_tracing = std::make_shared<spdlog::logger>("level-off/backtrace-on"); | ||||||
|  |     empty_logger_tracing->set_level(spdlog::level::off); | ||||||
|  |     empty_logger_tracing->enable_backtrace(32); | ||||||
|  |     bench(iters, empty_logger_tracing); | ||||||
|  | } | ||||||
|  |  | ||||||
| int main(int argc, char *argv[]) | int main(int argc, char *argv[]) | ||||||
| { | { | ||||||
|  |     spdlog::set_automatic_registration(false); | ||||||
|     spdlog::default_logger()->set_pattern("[%^%l%$] %v"); |     spdlog::default_logger()->set_pattern("[%^%l%$] %v"); | ||||||
|     int howmany = 1000000; |     int iters = 250000; | ||||||
|     int queue_size = howmany + 2; |     int threads = 4; | ||||||
|     int threads = 10; |  | ||||||
|     size_t file_size = 30 * 1024 * 1024; |  | ||||||
|     size_t rotating_files = 5; |  | ||||||
|  |  | ||||||
|     try |     try | ||||||
|     { |     { | ||||||
|  |  | ||||||
|         if (argc > 1) |         if (argc > 1) | ||||||
|             howmany = atoi(argv[1]); |             iters = atoi(argv[1]); | ||||||
|         if (argc > 2) |         if (argc > 2) | ||||||
|             threads = atoi(argv[2]); |             threads = atoi(argv[2]); | ||||||
|         if (argc > 3) |  | ||||||
|             queue_size = atoi(argv[3]); |  | ||||||
|  |  | ||||||
|         spdlog::info("**************************************************************"); |         bench_single_threaded(iters); | ||||||
|         spdlog::info("Single thread, {:n} iterations", howmany); |         bench_threaded_logging(1, iters); | ||||||
|         spdlog::info("**************************************************************"); |         bench_threaded_logging(threads, iters); | ||||||
|  |  | ||||||
|         auto basic_st = spdlog::basic_logger_st("basic_st", "logs/basic_st.log", true); |  | ||||||
|         bench(howmany, std::move(basic_st)); |  | ||||||
|  |  | ||||||
|         basic_st.reset(); |  | ||||||
|         auto rotating_st = spdlog::rotating_logger_st("rotating_st", "logs/rotating_st.log", file_size, rotating_files); |  | ||||||
|         bench(howmany, std::move(rotating_st)); |  | ||||||
|  |  | ||||||
|         auto daily_st = spdlog::daily_logger_st("daily_st", "logs/daily_st.log"); |  | ||||||
|         bench(howmany, std::move(daily_st)); |  | ||||||
|  |  | ||||||
|         bench(howmany, spdlog::create<null_sink_st>("null_st")); |  | ||||||
|  |  | ||||||
|         spdlog::info("**************************************************************"); |  | ||||||
|         spdlog::info("C-string (400 bytes). Single thread, {:n} iterations", howmany); |  | ||||||
|         spdlog::info("**************************************************************"); |  | ||||||
|  |  | ||||||
|         basic_st = spdlog::basic_logger_st("basic_st", "logs/basic_cs.log", true); |  | ||||||
|         bench_c_string(howmany, std::move(basic_st)); |  | ||||||
|  |  | ||||||
|         rotating_st = spdlog::rotating_logger_st("rotating_st", "logs/rotating_cs.log", file_size, rotating_files); |  | ||||||
|         bench_c_string(howmany, std::move(rotating_st)); |  | ||||||
|  |  | ||||||
|         daily_st = spdlog::daily_logger_st("daily_st", "logs/daily_cs.log"); |  | ||||||
|         bench_c_string(howmany, std::move(daily_st)); |  | ||||||
|  |  | ||||||
|         bench_c_string(howmany, spdlog::create<null_sink_st>("null_st")); |  | ||||||
|  |  | ||||||
|         spdlog::info("**************************************************************"); |  | ||||||
|         spdlog::info("{:n} threads sharing same logger, {:n} iterations", threads, howmany); |  | ||||||
|         spdlog::info("**************************************************************"); |  | ||||||
|  |  | ||||||
|         auto basic_mt = spdlog::basic_logger_mt("basic_mt", "logs/basic_mt.log", true); |  | ||||||
|         bench_mt(howmany, std::move(basic_mt), threads); |  | ||||||
|  |  | ||||||
|         auto rotating_mt = spdlog::rotating_logger_mt("rotating_mt", "logs/rotating_mt.log", file_size, rotating_files); |  | ||||||
|         bench_mt(howmany, std::move(rotating_mt), threads); |  | ||||||
|  |  | ||||||
|         auto daily_mt = spdlog::daily_logger_mt("daily_mt", "logs/daily_mt.log"); |  | ||||||
|         bench_mt(howmany, std::move(daily_mt), threads); |  | ||||||
|         bench_mt(howmany, spdlog::create<null_sink_mt>("null_mt"), threads); |  | ||||||
|  |  | ||||||
|         spdlog::info("**************************************************************"); |  | ||||||
|         spdlog::info("Asyncronous.. {:n} threads sharing same logger, {:n} iterations", threads, howmany); |  | ||||||
|         spdlog::info("**************************************************************"); |  | ||||||
|  |  | ||||||
|         for (int i = 0; i < 3; ++i) |  | ||||||
|         { |  | ||||||
|             spdlog::init_thread_pool(static_cast<size_t>(queue_size), 1); |  | ||||||
|             auto as = spdlog::basic_logger_mt<spdlog::async_factory>("async", "logs/basic_async.log", true); |  | ||||||
|             bench_mt(howmany, std::move(as), threads); |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
|     catch (std::exception &ex) |     catch (std::exception &ex) | ||||||
|     { |     { | ||||||
| @@ -127,7 +144,7 @@ void bench(int howmany, std::shared_ptr<spdlog::logger> log) | |||||||
|     auto delta = high_resolution_clock::now() - start; |     auto delta = high_resolution_clock::now() - start; | ||||||
|     auto delta_d = duration_cast<duration<double>>(delta).count(); |     auto delta_d = duration_cast<duration<double>>(delta).count(); | ||||||
|  |  | ||||||
|     spdlog::info("{:<16} Elapsed: {:0.2f} secs {:>16n}/sec", log->name(), delta_d, int(howmany / delta_d)); |     spdlog::info("{:<30} Elapsed: {:0.2f} secs {:>16n}/sec", log->name(), delta_d, int(howmany / delta_d)); | ||||||
|     spdlog::drop(log->name()); |     spdlog::drop(log->name()); | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -153,7 +170,7 @@ void bench_mt(int howmany, std::shared_ptr<spdlog::logger> log, int thread_count | |||||||
|  |  | ||||||
|     auto delta = high_resolution_clock::now() - start; |     auto delta = high_resolution_clock::now() - start; | ||||||
|     auto delta_d = duration_cast<duration<double>>(delta).count(); |     auto delta_d = duration_cast<duration<double>>(delta).count(); | ||||||
|     spdlog::info("{:<16} Elapsed: {:0.2f} secs {:>16n}/sec", log->name(), delta_d, int(howmany / delta_d)); |     spdlog::info("{:<30} Elapsed: {:0.2f} secs {:>16n}/sec", log->name(), delta_d, int(howmany / delta_d)); | ||||||
|     spdlog::drop(log->name()); |     spdlog::drop(log->name()); | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -172,7 +189,7 @@ void bench_default_api(int howmany, std::shared_ptr<spdlog::logger> log) | |||||||
|     auto delta_d = duration_cast<duration<double>>(delta).count(); |     auto delta_d = duration_cast<duration<double>>(delta).count(); | ||||||
|     spdlog::drop(log->name()); |     spdlog::drop(log->name()); | ||||||
|     spdlog::set_default_logger(std::move(orig_default)); |     spdlog::set_default_logger(std::move(orig_default)); | ||||||
|     spdlog::info("{:<16} Elapsed: {:0.2f} secs {:>16n}/sec", log->name(), delta_d, int(howmany / delta_d)); |     spdlog::info("{:<30} Elapsed: {:0.2f} secs {:>16n}/sec", log->name(), delta_d, int(howmany / delta_d)); | ||||||
| } | } | ||||||
|  |  | ||||||
| void bench_c_string(int howmany, std::shared_ptr<spdlog::logger> log) | void bench_c_string(int howmany, std::shared_ptr<spdlog::logger> log) | ||||||
| @@ -195,5 +212,5 @@ void bench_c_string(int howmany, std::shared_ptr<spdlog::logger> log) | |||||||
|     auto delta_d = duration_cast<duration<double>>(delta).count(); |     auto delta_d = duration_cast<duration<double>>(delta).count(); | ||||||
|     spdlog::drop(log->name()); |     spdlog::drop(log->name()); | ||||||
|     spdlog::set_default_logger(std::move(orig_default)); |     spdlog::set_default_logger(std::move(orig_default)); | ||||||
|     spdlog::info("{:<16} Elapsed: {:0.2f} secs {:>16n}/sec", log->name(), delta_d, int(howmany / delta_d)); |     spdlog::info("{:<30} Elapsed: {:0.2f} secs {:>16n}/sec", log->name(), delta_d, int(howmany / delta_d)); | ||||||
| } | } | ||||||
|   | |||||||
							
								
								
									
										20
									
								
								third_party/spdlog/bench/formatter-bench.cpp
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										20
									
								
								third_party/spdlog/bench/formatter-bench.cpp
									
									
									
									
										vendored
									
									
								
							| @@ -8,27 +8,15 @@ | |||||||
| #include "spdlog/spdlog.h" | #include "spdlog/spdlog.h" | ||||||
| #include "spdlog/details/pattern_formatter.h" | #include "spdlog/details/pattern_formatter.h" | ||||||
|  |  | ||||||
| void bench_scoped_pad(benchmark::State &state, size_t wrapped_size, spdlog::details::padding_info padinfo) |  | ||||||
| { |  | ||||||
|     fmt::memory_buffer dest; |  | ||||||
|     for (auto _ : state) |  | ||||||
|     { |  | ||||||
|         { |  | ||||||
|             spdlog::details::scoped_pad p(wrapped_size, padinfo, dest); |  | ||||||
|             benchmark::DoNotOptimize(p); |  | ||||||
|             dest.clear(); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void bench_formatter(benchmark::State &state, std::string pattern) | void bench_formatter(benchmark::State &state, std::string pattern) | ||||||
| { | { | ||||||
|     auto formatter = spdlog::details::make_unique<spdlog::pattern_formatter>(pattern); |     auto formatter = spdlog::details::make_unique<spdlog::pattern_formatter>(pattern); | ||||||
|     fmt::memory_buffer dest; |     spdlog::memory_buf_t dest; | ||||||
|     std::string logger_name = "logger-name"; |     std::string logger_name = "logger-name"; | ||||||
|     const char *text = "Hello. This is some message with length of 80                                   "; |     const char *text = "Hello. This is some message with length of 80                                   "; | ||||||
|  |  | ||||||
|     spdlog::details::log_msg msg(&logger_name, spdlog::level::info, text); |     spdlog::source_loc source_loc{"a/b/c/d/myfile.cpp", 123, "some_func()"}; | ||||||
|  |     spdlog::details::log_msg msg(source_loc, logger_name, spdlog::level::info, text); | ||||||
|  |  | ||||||
|     for (auto _ : state) |     for (auto _ : state) | ||||||
|     { |     { | ||||||
| @@ -41,7 +29,7 @@ void bench_formatter(benchmark::State &state, std::string pattern) | |||||||
| void bench_formatters() | void bench_formatters() | ||||||
| { | { | ||||||
|     // basic patterns(single flag) |     // basic patterns(single flag) | ||||||
|     std::string all_flags = "+vtPnlLaAbBcCYDmdHIMSefFprRTXzEi%"; |     std::string all_flags = "+vtPnlLaAbBcCYDmdHIMSefFprRTXzEisg@luioO%"; | ||||||
|     std::vector<std::string> basic_patterns; |     std::vector<std::string> basic_patterns; | ||||||
|     for (auto &flag : all_flags) |     for (auto &flag : all_flags) | ||||||
|     { |     { | ||||||
|   | |||||||
							
								
								
									
										32
									
								
								third_party/spdlog/bench/latency.cpp
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										32
									
								
								third_party/spdlog/bench/latency.cpp
									
									
									
									
										vendored
									
									
								
							| @@ -90,29 +90,50 @@ int main(int argc, char *argv[]) | |||||||
|     disabled_logger->set_level(spdlog::level::off); |     disabled_logger->set_level(spdlog::level::off); | ||||||
|     benchmark::RegisterBenchmark("disabled-at-compile-time", bench_disabled_macro, disabled_logger); |     benchmark::RegisterBenchmark("disabled-at-compile-time", bench_disabled_macro, disabled_logger); | ||||||
|     benchmark::RegisterBenchmark("disabled-at-runtime", bench_logger, disabled_logger); |     benchmark::RegisterBenchmark("disabled-at-runtime", bench_logger, disabled_logger); | ||||||
|  |     // with backtrace of 64 | ||||||
|  |     auto tracing_disabled_logger = std::make_shared<spdlog::logger>("bench", std::make_shared<null_sink_mt>()); | ||||||
|  |     tracing_disabled_logger->enable_backtrace(64); | ||||||
|  |     benchmark::RegisterBenchmark("disabled-at-runtime/backtrace", bench_logger, tracing_disabled_logger); | ||||||
|  |  | ||||||
|     auto null_logger_st = std::make_shared<spdlog::logger>("bench", std::make_shared<null_sink_st>()); |     auto null_logger_st = std::make_shared<spdlog::logger>("bench", std::make_shared<null_sink_st>()); | ||||||
|     benchmark::RegisterBenchmark("null_sink_st (500_bytes c_str)", bench_c_string, std::move(null_logger_st)); |     benchmark::RegisterBenchmark("null_sink_st (500_bytes c_str)", bench_c_string, std::move(null_logger_st)); | ||||||
|     benchmark::RegisterBenchmark("null_sink_st", bench_logger, null_logger_st); |     benchmark::RegisterBenchmark("null_sink_st", bench_logger, null_logger_st); | ||||||
|  |     // with backtrace of 64 | ||||||
|  |     auto tracing_null_logger_st = std::make_shared<spdlog::logger>("bench", std::make_shared<null_sink_st>()); | ||||||
|  |     tracing_null_logger_st->enable_backtrace(64); | ||||||
|  |     benchmark::RegisterBenchmark("null_sink_st/backtrace", bench_logger, tracing_null_logger_st); | ||||||
|  |  | ||||||
|     // basic_st |     // basic_st | ||||||
|     auto basic_st = spdlog::basic_logger_st("basic_st", "latency_logs/basic_st.log", true); |     auto basic_st = spdlog::basic_logger_st("basic_st", "latency_logs/basic_st.log", true); | ||||||
|     benchmark::RegisterBenchmark("basic_st", bench_logger, std::move(basic_st))->UseRealTime(); |     benchmark::RegisterBenchmark("basic_st", bench_logger, std::move(basic_st))->UseRealTime(); | ||||||
|     spdlog::drop("basic_st"); |     spdlog::drop("basic_st"); | ||||||
|  |     // with backtrace of 64 | ||||||
|  |     auto tracing_basic_st = spdlog::basic_logger_st("tracing_basic_st", "latency_logs/tracing_basic_st.log", true); | ||||||
|  |     tracing_basic_st->enable_backtrace(64); | ||||||
|  |     benchmark::RegisterBenchmark("basic_st/backtrace", bench_logger, std::move(tracing_basic_st))->UseRealTime(); | ||||||
|  |     spdlog::drop("tracing_basic_st"); | ||||||
|  |  | ||||||
|     // rotating st |     // rotating st | ||||||
|     auto rotating_st = spdlog::rotating_logger_st("rotating_st", "latency_logs/rotating_st.log", file_size, rotating_files); |     auto rotating_st = spdlog::rotating_logger_st("rotating_st", "latency_logs/rotating_st.log", file_size, rotating_files); | ||||||
|     benchmark::RegisterBenchmark("rotating_st", bench_logger, std::move(rotating_st))->UseRealTime(); |     benchmark::RegisterBenchmark("rotating_st", bench_logger, std::move(rotating_st))->UseRealTime(); | ||||||
|     spdlog::drop("rotating_st"); |     spdlog::drop("rotating_st"); | ||||||
|  |     // with backtrace of 64 | ||||||
|  |     auto tracing_rotating_st = | ||||||
|  |         spdlog::rotating_logger_st("tracing_rotating_st", "latency_logs/tracing_rotating_st.log", file_size, rotating_files); | ||||||
|  |     benchmark::RegisterBenchmark("rotating_st/backtrace", bench_logger, std::move(tracing_rotating_st))->UseRealTime(); | ||||||
|  |     spdlog::drop("tracing_rotating_st"); | ||||||
|  |  | ||||||
|     // daily st |     // daily st | ||||||
|     auto daily_st = spdlog::daily_logger_mt("daily_st", "latency_logs/daily_st.log"); |     auto daily_st = spdlog::daily_logger_mt("daily_st", "latency_logs/daily_st.log"); | ||||||
|     benchmark::RegisterBenchmark("daily_st", bench_logger, std::move(daily_st))->UseRealTime(); |     benchmark::RegisterBenchmark("daily_st", bench_logger, std::move(daily_st))->UseRealTime(); | ||||||
|     spdlog::drop("daily_st"); |     spdlog::drop("daily_st"); | ||||||
|  |     auto tracing_daily_st = spdlog::daily_logger_mt("tracing_daily_st", "latency_logs/daily_st.log"); | ||||||
|  |     benchmark::RegisterBenchmark("daily_st/backtrace", bench_logger, std::move(tracing_daily_st))->UseRealTime(); | ||||||
|  |     spdlog::drop("tracing_daily_st"); | ||||||
|  |  | ||||||
|     //    // |     // | ||||||
|     //    // Multi threaded bench, 10 loggers using same logger concurrently |     // Multi threaded bench, 10 loggers using same logger concurrently | ||||||
|     //    // |     // | ||||||
|     auto null_logger_mt = std::make_shared<spdlog::logger>("bench", std::make_shared<null_sink_mt>()); |     auto null_logger_mt = std::make_shared<spdlog::logger>("bench", std::make_shared<null_sink_mt>()); | ||||||
|     benchmark::RegisterBenchmark("null_sink_mt", bench_logger, null_logger_mt)->Threads(n_threads)->UseRealTime(); |     benchmark::RegisterBenchmark("null_sink_mt", bench_logger, null_logger_mt)->Threads(n_threads)->UseRealTime(); | ||||||
|  |  | ||||||
| @@ -138,6 +159,11 @@ int main(int argc, char *argv[]) | |||||||
|         "async_logger", std::make_shared<null_sink_mt>(), std::move(tp), spdlog::async_overflow_policy::overrun_oldest); |         "async_logger", std::make_shared<null_sink_mt>(), std::move(tp), spdlog::async_overflow_policy::overrun_oldest); | ||||||
|     benchmark::RegisterBenchmark("async_logger", bench_logger, async_logger)->Threads(n_threads)->UseRealTime(); |     benchmark::RegisterBenchmark("async_logger", bench_logger, async_logger)->Threads(n_threads)->UseRealTime(); | ||||||
|  |  | ||||||
|  |     auto async_logger_tracing = std::make_shared<spdlog::async_logger>( | ||||||
|  |         "async_logger_tracing", std::make_shared<null_sink_mt>(), std::move(tp), spdlog::async_overflow_policy::overrun_oldest); | ||||||
|  |     async_logger_tracing->enable_backtrace(32); | ||||||
|  |     benchmark::RegisterBenchmark("async_logger/tracing", bench_logger, async_logger_tracing)->Threads(n_threads)->UseRealTime(); | ||||||
|  |  | ||||||
|     benchmark::Initialize(&argc, argv); |     benchmark::Initialize(&argc, argv); | ||||||
|     benchmark::RunSpecifiedBenchmarks(); |     benchmark::RunSpecifiedBenchmarks(); | ||||||
| } | } | ||||||
|   | |||||||
							
								
								
									
										4
									
								
								third_party/spdlog/bench/logs/.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								third_party/spdlog/bench/logs/.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -1,4 +0,0 @@ | |||||||
| # Ignore everything in this directory |  | ||||||
| * |  | ||||||
| # Except this file |  | ||||||
| !.gitignore |  | ||||||
							
								
								
									
										19
									
								
								third_party/spdlog/bench/mem
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										19
									
								
								third_party/spdlog/bench/mem
									
									
									
									
										vendored
									
									
								
							| @@ -1,19 +0,0 @@ | |||||||
| #!/bin/sh |  | ||||||
|  |  | ||||||
| if [ $# -lt 1 ]; then |  | ||||||
|   echo "usage: $0 <program>" |  | ||||||
| fi |  | ||||||
|  |  | ||||||
| PROG=$1 |  | ||||||
|  |  | ||||||
| if [ ! -x "$PROG" ]; then |  | ||||||
|   echo $PROG not found or not executable. |  | ||||||
|   exit 1 |  | ||||||
| fi |  | ||||||
|  |  | ||||||
| $* & |  | ||||||
| PID=$! |  | ||||||
|  |  | ||||||
| while `kill -0 $PID 2>/dev/null`; do |  | ||||||
|   ps -eo size,pid,user,pcpu,command --sort -size | awk '{ line=1 ; hr=$1/1024 ; printf("%13.2f Mb ",hr); } { for ( x=4 ; x<=NF ; x++ ) { printf("%s ",$x) } print "" }' | grep -v grep | grep -v $0 | grep $PROG |  | ||||||
| done |  | ||||||
							
								
								
									
										15
									
								
								third_party/spdlog/bench/meson.build
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								third_party/spdlog/bench/meson.build
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,15 @@ | |||||||
|  | benchmark = dependency('benchmark') | ||||||
|  |  | ||||||
|  | bench_matrix = [ | ||||||
|  |   ['bench',           [spdlog_dep],            []], | ||||||
|  |   ['async_bench',     [spdlog_dep],            []], | ||||||
|  |   ['formatter-bench', [spdlog_dep, benchmark], ['all']], | ||||||
|  |   ['latency',         [spdlog_dep, benchmark], []], | ||||||
|  | ] | ||||||
|  |  | ||||||
|  | foreach i : bench_matrix | ||||||
|  |   bench_exe = executable(i[0], i[0] + '.cpp', dependencies: i[1]) | ||||||
|  |   benchmark('bench_' + i[0], bench_exe, args: i[2]) | ||||||
|  | endforeach | ||||||
|  |  | ||||||
|  | run_command(find_program('mkdir'), meson.current_build_dir() + '/logs') | ||||||
							
								
								
									
										2
									
								
								third_party/spdlog/clang_tidy.sh
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								third_party/spdlog/clang_tidy.sh
									
									
									
									
										vendored
									
									
								
							| @@ -1,2 +0,0 @@ | |||||||
| #!/bin/bash |  | ||||||
| clang-tidy example/example.cpp -- -I ./include  |  | ||||||
							
								
								
									
										31
									
								
								third_party/spdlog/cmake/Config.cmake.in
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										31
									
								
								third_party/spdlog/cmake/Config.cmake.in
									
									
									
									
										vendored
									
									
								
							| @@ -1,31 +0,0 @@ | |||||||
| # *************************************************************************/ |  | ||||||
| # * Copyright (c) 2015 Ruslan Baratov.                                    */ |  | ||||||
| # *                                                                       */ |  | ||||||
| # * Permission is hereby granted, free of charge, to any person obtaining */ |  | ||||||
| # * a copy of this software and associated documentation files (the       */ |  | ||||||
| # * "Software"), to deal in the Software without restriction, including   */ |  | ||||||
| # * without limitation the rights to use, copy, modify, merge, publish,   */ |  | ||||||
| # * distribute, sublicense, and/or sell copies of the Software, and to    */ |  | ||||||
| # * permit persons to whom the Software is furnished to do so, subject to */ |  | ||||||
| # * the following conditions:                                             */ |  | ||||||
| # *                                                                       */ |  | ||||||
| # * The above copyright notice and this permission notice shall be        */ |  | ||||||
| # * included in all copies or substantial portions of the Software.       */ |  | ||||||
| # *                                                                       */ |  | ||||||
| # * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */ |  | ||||||
| # * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */ |  | ||||||
| # * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ |  | ||||||
| # * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */ |  | ||||||
| # * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */ |  | ||||||
| # * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */ |  | ||||||
| # * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */ |  | ||||||
| # *************************************************************************/ |  | ||||||
|  |  | ||||||
| set(SPDLOG_FMT_EXTERNAL @SPDLOG_FMT_EXTERNAL@) |  | ||||||
|  |  | ||||||
| include("${CMAKE_CURRENT_LIST_DIR}/@targets_export_name@.cmake") |  | ||||||
|  |  | ||||||
| if(SPDLOG_FMT_EXTERNAL) |  | ||||||
|     include(CMakeFindDependencyMacro) |  | ||||||
|     find_dependency(fmt CONFIG) |  | ||||||
| endif() |  | ||||||
							
								
								
									
										18
									
								
								third_party/spdlog/cmake/ide.cmake
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								third_party/spdlog/cmake/ide.cmake
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,18 @@ | |||||||
|  | #--------------------------------------------------------------------------------------- | ||||||
|  | # IDE support for headers | ||||||
|  | #--------------------------------------------------------------------------------------- | ||||||
|  | set(SPDLOG_HEADERS_DIR "${CMAKE_CURRENT_LIST_DIR}/../include") | ||||||
|  |  | ||||||
|  | file(GLOB SPDLOG_TOP_HEADERS "${SPDLOG_HEADERS_DIR}/spdlog/*.h") | ||||||
|  | file(GLOB SPDLOG_DETAILS_HEADERS "${SPDLOG_HEADERS_DIR}/spdlog/details/*.h") | ||||||
|  | file(GLOB SPDLOG_SINKS_HEADERS "${SPDLOG_HEADERS_DIR}/spdlog/sinks/*.h") | ||||||
|  | file(GLOB SPDLOG_FMT_HEADERS "${SPDLOG_HEADERS_DIR}/spdlog/fmt/*.h") | ||||||
|  | file(GLOB SPDLOG_FMT_BUNDELED_HEADERS "${SPDLOG_HEADERS_DIR}/spdlog/fmt/bundled/*.h") | ||||||
|  | set(SPDLOG_ALL_HEADERS ${SPDLOG_TOP_HEADERS} ${SPDLOG_DETAILS_HEADERS} ${SPDLOG_SINKS_HEADERS} ${SPDLOG_FMT_HEADERS} ${SPDLOG_FMT_BUNDELED_HEADERS}) | ||||||
|  |  | ||||||
|  | source_group("Header Files\\spdlog" FILES ${SPDLOG_TOP_HEADERS}) | ||||||
|  | source_group("Header Files\\spdlog\\details" FILES ${SPDLOG_DETAILS_HEADERS}) | ||||||
|  | source_group("Header Files\\spdlog\\sinks" FILES ${SPDLOG_SINKS_HEADERS}) | ||||||
|  | source_group("Header Files\\spdlog\\fmt" FILES ${SPDLOG_FMT_HEADERS}) | ||||||
|  | source_group("Header Files\\spdlog\\fmt\\bundled\\" FILES ${SPDLOG_FMT_BUNDELED_HEADERS}) | ||||||
|  |  | ||||||
							
								
								
									
										21
									
								
								third_party/spdlog/cmake/sanitizers.cmake
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										21
									
								
								third_party/spdlog/cmake/sanitizers.cmake
									
									
									
									
										vendored
									
									
								
							| @@ -1,21 +0,0 @@ | |||||||
| if(SPDLOG_SANITIZE_THREAD AND SPDLOG_SANITIZE_ADDRESS) |  | ||||||
|     message(FATAL_ERROR "AddressSanitizer is not compatible with ThreadSanitizer.") |  | ||||||
| endif() |  | ||||||
|  |  | ||||||
| if(SPDLOG_SANITIZE_ADDRESS) |  | ||||||
|     message(STATUS "AddressSanitizer enabled") |  | ||||||
|     set(SANITIZER_FLAGS "-fsanitize=address,undefined") |  | ||||||
|     add_compile_options("-fno-sanitize=signed-integer-overflow") |  | ||||||
| endif() |  | ||||||
|  |  | ||||||
| if(SPDLOG_SANITIZE_THREAD) |  | ||||||
|     message(STATUS "ThreadSanitizer enabled") |  | ||||||
|     set(SANITIZER_FLAGS "-fsanitize=thread") |  | ||||||
| endif() |  | ||||||
|  |  | ||||||
| if(SPDLOG_SANITIZE_THREAD OR SPDLOG_SANITIZE_ADDRESS) |  | ||||||
|     add_compile_options(${SANITIZER_FLAGS}) |  | ||||||
|     add_compile_options("-fno-sanitize-recover=all") |  | ||||||
|     add_compile_options("-fno-omit-frame-pointer") |  | ||||||
|     set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${SANITIZER_FLAGS} -fuse-ld=gold") |  | ||||||
| endif() |  | ||||||
							
								
								
									
										11
									
								
								third_party/spdlog/cmake/spdlog.pc.in
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										11
									
								
								third_party/spdlog/cmake/spdlog.pc.in
									
									
									
									
										vendored
									
									
								
							| @@ -1,6 +1,11 @@ | |||||||
| prefix=@CMAKE_INSTALL_PREFIX@ | prefix=@CMAKE_INSTALL_PREFIX@ | ||||||
|  | exec_prefix=${prefix} | ||||||
| includedir=${prefix}/include | includedir=${prefix}/include | ||||||
|  | libdir=${exec_prefix}/@CMAKE_INSTALL_LIBDIR@ | ||||||
|  |  | ||||||
| Name: @PROJECT_NAME@ | Name: lib@PROJECT_NAME@ | ||||||
| Description: Super fast C++ logging library.  | Description: Fast C++ logging library. | ||||||
| Version: @PROJECT_VERSION@ | URL: https://github.com/gabime/@PROJECT_NAME@ | ||||||
|  | Version: @SPDLOG_VERSION@ | ||||||
|  | CFlags: -I${includedir}/@SPDLOG_CFLAGS@ | ||||||
|  | Libs: -L${libdir}/@PROJECT_NAME@ -l@PROJECT_NAME@ | ||||||
|   | |||||||
							
								
								
									
										32
									
								
								third_party/spdlog/cmake/spdlogCPack.cmake
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								third_party/spdlog/cmake/spdlogCPack.cmake
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,32 @@ | |||||||
|  | set(CPACK_GENERATOR | ||||||
|  |     TGZ | ||||||
|  |     ZIP | ||||||
|  |     ) | ||||||
|  |  | ||||||
|  | set(CPACK_INCLUDE_TOPLEVEL_DIRECTORY 0) | ||||||
|  | set(CPACK_INSTALL_CMAKE_PROJECTS | ||||||
|  |     "${CMAKE_BINARY_DIR}" | ||||||
|  |     "${PROJECT_NAME}" | ||||||
|  |     ALL | ||||||
|  |     . | ||||||
|  |     ) | ||||||
|  |  | ||||||
|  | set(CPACK_PROJECT_URL "https://github.com/gabime/spdlog") | ||||||
|  | set(CPACK_PACKAGE_VENDOR "Gabi Melman") | ||||||
|  | set(CPACK_PACKAGE_CONTACT "Gabi Melman <gmelman1@gmail.com>") | ||||||
|  | set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Fast C++ logging library") | ||||||
|  | set(CPACK_PACKAGE_VERSION_MAJOR ${PROJECT_VERSION_MAJOR}) | ||||||
|  | set(CPACK_PACKAGE_VERSION_MINOR ${PROJECT_VERSION_MINOR}) | ||||||
|  | set(CPACK_PACKAGE_VERSION_PATCH ${PROJECT_VERSION_PATCH}) | ||||||
|  | set(CPACK_PACKAGE_VERSION ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}) | ||||||
|  | if (PROJECT_VERSION_TWEAK) | ||||||
|  |     set(CPACK_PACKAGE_VERSION ${CPACK_PACKAGE_VERSION}.${PROJECT_VERSION_TWEAK}) | ||||||
|  | endif () | ||||||
|  | set(CPACK_PACKAGE_RELOCATABLE ON) | ||||||
|  |  | ||||||
|  | set(CPACK_RPM_PACKAGE_LICENSE "MIT") | ||||||
|  | set(CPACK_RPM_PACKAGE_GROUP "System Environment/Libraries") | ||||||
|  | set(CPACK_RPM_PACKAGE_URL ${CPACK_PROJECT_URL}) | ||||||
|  | set(CPACK_RPM_PACKAGE_DESCRIPTION "Very fast, header-only/compiled, C++ logging library.") | ||||||
|  |  | ||||||
|  | include(CPack) | ||||||
							
								
								
									
										15
									
								
								third_party/spdlog/cmake/spdlogConfig.cmake.in
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								third_party/spdlog/cmake/spdlogConfig.cmake.in
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,15 @@ | |||||||
|  | # Copyright(c) 2019 spdlog authors | ||||||
|  | # Distributed under the MIT License (http://opensource.org/licenses/MIT) | ||||||
|  |  | ||||||
|  | find_package(Threads REQUIRED) | ||||||
|  |  | ||||||
|  | set(SPDLOG_FMT_EXTERNAL @SPDLOG_FMT_EXTERNAL@) | ||||||
|  | set(config_targets_file @config_targets_file@) | ||||||
|  |  | ||||||
|  | if(SPDLOG_FMT_EXTERNAL) | ||||||
|  |     include(CMakeFindDependencyMacro) | ||||||
|  |     find_dependency(fmt CONFIG) | ||||||
|  | endif() | ||||||
|  |  | ||||||
|  |  | ||||||
|  | include("${CMAKE_CURRENT_LIST_DIR}/${config_targets_file}") | ||||||
							
								
								
									
										47
									
								
								third_party/spdlog/cmake/utils.cmake
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								third_party/spdlog/cmake/utils.cmake
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,47 @@ | |||||||
|  | # Get spdlog version from include/spdlog/version.h and put it in SPDLOG_VERSION | ||||||
|  | function(spdlog_extract_version) | ||||||
|  | 	file(READ "${CMAKE_CURRENT_LIST_DIR}/include/spdlog/version.h" file_contents) | ||||||
|  | 	string(REGEX MATCH "SPDLOG_VER_MAJOR ([0-9]+)" _  "${file_contents}") | ||||||
|  | 	if(NOT CMAKE_MATCH_COUNT EQUAL 1) | ||||||
|  |         message(FATAL_ERROR "Could not extract major version number from spdlog/version.h") | ||||||
|  | 	endif() | ||||||
|  | 	set(ver_major ${CMAKE_MATCH_1}) | ||||||
|  |  | ||||||
|  | 	string(REGEX MATCH "SPDLOG_VER_MINOR ([0-9]+)" _  "${file_contents}") | ||||||
|  | 	if(NOT CMAKE_MATCH_COUNT EQUAL 1) | ||||||
|  |         message(FATAL_ERROR "Could not extract minor version number from spdlog/version.h") | ||||||
|  | 	endif() | ||||||
|  |  | ||||||
|  | 	set(ver_minor ${CMAKE_MATCH_1}) | ||||||
|  | 	string(REGEX MATCH "SPDLOG_VER_PATCH ([0-9]+)" _  "${file_contents}") | ||||||
|  | 	if(NOT CMAKE_MATCH_COUNT EQUAL 1) | ||||||
|  |         message(FATAL_ERROR "Could not extract patch version number from spdlog/version.h") | ||||||
|  | 	endif() | ||||||
|  | 	set(ver_patch ${CMAKE_MATCH_1}) | ||||||
|  |  | ||||||
|  |     set(SPDLOG_VERSION_MAJOR ${ver_major} PARENT_SCOPE) | ||||||
|  | 	set (SPDLOG_VERSION "${ver_major}.${ver_minor}.${ver_patch}" PARENT_SCOPE) | ||||||
|  | endfunction() | ||||||
|  |  | ||||||
|  |  | ||||||
|  | # Turn on warnings on the given target | ||||||
|  | function(spdlog_enable_warnings target_name) | ||||||
|  |     target_compile_options(${target_name} PRIVATE | ||||||
|  |         $<$<OR:$<CXX_COMPILER_ID:Clang>,$<CXX_COMPILER_ID:AppleClang>,$<CXX_COMPILER_ID:GNU>>: | ||||||
|  |             -Wall -Wextra -Wconversion -pedantic -Wfatal-errors> | ||||||
|  |         $<$<CXX_COMPILER_ID:MSVC>:/W4 /WX>) | ||||||
|  | endfunction() | ||||||
|  |  | ||||||
|  |  | ||||||
|  | # Enable address sanitizer (gcc/clang only) | ||||||
|  | function(spdlog_enable_sanitizer target_name) | ||||||
|  | 	if (NOT CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") | ||||||
|  | 		message(FATAL_ERROR "Sanitizer supported only for gcc/clang") | ||||||
|  | 	endif() | ||||||
|  | 	message(STATUS "Address sanitizer enabled") | ||||||
|  | 	target_compile_options(${target_name} PRIVATE -fsanitize=address,undefined) | ||||||
|  | 	target_compile_options(${target_name} PRIVATE -fno-sanitize=signed-integer-overflow) | ||||||
|  | 	target_compile_options(${target_name} PRIVATE -fno-sanitize-recover=all) | ||||||
|  | 	target_compile_options(${target_name} PRIVATE -fno-omit-frame-pointer) | ||||||
|  | 	target_link_libraries(${target_name} PRIVATE -fsanitize=address,undefined -fuse-ld=gold) | ||||||
|  | endfunction() | ||||||
							
								
								
									
										58
									
								
								third_party/spdlog/example/CMakeLists.txt
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										58
									
								
								third_party/spdlog/example/CMakeLists.txt
									
									
									
									
										vendored
									
									
								
							| @@ -1,49 +1,29 @@ | |||||||
| # *************************************************************************/ | # Copyright(c) 2019 spdlog authors | ||||||
| # * Copyright (c) 2015 Ruslan Baratov.                                    */ | # Distributed under the MIT License (http://opensource.org/licenses/MIT) | ||||||
| # *                                                                       */ |  | ||||||
| # * Permission is hereby granted, free of charge, to any person obtaining */ |  | ||||||
| # * a copy of this software and associated documentation files (the       */ |  | ||||||
| # * "Software"), to deal in the Software without restriction, including   */ |  | ||||||
| # * without limitation the rights to use, copy, modify, merge, publish,   */ |  | ||||||
| # * distribute, sublicense, and/or sell copies of the Software, and to    */ |  | ||||||
| # * permit persons to whom the Software is furnished to do so, subject to */ |  | ||||||
| # * the following conditions:                                             */ |  | ||||||
| # *                                                                       */ |  | ||||||
| # * The above copyright notice and this permission notice shall be        */ |  | ||||||
| # * included in all copies or substantial portions of the Software.       */ |  | ||||||
| # *                                                                       */ |  | ||||||
| # * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */ |  | ||||||
| # * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */ |  | ||||||
| # * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ |  | ||||||
| # * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */ |  | ||||||
| # * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */ |  | ||||||
| # * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */ |  | ||||||
| # * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */ |  | ||||||
| # *************************************************************************/ |  | ||||||
|  |  | ||||||
| cmake_minimum_required(VERSION 3.1) | cmake_minimum_required(VERSION 3.1) | ||||||
| project(SpdlogExamples CXX) | project(spdlog_examples CXX) | ||||||
|  |  | ||||||
| if(NOT TARGET spdlog) | if(NOT TARGET spdlog) | ||||||
|   # Stand-alone build |     # Stand-alone build | ||||||
|   find_package(spdlog CONFIG REQUIRED) |     find_package(spdlog REQUIRED) | ||||||
| endif() | endif() | ||||||
|  |  | ||||||
| find_package(Threads REQUIRED) | #--------------------------------------------------------------------------------------- | ||||||
|  | # Example of using pre-compiled library | ||||||
|  | #--------------------------------------------------------------------------------------- | ||||||
| add_executable(example example.cpp) | add_executable(example example.cpp) | ||||||
| if(CMAKE_SYSTEM_NAME STREQUAL "Android") | spdlog_enable_warnings(example) | ||||||
|     find_library(log-lib log) | target_link_libraries(example PRIVATE spdlog::spdlog) | ||||||
|     target_link_libraries(example spdlog::spdlog Threads::Threads log) |  | ||||||
| else() | #--------------------------------------------------------------------------------------- | ||||||
|     target_link_libraries(example spdlog::spdlog Threads::Threads) | # Example of using header-only library | ||||||
|  | #--------------------------------------------------------------------------------------- | ||||||
|  | if(SPDLOG_BUILD_EXAMPLE_HO) | ||||||
|  |     add_executable(example_header_only example.cpp) | ||||||
|  |     spdlog_enable_warnings(example_header_only) | ||||||
|  |     target_link_libraries(example_header_only PRIVATE spdlog::spdlog_header_only) | ||||||
| endif() | endif() | ||||||
|  |  | ||||||
|  | # Create logs directory | ||||||
| add_executable(multisink multisink.cpp) |  | ||||||
| target_link_libraries(multisink spdlog::spdlog Threads::Threads) |  | ||||||
|  |  | ||||||
| file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/logs") | file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/logs") | ||||||
|  |  | ||||||
| enable_testing() |  | ||||||
| add_test(NAME example COMMAND example) |  | ||||||
|   | |||||||
							
								
								
									
										22
									
								
								third_party/spdlog/example/Makefile-all-warn
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										22
									
								
								third_party/spdlog/example/Makefile-all-warn
									
									
									
									
										vendored
									
									
								
							| @@ -1,22 +0,0 @@ | |||||||
| #-Weverything -Wno-c++98-compat -Wno-c++98-compat-pedantic -Wno-padded |  | ||||||
| CXX	?= g++ |  | ||||||
| CXX_FLAGS = -Wall -Wextra -pedantic -std=c++11 -pthread -I../include -fmax-errors=1 -Wconversion -Weverything -Wno-c++98-compat -Wno-c++98-compat-pedantic -Wno-padded -Wno-weak-vtables -Wno-global-constructors |  | ||||||
| CXX_RELEASE_FLAGS = -O3 -march=native |  | ||||||
| CXX_DEBUG_FLAGS= -g |  | ||||||
|  |  | ||||||
| all:	example  |  | ||||||
| debug:	example-debug |  | ||||||
|  |  | ||||||
| example: example.cpp |  | ||||||
| 	$(CXX) example.cpp -o example $(CXX_FLAGS) $(CXX_RELEASE_FLAGS) $(CXXFLAGS) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| example-debug: example.cpp |  | ||||||
| 	$(CXX) example.cpp -o example-debug $(CXX_FLAGS) $(CXX_DEBUG_FLAGS) $(CXXFLAGS) |  | ||||||
|  |  | ||||||
| clean: |  | ||||||
| 	rm -f *.o logs/*.txt example example-debug |  | ||||||
|  |  | ||||||
|  |  | ||||||
| rebuild: clean all |  | ||||||
| rebuild-debug: clean debug |  | ||||||
							
								
								
									
										26
									
								
								third_party/spdlog/example/Makefile.clang
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										26
									
								
								third_party/spdlog/example/Makefile.clang
									
									
									
									
										vendored
									
									
								
							| @@ -1,26 +0,0 @@ | |||||||
| CXX	= clang++ |  | ||||||
| CXXFLAGS	= -march=native -Wall -Wextra -Wshadow -pedantic -std=c++11 -pthread -I../include |  | ||||||
| CXX_RELEASE_FLAGS = -O2 |  | ||||||
| CXX_DEBUG_FLAGS= -g  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| all:	example  |  | ||||||
| debug: example-debug  |  | ||||||
|  |  | ||||||
| example: example.cpp |  | ||||||
| 	$(CXX) example.cpp -o example-clang $(CXXFLAGS) $(CXX_RELEASE_FLAGS) |  | ||||||
|  |  | ||||||
| 	 |  | ||||||
|  |  | ||||||
| example-debug: example.cpp |  | ||||||
| 	$(CXX) example.cpp -o example-clang-debug $(CXXFLAGS) $(CXX_DEBUG_FLAGS) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| clean: |  | ||||||
| 	rm -f *.o logs/*.txt example-clang example-clang-debug  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| rebuild: clean all |  | ||||||
| rebuild-debug: clean debug |  | ||||||
|  |  | ||||||
|  |  | ||||||
							
								
								
									
										25
									
								
								third_party/spdlog/example/Makefile.mingw
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										25
									
								
								third_party/spdlog/example/Makefile.mingw
									
									
									
									
										vendored
									
									
								
							| @@ -1,25 +0,0 @@ | |||||||
| CXX	?= g++ |  | ||||||
| CXXFLAGS	=  -D_WIN32_WINNT=0x600 -march=native -Wall -Wextra -pedantic -std=gnu++0x -pthread -Wl,--no-as-needed  -I../include  |  | ||||||
| CXX_RELEASE_FLAGS = -O3  |  | ||||||
| CXX_DEBUG_FLAGS= -g  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| all:	example  |  | ||||||
| debug: example-debug  |  | ||||||
|  |  | ||||||
| example: example.cpp |  | ||||||
| 	$(CXX) example.cpp -o example $(CXXFLAGS) $(CXX_RELEASE_FLAGS) |  | ||||||
|  |  | ||||||
| 	 |  | ||||||
| example-debug: example.cpp |  | ||||||
| 	$(CXX) example.cpp -o example-debug $(CXXFLAGS) $(CXX_DEBUG_FLAGS) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| clean: |  | ||||||
| 	rm -f *.o logs/*.txt example example-debug |  | ||||||
|  |  | ||||||
|  |  | ||||||
| rebuild: clean all |  | ||||||
| rebuild-debug: clean debug |  | ||||||
|  |  | ||||||
|  |  | ||||||
							
								
								
									
										29
									
								
								third_party/spdlog/example/example.cpp
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										29
									
								
								third_party/spdlog/example/example.cpp
									
									
									
									
										vendored
									
									
								
							| @@ -1,11 +1,8 @@ | |||||||
| // | // | ||||||
| // Copyright(c) 2015 Gabi Melman. | // Copyright(c) 2015 Gabi Melman. | ||||||
| // Distributed under the MIT License (http://opensource.org/licenses/MIT) | // Distributed under the MIT License (http://opensource.org/licenses/MIT) | ||||||
| // |  | ||||||
| // |  | ||||||
| // spdlog usage example | // spdlog usage example | ||||||
| // |  | ||||||
| // |  | ||||||
|  |  | ||||||
| #include <cstdio> | #include <cstdio> | ||||||
|  |  | ||||||
| @@ -20,13 +17,12 @@ void multi_sink_example(); | |||||||
| void user_defined_example(); | void user_defined_example(); | ||||||
| void err_handler_example(); | void err_handler_example(); | ||||||
| void syslog_example(); | void syslog_example(); | ||||||
| void clone_example(); |  | ||||||
|  |  | ||||||
| #include "spdlog/spdlog.h" | #include "spdlog/spdlog.h" | ||||||
|  |  | ||||||
| int main(int, char *[]) | int main(int, char *[]) | ||||||
| { | { | ||||||
|     spdlog::info("Welcome to spdlog version {}.{}.{} !", SPDLOG_VER_MAJOR, SPDLOG_VER_MINOR, SPDLOG_VER_PATCH); |     spdlog::info("Welcome to spdlog version {}.{}.{}  !", SPDLOG_VER_MAJOR, SPDLOG_VER_MINOR, SPDLOG_VER_PATCH); | ||||||
|     spdlog::warn("Easy padding in numbers like {:08d}", 12); |     spdlog::warn("Easy padding in numbers like {:08d}", 12); | ||||||
|     spdlog::critical("Support for int: {0:d};  hex: {0:x};  oct: {0:o}; bin: {0:b}", 42); |     spdlog::critical("Support for int: {0:d};  hex: {0:x};  oct: {0:o}; bin: {0:b}", 42); | ||||||
|     spdlog::info("Support for floats {:03.2f}", 1.23456); |     spdlog::info("Support for floats {:03.2f}", 1.23456); | ||||||
| @@ -43,6 +39,18 @@ int main(int, char *[]) | |||||||
|     spdlog::set_pattern("[%H:%M:%S %z] [%^%L%$] [thread %t] %v"); |     spdlog::set_pattern("[%H:%M:%S %z] [%^%L%$] [thread %t] %v"); | ||||||
|     spdlog::info("This an info message with custom format"); |     spdlog::info("This an info message with custom format"); | ||||||
|     spdlog::set_pattern("%+"); // back to default format |     spdlog::set_pattern("%+"); // back to default format | ||||||
|  |     spdlog::set_level(spdlog::level::info); | ||||||
|  |  | ||||||
|  |     // Backtrace support | ||||||
|  |     // Loggers can store in a ring buffer all messages (including debug/trace) for later inspection. | ||||||
|  |     // When needed, call dump_backtrace() to see what happened: | ||||||
|  |     spdlog::enable_backtrace(10); // create ring buffer with capacity of 10  messages | ||||||
|  |     for (int i = 0; i < 100; i++) | ||||||
|  |     { | ||||||
|  |         spdlog::debug("Backtrace message {}", i); // not logged.. | ||||||
|  |     } | ||||||
|  |     // e.g. if some error happened: | ||||||
|  |     spdlog::dump_backtrace(); // log them now! | ||||||
|  |  | ||||||
|     try |     try | ||||||
|     { |     { | ||||||
| @@ -50,7 +58,6 @@ int main(int, char *[]) | |||||||
|         basic_example(); |         basic_example(); | ||||||
|         rotating_example(); |         rotating_example(); | ||||||
|         daily_example(); |         daily_example(); | ||||||
|         clone_example(); |  | ||||||
|         async_example(); |         async_example(); | ||||||
|         binary_example(); |         binary_example(); | ||||||
|         multi_sink_example(); |         multi_sink_example(); | ||||||
| @@ -109,14 +116,6 @@ void daily_example() | |||||||
|     auto daily_logger = spdlog::daily_logger_mt("daily_logger", "logs/daily.txt", 2, 30); |     auto daily_logger = spdlog::daily_logger_mt("daily_logger", "logs/daily.txt", 2, 30); | ||||||
| } | } | ||||||
|  |  | ||||||
| // Clone a logger and give it new name. |  | ||||||
| // Useful for creating component/subsystem loggers from some "root" logger. |  | ||||||
| void clone_example() |  | ||||||
| { |  | ||||||
|     auto network_logger = spdlog::default_logger()->clone("network"); |  | ||||||
|     network_logger->info("Logging network stuff.."); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| #include "spdlog/async.h" | #include "spdlog/async.h" | ||||||
| void async_example() | void async_example() | ||||||
| { | { | ||||||
|   | |||||||
							
								
								
									
										106
									
								
								third_party/spdlog/example/example.sln
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										106
									
								
								third_party/spdlog/example/example.sln
									
									
									
									
										vendored
									
									
								
							| @@ -1,106 +0,0 @@ | |||||||
|  |  | ||||||
| Microsoft Visual Studio Solution File, Format Version 12.00 |  | ||||||
| # Visual Studio 15 |  | ||||||
| VisualStudioVersion = 15.0.27703.2018 |  | ||||||
| MinimumVisualStudioVersion = 10.0.40219.1 |  | ||||||
| Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "example", "example.vcxproj", "{9E5AB93A-0CCE-4BAC-9FCB-0FC9CB5EB8D2}" |  | ||||||
| EndProject |  | ||||||
| Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "spdlog", "spdlog", "{7FC6AB76-AD88-4135-888C-0568E81475AF}" |  | ||||||
| 	ProjectSection(SolutionItems) = preProject |  | ||||||
| 		..\include\spdlog\async.h = ..\include\spdlog\async.h |  | ||||||
| 		..\include\spdlog\async_logger.h = ..\include\spdlog\async_logger.h |  | ||||||
| 		..\include\spdlog\common.h = ..\include\spdlog\common.h |  | ||||||
| 		..\include\spdlog\formatter.h = ..\include\spdlog\formatter.h |  | ||||||
| 		..\include\spdlog\logger.h = ..\include\spdlog\logger.h |  | ||||||
| 		..\include\spdlog\spdlog.h = ..\include\spdlog\spdlog.h |  | ||||||
| 		..\include\spdlog\tweakme.h = ..\include\spdlog\tweakme.h |  | ||||||
| 		..\include\spdlog\version.h = ..\include\spdlog\version.h |  | ||||||
| 	EndProjectSection |  | ||||||
| EndProject |  | ||||||
| Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "details", "details", "{08E93803-E650-42D9-BBB4-3C16979F850E}" |  | ||||||
| 	ProjectSection(SolutionItems) = preProject |  | ||||||
| 		..\include\spdlog\details\async_logger_impl.h = ..\include\spdlog\details\async_logger_impl.h |  | ||||||
| 		..\include\spdlog\details\circular_q.h = ..\include\spdlog\details\circular_q.h |  | ||||||
| 		..\include\spdlog\details\console_globals.h = ..\include\spdlog\details\console_globals.h |  | ||||||
| 		..\include\spdlog\details\file_helper.h = ..\include\spdlog\details\file_helper.h |  | ||||||
| 		..\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\logger_impl.h = ..\include\spdlog\details\logger_impl.h |  | ||||||
| 		..\include\spdlog\details\mpmc_blocking_q.h = ..\include\spdlog\details\mpmc_blocking_q.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\details\pattern_formatter.h = ..\include\spdlog\details\pattern_formatter.h |  | ||||||
| 		..\include\spdlog\details\periodic_worker.h = ..\include\spdlog\details\periodic_worker.h |  | ||||||
| 		..\include\spdlog\details\registry.h = ..\include\spdlog\details\registry.h |  | ||||||
| 		..\include\spdlog\details\spdlog_impl.h = ..\include\spdlog\details\spdlog_impl.h |  | ||||||
| 		..\include\spdlog\details\thread_pool.h = ..\include\spdlog\details\thread_pool.h |  | ||||||
| 	EndProjectSection |  | ||||||
| EndProject |  | ||||||
| Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "fmt", "fmt", "{82378DE1-8463-4F91-91A0-C2C40E2AEA2A}" |  | ||||||
| 	ProjectSection(SolutionItems) = preProject |  | ||||||
| 		..\include\spdlog\fmt\fmt.h = ..\include\spdlog\fmt\fmt.h |  | ||||||
| 		..\include\spdlog\fmt\ostr.h = ..\include\spdlog\fmt\ostr.h |  | ||||||
| 	EndProjectSection |  | ||||||
| EndProject |  | ||||||
| Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "bundled", "bundled", "{D9CA4494-80D1-48D1-A897-D3564F7B27FF}" |  | ||||||
| 	ProjectSection(SolutionItems) = preProject |  | ||||||
| 		..\include\spdlog\fmt\bundled\format.cc = ..\include\spdlog\fmt\bundled\format.cc |  | ||||||
| 		..\include\spdlog\fmt\bundled\format.h = ..\include\spdlog\fmt\bundled\format.h |  | ||||||
| 		..\include\spdlog\fmt\bundled\LICENSE.rst = ..\include\spdlog\fmt\bundled\LICENSE.rst |  | ||||||
| 		..\include\spdlog\fmt\bundled\ostream.cc = ..\include\spdlog\fmt\bundled\ostream.cc |  | ||||||
| 		..\include\spdlog\fmt\bundled\ostream.h = ..\include\spdlog\fmt\bundled\ostream.h |  | ||||||
| 		..\include\spdlog\fmt\bundled\posix.cc = ..\include\spdlog\fmt\bundled\posix.cc |  | ||||||
| 		..\include\spdlog\fmt\bundled\posix.h = ..\include\spdlog\fmt\bundled\posix.h |  | ||||||
| 		..\include\spdlog\fmt\bundled\printf.cc = ..\include\spdlog\fmt\bundled\printf.cc |  | ||||||
| 		..\include\spdlog\fmt\bundled\printf.h = ..\include\spdlog\fmt\bundled\printf.h |  | ||||||
| 		..\include\spdlog\fmt\bundled\time.h = ..\include\spdlog\fmt\bundled\time.h |  | ||||||
| 	EndProjectSection |  | ||||||
| EndProject |  | ||||||
| Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "sinks", "sinks", "{27D16BB9-2B81-4F61-80EC-0C7A777248E4}" |  | ||||||
| 	ProjectSection(SolutionItems) = preProject |  | ||||||
| 		..\include\spdlog\sinks\android_sink.h = ..\include\spdlog\sinks\android_sink.h |  | ||||||
| 		..\include\spdlog\sinks\ansicolor_sink.h = ..\include\spdlog\sinks\ansicolor_sink.h |  | ||||||
| 		..\include\spdlog\sinks\base_sink.h = ..\include\spdlog\sinks\base_sink.h |  | ||||||
| 		..\include\spdlog\sinks\dist_sink.h = ..\include\spdlog\sinks\dist_sink.h |  | ||||||
| 		..\include\spdlog\sinks\file_sinks.h = ..\include\spdlog\sinks\file_sinks.h |  | ||||||
| 		..\include\spdlog\sinks\msvc_sink.h = ..\include\spdlog\sinks\msvc_sink.h |  | ||||||
| 		..\include\spdlog\sinks\null_sink.h = ..\include\spdlog\sinks\null_sink.h |  | ||||||
| 		..\include\spdlog\sinks\ostream_sink.h = ..\include\spdlog\sinks\ostream_sink.h |  | ||||||
| 		..\include\spdlog\sinks\sink.h = ..\include\spdlog\sinks\sink.h |  | ||||||
| 		..\include\spdlog\sinks\stdout_color_sinks.h = ..\include\spdlog\sinks\stdout_color_sinks.h |  | ||||||
| 		..\include\spdlog\sinks\stdout_sinks.h = ..\include\spdlog\sinks\stdout_sinks.h |  | ||||||
| 		..\include\spdlog\sinks\syslog_sink.h = ..\include\spdlog\sinks\syslog_sink.h |  | ||||||
| 		..\include\spdlog\sinks\wincolor_sink.h = ..\include\spdlog\sinks\wincolor_sink.h |  | ||||||
| 		..\include\spdlog\sinks\windebug_sink.h = ..\include\spdlog\sinks\windebug_sink.h |  | ||||||
| 	EndProjectSection |  | ||||||
| EndProject |  | ||||||
| Global |  | ||||||
| 	GlobalSection(SolutionConfigurationPlatforms) = preSolution |  | ||||||
| 		Debug|Win32 = Debug|Win32 |  | ||||||
| 		Debug|x64 = Debug|x64 |  | ||||||
| 		Release|Win32 = Release|Win32 |  | ||||||
| 		Release|x64 = Release|x64 |  | ||||||
| 	EndGlobalSection |  | ||||||
| 	GlobalSection(ProjectConfigurationPlatforms) = postSolution |  | ||||||
| 		{9E5AB93A-0CCE-4BAC-9FCB-0FC9CB5EB8D2}.Debug|Win32.ActiveCfg = Debug|Win32 |  | ||||||
| 		{9E5AB93A-0CCE-4BAC-9FCB-0FC9CB5EB8D2}.Debug|Win32.Build.0 = Debug|Win32 |  | ||||||
| 		{9E5AB93A-0CCE-4BAC-9FCB-0FC9CB5EB8D2}.Debug|x64.ActiveCfg = Debug|x64 |  | ||||||
| 		{9E5AB93A-0CCE-4BAC-9FCB-0FC9CB5EB8D2}.Debug|x64.Build.0 = Debug|x64 |  | ||||||
| 		{9E5AB93A-0CCE-4BAC-9FCB-0FC9CB5EB8D2}.Release|Win32.ActiveCfg = Release|Win32 |  | ||||||
| 		{9E5AB93A-0CCE-4BAC-9FCB-0FC9CB5EB8D2}.Release|Win32.Build.0 = Release|Win32 |  | ||||||
| 		{9E5AB93A-0CCE-4BAC-9FCB-0FC9CB5EB8D2}.Release|x64.ActiveCfg = Release|x64 |  | ||||||
| 		{9E5AB93A-0CCE-4BAC-9FCB-0FC9CB5EB8D2}.Release|x64.Build.0 = Release|x64 |  | ||||||
| 	EndGlobalSection |  | ||||||
| 	GlobalSection(SolutionProperties) = preSolution |  | ||||||
| 		HideSolutionNode = FALSE |  | ||||||
| 	EndGlobalSection |  | ||||||
| 	GlobalSection(NestedProjects) = preSolution |  | ||||||
| 		{08E93803-E650-42D9-BBB4-3C16979F850E} = {7FC6AB76-AD88-4135-888C-0568E81475AF} |  | ||||||
| 		{82378DE1-8463-4F91-91A0-C2C40E2AEA2A} = {7FC6AB76-AD88-4135-888C-0568E81475AF} |  | ||||||
| 		{D9CA4494-80D1-48D1-A897-D3564F7B27FF} = {82378DE1-8463-4F91-91A0-C2C40E2AEA2A} |  | ||||||
| 		{27D16BB9-2B81-4F61-80EC-0C7A777248E4} = {7FC6AB76-AD88-4135-888C-0568E81475AF} |  | ||||||
| 	EndGlobalSection |  | ||||||
| 	GlobalSection(ExtensibilityGlobals) = postSolution |  | ||||||
| 		SolutionGuid = {1BF53532-C5DC-4236-B195-9E17CBE40A48} |  | ||||||
| 	EndGlobalSection |  | ||||||
| EndGlobal |  | ||||||
							
								
								
									
										167
									
								
								third_party/spdlog/example/example.vcxproj
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										167
									
								
								third_party/spdlog/example/example.vcxproj
									
									
									
									
										vendored
									
									
								
							| @@ -1,167 +0,0 @@ | |||||||
| <?xml version="1.0" encoding="utf-8"?> |  | ||||||
| <Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> |  | ||||||
|   <ItemGroup Label="ProjectConfigurations"> |  | ||||||
|     <ProjectConfiguration Include="Debug|Win32"> |  | ||||||
|       <Configuration>Debug</Configuration> |  | ||||||
|       <Platform>Win32</Platform> |  | ||||||
|     </ProjectConfiguration> |  | ||||||
|     <ProjectConfiguration Include="Debug|x64"> |  | ||||||
|       <Configuration>Debug</Configuration> |  | ||||||
|       <Platform>x64</Platform> |  | ||||||
|     </ProjectConfiguration> |  | ||||||
|     <ProjectConfiguration Include="Release|Win32"> |  | ||||||
|       <Configuration>Release</Configuration> |  | ||||||
|       <Platform>Win32</Platform> |  | ||||||
|     </ProjectConfiguration> |  | ||||||
|     <ProjectConfiguration Include="Release|x64"> |  | ||||||
|       <Configuration>Release</Configuration> |  | ||||||
|       <Platform>x64</Platform> |  | ||||||
|     </ProjectConfiguration> |  | ||||||
|   </ItemGroup> |  | ||||||
|   <ItemGroup> |  | ||||||
|     <ClCompile Include="example.cpp" /> |  | ||||||
|   </ItemGroup> |  | ||||||
|   <PropertyGroup Label="Globals"> |  | ||||||
|     <ProjectGuid>{9E5AB93A-0CCE-4BAC-9FCB-0FC9CB5EB8D2}</ProjectGuid> |  | ||||||
|     <Keyword>Win32Proj</Keyword> |  | ||||||
|     <RootNamespace>.</RootNamespace> |  | ||||||
|   </PropertyGroup> |  | ||||||
|   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> |  | ||||||
|   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> |  | ||||||
|     <ConfigurationType>Application</ConfigurationType> |  | ||||||
|     <UseDebugLibraries>true</UseDebugLibraries> |  | ||||||
|     <PlatformToolset>v141</PlatformToolset> |  | ||||||
|     <CharacterSet>Unicode</CharacterSet> |  | ||||||
|   </PropertyGroup> |  | ||||||
|   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> |  | ||||||
|     <ConfigurationType>Application</ConfigurationType> |  | ||||||
|     <UseDebugLibraries>true</UseDebugLibraries> |  | ||||||
|     <PlatformToolset>v141</PlatformToolset> |  | ||||||
|     <CharacterSet>Unicode</CharacterSet> |  | ||||||
|   </PropertyGroup> |  | ||||||
|   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> |  | ||||||
|     <ConfigurationType>Application</ConfigurationType> |  | ||||||
|     <UseDebugLibraries>false</UseDebugLibraries> |  | ||||||
|     <PlatformToolset>v141</PlatformToolset> |  | ||||||
|     <WholeProgramOptimization>true</WholeProgramOptimization> |  | ||||||
|     <CharacterSet>Unicode</CharacterSet> |  | ||||||
|   </PropertyGroup> |  | ||||||
|   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> |  | ||||||
|     <ConfigurationType>Application</ConfigurationType> |  | ||||||
|     <UseDebugLibraries>false</UseDebugLibraries> |  | ||||||
|     <PlatformToolset>v141</PlatformToolset> |  | ||||||
|     <WholeProgramOptimization>true</WholeProgramOptimization> |  | ||||||
|     <CharacterSet>Unicode</CharacterSet> |  | ||||||
|   </PropertyGroup> |  | ||||||
|   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> |  | ||||||
|   <ImportGroup Label="ExtensionSettings"> |  | ||||||
|   </ImportGroup> |  | ||||||
|   <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> |  | ||||||
|     <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> |  | ||||||
|   </ImportGroup> |  | ||||||
|   <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets"> |  | ||||||
|     <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> |  | ||||||
|   </ImportGroup> |  | ||||||
|   <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> |  | ||||||
|     <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> |  | ||||||
|   </ImportGroup> |  | ||||||
|   <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets"> |  | ||||||
|     <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> |  | ||||||
|   </ImportGroup> |  | ||||||
|   <PropertyGroup Label="UserMacros" /> |  | ||||||
|   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> |  | ||||||
|     <LinkIncremental>true</LinkIncremental> |  | ||||||
|   </PropertyGroup> |  | ||||||
|   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> |  | ||||||
|     <LinkIncremental>true</LinkIncremental> |  | ||||||
|   </PropertyGroup> |  | ||||||
|   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> |  | ||||||
|     <LinkIncremental>false</LinkIncremental> |  | ||||||
|   </PropertyGroup> |  | ||||||
|   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> |  | ||||||
|     <LinkIncremental>false</LinkIncremental> |  | ||||||
|   </PropertyGroup> |  | ||||||
|   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> |  | ||||||
|     <ClCompile> |  | ||||||
|       <PrecompiledHeader> |  | ||||||
|       </PrecompiledHeader> |  | ||||||
|       <WarningLevel>Level3</WarningLevel> |  | ||||||
|       <Optimization>Disabled</Optimization> |  | ||||||
|       <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions> |  | ||||||
|       <AdditionalIncludeDirectories>..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> |  | ||||||
|       <PrecompiledHeaderFile /> |  | ||||||
|       <PrecompiledHeaderOutputFile /> |  | ||||||
|     </ClCompile> |  | ||||||
|     <Link> |  | ||||||
|       <SubSystem>Console</SubSystem> |  | ||||||
|       <GenerateDebugInformation>true</GenerateDebugInformation> |  | ||||||
|     </Link> |  | ||||||
|   </ItemDefinitionGroup> |  | ||||||
|   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> |  | ||||||
|     <ClCompile> |  | ||||||
|       <PrecompiledHeader> |  | ||||||
|       </PrecompiledHeader> |  | ||||||
|       <WarningLevel>Level3</WarningLevel> |  | ||||||
|       <Optimization>Disabled</Optimization> |  | ||||||
|       <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions> |  | ||||||
|       <AdditionalIncludeDirectories>..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> |  | ||||||
|       <PrecompiledHeaderFile> |  | ||||||
|       </PrecompiledHeaderFile> |  | ||||||
|       <PrecompiledHeaderOutputFile> |  | ||||||
|       </PrecompiledHeaderOutputFile> |  | ||||||
|     </ClCompile> |  | ||||||
|     <Link> |  | ||||||
|       <SubSystem>Console</SubSystem> |  | ||||||
|       <GenerateDebugInformation>true</GenerateDebugInformation> |  | ||||||
|     </Link> |  | ||||||
|   </ItemDefinitionGroup> |  | ||||||
|   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> |  | ||||||
|     <ClCompile> |  | ||||||
|       <WarningLevel>Level3</WarningLevel> |  | ||||||
|       <PrecompiledHeader> |  | ||||||
|       </PrecompiledHeader> |  | ||||||
|       <Optimization>MaxSpeed</Optimization> |  | ||||||
|       <FunctionLevelLinking>true</FunctionLevelLinking> |  | ||||||
|       <IntrinsicFunctions>true</IntrinsicFunctions> |  | ||||||
|       <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions> |  | ||||||
|       <AdditionalIncludeDirectories>..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> |  | ||||||
|       <PrecompiledHeaderFile /> |  | ||||||
|       <PrecompiledHeaderOutputFile /> |  | ||||||
|     </ClCompile> |  | ||||||
|     <Link> |  | ||||||
|       <SubSystem>Console</SubSystem> |  | ||||||
|       <GenerateDebugInformation>true</GenerateDebugInformation> |  | ||||||
|       <EnableCOMDATFolding>true</EnableCOMDATFolding> |  | ||||||
|       <OptimizeReferences>true</OptimizeReferences> |  | ||||||
|       <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> |  | ||||||
|       <AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies> |  | ||||||
|     </Link> |  | ||||||
|   </ItemDefinitionGroup> |  | ||||||
|   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> |  | ||||||
|     <ClCompile> |  | ||||||
|       <WarningLevel>Level3</WarningLevel> |  | ||||||
|       <PrecompiledHeader> |  | ||||||
|       </PrecompiledHeader> |  | ||||||
|       <Optimization>MaxSpeed</Optimization> |  | ||||||
|       <FunctionLevelLinking>true</FunctionLevelLinking> |  | ||||||
|       <IntrinsicFunctions>true</IntrinsicFunctions> |  | ||||||
|       <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions> |  | ||||||
|       <AdditionalIncludeDirectories>..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> |  | ||||||
|       <PrecompiledHeaderFile> |  | ||||||
|       </PrecompiledHeaderFile> |  | ||||||
|       <PrecompiledHeaderOutputFile> |  | ||||||
|       </PrecompiledHeaderOutputFile> |  | ||||||
|     </ClCompile> |  | ||||||
|     <Link> |  | ||||||
|       <SubSystem>Console</SubSystem> |  | ||||||
|       <GenerateDebugInformation>true</GenerateDebugInformation> |  | ||||||
|       <EnableCOMDATFolding>true</EnableCOMDATFolding> |  | ||||||
|       <OptimizeReferences>true</OptimizeReferences> |  | ||||||
|       <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> |  | ||||||
|       <AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies> |  | ||||||
|     </Link> |  | ||||||
|   </ItemDefinitionGroup> |  | ||||||
|   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> |  | ||||||
|   <ImportGroup Label="ExtensionTargets"> |  | ||||||
|   </ImportGroup> |  | ||||||
| </Project> |  | ||||||
							
								
								
									
										15
									
								
								third_party/spdlog/example/jni/Android.mk
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										15
									
								
								third_party/spdlog/example/jni/Android.mk
									
									
									
									
										vendored
									
									
								
							| @@ -1,15 +0,0 @@ | |||||||
| # Setup a project |  | ||||||
| LOCAL_PATH := $(call my-dir) |  | ||||||
| include $(CLEAR_VARS) |  | ||||||
|  |  | ||||||
| LOCAL_MODULE := example |  | ||||||
| LOCAL_SRC_FILES := example.cpp |  | ||||||
| LOCAL_CPPFLAGS += -Wall -Wshadow -Wextra -pedantic -std=c++11 -fPIE -pie |  | ||||||
| LOCAL_LDFLAGS +=  -fPIE -pie |  | ||||||
|  |  | ||||||
| # Add exception support and set path for spdlog's headers |  | ||||||
| LOCAL_CPPFLAGS += -fexceptions -I../include |  | ||||||
| # Use android's log library |  | ||||||
| LOCAL_LDFLAGS += -llog |  | ||||||
|  |  | ||||||
| include $(BUILD_EXECUTABLE) |  | ||||||
| @@ -1,2 +0,0 @@ | |||||||
| # Exceptions are used in spdlog. Link to an exception-ready C++ runtime. |  | ||||||
| APP_STL = gnustl_static |  | ||||||
							
								
								
									
										157
									
								
								third_party/spdlog/example/jni/example.cpp
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										157
									
								
								third_party/spdlog/example/jni/example.cpp
									
									
									
									
										vendored
									
									
								
							| @@ -1,157 +0,0 @@ | |||||||
| // |  | ||||||
| // Copyright(c) 2015 Gabi Melman. |  | ||||||
| // Distributed under the MIT License (http://opensource.org/licenses/MIT) |  | ||||||
| // |  | ||||||
| // |  | ||||||
| // spdlog usage example |  | ||||||
| // |  | ||||||
| // |  | ||||||
|  |  | ||||||
| #define SPDLOG_TRACE_ON |  | ||||||
| #define SPDLOG_DEBUG_ON |  | ||||||
|  |  | ||||||
| #include "spdlog/spdlog.h" |  | ||||||
|  |  | ||||||
| #include <iostream> |  | ||||||
| #include <memory> |  | ||||||
|  |  | ||||||
| void async_example(); |  | ||||||
| void syslog_example(); |  | ||||||
| void android_example(); |  | ||||||
| void user_defined_example(); |  | ||||||
| void err_handler_example(); |  | ||||||
|  |  | ||||||
| namespace spd = spdlog; |  | ||||||
| int main(int, char *[]) |  | ||||||
| { |  | ||||||
|     try |  | ||||||
|     { |  | ||||||
|         // Console logger with color |  | ||||||
|         auto console = spd::stdout_color_mt("console"); |  | ||||||
|         console->info("Welcome to spdlog!"); |  | ||||||
|         console->error("Some error message with arg{}..", 1); |  | ||||||
|  |  | ||||||
|         // Formatting examples |  | ||||||
|         console->warn("Easy padding in numbers like {:08d}", 12); |  | ||||||
|         console->critical("Support for int: {0:d};  hex: {0:x};  oct: {0:o}; bin: {0:b}", 42); |  | ||||||
|         console->info("Support for floats {:03.2f}", 1.23456); |  | ||||||
|         console->info("Positional args are {1} {0}..", "too", "supported"); |  | ||||||
|         console->info("{:<30}", "left aligned"); |  | ||||||
|  |  | ||||||
|         spd::get("console")->info("loggers can be retrieved from a global registry using the spdlog::get(logger_name) function"); |  | ||||||
|  |  | ||||||
|         // Create basic file logger (not rotated) |  | ||||||
|         auto my_logger = spd::basic_logger_mt("basic_logger", "logs/basic-log.txt"); |  | ||||||
|         my_logger->info("Some log message"); |  | ||||||
|  |  | ||||||
|         // Create a file rotating logger with 5mb size max and 3 rotated files |  | ||||||
|         auto rotating_logger = spd::rotating_logger_mt("some_logger_name", "logs/rotating.txt", 1048576 * 5, 3); |  | ||||||
|         for (int i = 0; i < 10; ++i) |  | ||||||
|             rotating_logger->info("{} * {} equals {:>10}", i, i, i * i); |  | ||||||
|  |  | ||||||
|         // Create a daily logger - a new file is created every day on 2:30am |  | ||||||
|         auto daily_logger = spd::daily_logger_mt("daily_logger", "logs/daily.txt", 2, 30); |  | ||||||
|         // trigger flush if the log severity is error or higher |  | ||||||
|         daily_logger->flush_on(spd::level::err); |  | ||||||
|         daily_logger->info(123.44); |  | ||||||
|  |  | ||||||
|         // Customize msg format for all messages |  | ||||||
|         spd::set_pattern("*** [%H:%M:%S %z] [thread %t] %v ***"); |  | ||||||
|         rotating_logger->info("This is another message with custom format"); |  | ||||||
|  |  | ||||||
|         // Runtime log levels |  | ||||||
|         spd::set_level(spd::level::info); // Set global log level to info |  | ||||||
|         console->debug("This message should not be displayed!"); |  | ||||||
|         console->set_level(spd::level::debug); // Set specific logger's log level |  | ||||||
|         console->debug("This message should be displayed.."); |  | ||||||
|  |  | ||||||
|         // Compile time log levels |  | ||||||
|         // define SPDLOG_DEBUG_ON or SPDLOG_TRACE_ON |  | ||||||
|         SPDLOG_TRACE(console, "Enabled only #ifdef SPDLOG_TRACE_ON..{} ,{}", 1, 3.23); |  | ||||||
|         SPDLOG_DEBUG(console, "Enabled only #ifdef SPDLOG_DEBUG_ON.. {} ,{}", 1, 3.23); |  | ||||||
|  |  | ||||||
|         // Asynchronous logging is very fast.. |  | ||||||
|         // Just call spdlog::set_async_mode(q_size) and all created loggers from now on will be asynchronous.. |  | ||||||
|         async_example(); |  | ||||||
|  |  | ||||||
|         // syslog example. linux/osx only |  | ||||||
|         syslog_example(); |  | ||||||
|  |  | ||||||
|         // android example. compile with NDK |  | ||||||
|         android_example(); |  | ||||||
|  |  | ||||||
|         // Log user-defined types example |  | ||||||
|         user_defined_example(); |  | ||||||
|  |  | ||||||
|         // Change default log error handler |  | ||||||
|         err_handler_example(); |  | ||||||
|  |  | ||||||
|         // Apply a function on all registered loggers |  | ||||||
|         spd::apply_all([&](std::shared_ptr<spdlog::logger> l) { l->info("End of example."); }); |  | ||||||
|  |  | ||||||
|         // Release and close all loggers |  | ||||||
|         spdlog::drop_all(); |  | ||||||
|     } |  | ||||||
|     // Exceptions will only be thrown upon failed logger or sink construction (not during logging) |  | ||||||
|     catch (const spd::spdlog_ex &ex) |  | ||||||
|     { |  | ||||||
|         std::cout << "Log init failed: " << ex.what() << std::endl; |  | ||||||
|         return 1; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void async_example() |  | ||||||
| { |  | ||||||
|     size_t q_size = 4096; // queue size must be power of 2 |  | ||||||
|     spdlog::set_async_mode(q_size); |  | ||||||
|     auto async_file = spd::daily_logger_st("async_file_logger", "logs/async_log.txt"); |  | ||||||
|     for (int i = 0; i < 100; ++i) |  | ||||||
|         async_file->info("Async message #{}", i); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // syslog example (linux/osx/freebsd) |  | ||||||
| void syslog_example() |  | ||||||
| { |  | ||||||
| #ifdef SPDLOG_ENABLE_SYSLOG |  | ||||||
|     std::string ident = "spdlog-example"; |  | ||||||
|     auto syslog_logger = spd::syslog_logger("syslog", ident, LOG_PID); |  | ||||||
|     syslog_logger->warn("This is warning that will end up in syslog."); |  | ||||||
| #endif |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Android example |  | ||||||
| void android_example() |  | ||||||
| { |  | ||||||
| #if defined(__ANDROID__) |  | ||||||
|     std::string tag = "spdlog-android"; |  | ||||||
|     auto android_logger = spd::android_logger("android", tag); |  | ||||||
|     android_logger->critical("Use \"adb shell logcat\" to view this message."); |  | ||||||
| #endif |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // user defined types logging by implementing operator<< |  | ||||||
| struct my_type |  | ||||||
| { |  | ||||||
|     int i; |  | ||||||
|     template<typename OStream> |  | ||||||
|     friend OStream &operator<<(OStream &os, const my_type &c) |  | ||||||
|     { |  | ||||||
|         return os << "[my_type i=" << c.i << "]"; |  | ||||||
|     } |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| #include "spdlog/fmt/ostr.h" // must be included |  | ||||||
| void user_defined_example() |  | ||||||
| { |  | ||||||
|     spd::get("console")->info("user defined type: {}", my_type{14}); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // |  | ||||||
| // custom error handler |  | ||||||
| // |  | ||||||
| void err_handler_example() |  | ||||||
| { |  | ||||||
|     // can be set globaly or per logger(logger->set_error_handler(..)) |  | ||||||
|     spdlog::set_error_handler([](const std::string &msg) { std::cerr << "my err handler: " << msg << std::endl; }); |  | ||||||
|     spd::get("console")->info("some invalid message to trigger an error {}{}{}{}", 3); |  | ||||||
| } |  | ||||||
							
								
								
									
										5
									
								
								third_party/spdlog/example/meson.build
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								third_party/spdlog/example/meson.build
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | |||||||
|  | executable('example', 'example.cpp', dependencies: spdlog_dep) | ||||||
|  | executable('example_header_only', 'example.cpp', dependencies: spdlog_headeronly_dep) | ||||||
|  | run_command(find_program('mkdir'), meson.current_build_dir() + '/logs') | ||||||
|  |  | ||||||
|  |  | ||||||
							
								
								
									
										47
									
								
								third_party/spdlog/example/multisink.cpp
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										47
									
								
								third_party/spdlog/example/multisink.cpp
									
									
									
									
										vendored
									
									
								
							| @@ -1,47 +0,0 @@ | |||||||
| #include "spdlog/spdlog.h" |  | ||||||
| #include "spdlog/sinks/basic_file_sink.h" |  | ||||||
| #include "spdlog/sinks/stdout_sinks.h" |  | ||||||
|  |  | ||||||
| #include <iostream> |  | ||||||
| #include <memory> |  | ||||||
|  |  | ||||||
| int main(int, char *[]) |  | ||||||
| { |  | ||||||
|     bool enable_debug = true; |  | ||||||
|     try |  | ||||||
|     { |  | ||||||
|         // This other example use a single logger with multiple sinks. |  | ||||||
|         // This means that the same log_msg is forwarded to multiple sinks; |  | ||||||
|         // Each sink can have it's own log level and a message will be logged. |  | ||||||
|         std::vector<spdlog::sink_ptr> sinks; |  | ||||||
|         sinks.push_back(std::make_shared<spdlog::sinks::stdout_sink_mt>()); |  | ||||||
|         sinks.push_back(std::make_shared<spdlog::sinks::basic_file_sink_mt>("./log_regular_file.txt")); |  | ||||||
|         sinks.push_back(std::make_shared<spdlog::sinks::basic_file_sink_mt>("./log_debug_file.txt")); |  | ||||||
|  |  | ||||||
|         spdlog::logger console_multisink("multisink", sinks.begin(), sinks.end()); |  | ||||||
|         console_multisink.set_level(spdlog::level::warn); |  | ||||||
|  |  | ||||||
|         sinks[0]->set_level(spdlog::level::trace); // console. Allow everything.  Default value |  | ||||||
|         sinks[1]->set_level(spdlog::level::trace); //  regular file. Allow everything.  Default value |  | ||||||
|         sinks[2]->set_level(spdlog::level::off);   //  regular file. Ignore everything. |  | ||||||
|  |  | ||||||
|         console_multisink.warn("warn: will print only on console and regular file"); |  | ||||||
|  |  | ||||||
|         if (enable_debug) |  | ||||||
|         { |  | ||||||
|             console_multisink.set_level(spdlog::level::debug); // level of the logger |  | ||||||
|             sinks[1]->set_level(spdlog::level::debug);         // regular file |  | ||||||
|             sinks[2]->set_level(spdlog::level::debug);         // debug file |  | ||||||
|         } |  | ||||||
|         console_multisink.debug("Debug: you should see this on console and both files"); |  | ||||||
|  |  | ||||||
|         // Release and close all loggers |  | ||||||
|         spdlog::drop_all(); |  | ||||||
|     } |  | ||||||
|     // Exceptions will only be thrown upon failed logger or sink construction (not during logging) |  | ||||||
|     catch (const spdlog::spdlog_ex &ex) |  | ||||||
|     { |  | ||||||
|         std::cout << "Log init failed: " << ex.what() << std::endl; |  | ||||||
|         return 1; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
							
								
								
									
										34
									
								
								third_party/spdlog/example/utils.h
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										34
									
								
								third_party/spdlog/example/utils.h
									
									
									
									
										vendored
									
									
								
							| @@ -1,34 +0,0 @@ | |||||||
| // |  | ||||||
| // Copyright(c) 2015 Gabi Melman. |  | ||||||
| // Distributed under the MIT License (http://opensource.org/licenses/MIT) |  | ||||||
| // |  | ||||||
|  |  | ||||||
| #pragma once |  | ||||||
|  |  | ||||||
| #include <iomanip> |  | ||||||
| #include <locale> |  | ||||||
| #include <sstream> |  | ||||||
|  |  | ||||||
| namespace utils { |  | ||||||
|  |  | ||||||
| template<typename T> |  | ||||||
| inline std::string format(const T &value) |  | ||||||
| { |  | ||||||
|     static std::locale loc(""); |  | ||||||
|     std::stringstream ss; |  | ||||||
|     ss.imbue(loc); |  | ||||||
|     ss << value; |  | ||||||
|     return ss.str(); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| template<> |  | ||||||
| inline std::string format(const double &value) |  | ||||||
| { |  | ||||||
|     static std::locale loc(""); |  | ||||||
|     std::stringstream ss; |  | ||||||
|     ss.imbue(loc); |  | ||||||
|     ss << std::fixed << std::setprecision(1) << value; |  | ||||||
|     return ss.str(); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| } // namespace utils |  | ||||||
							
								
								
									
										9
									
								
								third_party/spdlog/format.sh
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										9
									
								
								third_party/spdlog/format.sh
									
									
									
									
										vendored
									
									
								
							| @@ -1,9 +0,0 @@ | |||||||
| #!/bin/bash |  | ||||||
| echo -n "Running dos2unix     " |  | ||||||
| find . -name "*\.h" -o -name "*\.cpp"|grep -v bundled|xargs -I {} sh -c "dos2unix '{}' 2>/dev/null; echo -n '.'" |  | ||||||
| echo |  | ||||||
| echo -n "Running clang-format " |  | ||||||
| find . -name "*\.h" -o -name "*\.cpp"|grep -v bundled|xargs -I {} sh -c "clang-format -i {}; echo -n '.'" |  | ||||||
| echo |  | ||||||
|  |  | ||||||
|  |  | ||||||
							
								
								
									
										20
									
								
								third_party/spdlog/include/spdlog/async.h
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										20
									
								
								third_party/spdlog/include/spdlog/async.h
									
									
									
									
										vendored
									
									
								
							| @@ -1,8 +1,5 @@ | |||||||
|  | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. | ||||||
| // |  | ||||||
| // Copyright(c) 2018 Gabi Melman. |  | ||||||
| // Distributed under the MIT License (http://opensource.org/licenses/MIT) | // Distributed under the MIT License (http://opensource.org/licenses/MIT) | ||||||
| // |  | ||||||
|  |  | ||||||
| #pragma once | #pragma once | ||||||
|  |  | ||||||
| @@ -23,6 +20,7 @@ | |||||||
|  |  | ||||||
| #include <memory> | #include <memory> | ||||||
| #include <mutex> | #include <mutex> | ||||||
|  | #include <functional> | ||||||
|  |  | ||||||
| namespace spdlog { | namespace spdlog { | ||||||
|  |  | ||||||
| @@ -42,7 +40,9 @@ struct async_factory_impl | |||||||
|         auto ®istry_inst = details::registry::instance(); |         auto ®istry_inst = details::registry::instance(); | ||||||
|  |  | ||||||
|         // create global thread pool if not already exists.. |         // create global thread pool if not already exists.. | ||||||
|         std::lock_guard<std::recursive_mutex> tp_lock(registry_inst.tp_mutex()); |  | ||||||
|  |         auto &mutex = registry_inst.tp_mutex(); | ||||||
|  |         std::lock_guard<std::recursive_mutex> tp_lock(mutex); | ||||||
|         auto tp = registry_inst.get_tp(); |         auto tp = registry_inst.get_tp(); | ||||||
|         if (tp == nullptr) |         if (tp == nullptr) | ||||||
|         { |         { | ||||||
| @@ -72,11 +72,17 @@ inline std::shared_ptr<spdlog::logger> create_async_nb(std::string logger_name, | |||||||
|     return async_factory_nonblock::create<Sink>(std::move(logger_name), std::forward<SinkArgs>(sink_args)...); |     return async_factory_nonblock::create<Sink>(std::move(logger_name), std::forward<SinkArgs>(sink_args)...); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | // set global thread pool. | ||||||
|  | inline void init_thread_pool(size_t q_size, size_t thread_count, std::function<void()> on_thread_start) | ||||||
|  | { | ||||||
|  |     auto tp = std::make_shared<details::thread_pool>(q_size, thread_count, on_thread_start); | ||||||
|  |     details::registry::instance().set_tp(std::move(tp)); | ||||||
|  | } | ||||||
|  |  | ||||||
| // set global thread pool. | // set global thread pool. | ||||||
| inline void init_thread_pool(size_t q_size, size_t thread_count) | inline void init_thread_pool(size_t q_size, size_t thread_count) | ||||||
| { | { | ||||||
|     auto tp = std::make_shared<details::thread_pool>(q_size, thread_count); |     init_thread_pool(q_size, thread_count, [] {}); | ||||||
|     details::registry::instance().set_tp(std::move(tp)); |  | ||||||
| } | } | ||||||
|  |  | ||||||
| // get the global thread pool. | // get the global thread pool. | ||||||
|   | |||||||
							
								
								
									
										92
									
								
								third_party/spdlog/include/spdlog/async_logger-inl.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										92
									
								
								third_party/spdlog/include/spdlog/async_logger-inl.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,92 @@ | |||||||
|  | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. | ||||||
|  | // Distributed under the MIT License (http://opensource.org/licenses/MIT) | ||||||
|  |  | ||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #ifndef SPDLOG_HEADER_ONLY | ||||||
|  | #include "spdlog/async_logger.h" | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #include "spdlog/sinks/sink.h" | ||||||
|  | #include "spdlog/details/thread_pool.h" | ||||||
|  |  | ||||||
|  | #include <memory> | ||||||
|  | #include <string> | ||||||
|  |  | ||||||
|  | SPDLOG_INLINE spdlog::async_logger::async_logger( | ||||||
|  |     std::string logger_name, sinks_init_list sinks_list, std::weak_ptr<details::thread_pool> tp, async_overflow_policy overflow_policy) | ||||||
|  |     : async_logger(std::move(logger_name), sinks_list.begin(), sinks_list.end(), std::move(tp), overflow_policy) | ||||||
|  | {} | ||||||
|  |  | ||||||
|  | SPDLOG_INLINE spdlog::async_logger::async_logger( | ||||||
|  |     std::string logger_name, sink_ptr single_sink, std::weak_ptr<details::thread_pool> tp, async_overflow_policy overflow_policy) | ||||||
|  |     : async_logger(std::move(logger_name), {std::move(single_sink)}, std::move(tp), overflow_policy) | ||||||
|  | {} | ||||||
|  |  | ||||||
|  | // send the log message to the thread pool | ||||||
|  | SPDLOG_INLINE void spdlog::async_logger::sink_it_(const details::log_msg &msg) | ||||||
|  | { | ||||||
|  |     if (auto pool_ptr = thread_pool_.lock()) | ||||||
|  |     { | ||||||
|  |         pool_ptr->post_log(shared_from_this(), msg, overflow_policy_); | ||||||
|  |     } | ||||||
|  |     else | ||||||
|  |     { | ||||||
|  |         SPDLOG_THROW(spdlog_ex("async log: thread pool doesn't exist anymore")); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // send flush request to the thread pool | ||||||
|  | SPDLOG_INLINE void spdlog::async_logger::flush_() | ||||||
|  | { | ||||||
|  |     if (auto pool_ptr = thread_pool_.lock()) | ||||||
|  |     { | ||||||
|  |         pool_ptr->post_flush(shared_from_this(), overflow_policy_); | ||||||
|  |     } | ||||||
|  |     else | ||||||
|  |     { | ||||||
|  |         SPDLOG_THROW(spdlog_ex("async flush: thread pool doesn't exist anymore")); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // | ||||||
|  | // backend functions - called from the thread pool to do the actual job | ||||||
|  | // | ||||||
|  | SPDLOG_INLINE void spdlog::async_logger::backend_sink_it_(const details::log_msg &msg) | ||||||
|  | { | ||||||
|  |     for (auto &sink : sinks_) | ||||||
|  |     { | ||||||
|  |         if (sink->should_log(msg.level)) | ||||||
|  |         { | ||||||
|  |             SPDLOG_TRY | ||||||
|  |             { | ||||||
|  |                 sink->log(msg); | ||||||
|  |             } | ||||||
|  |             SPDLOG_LOGGER_CATCH() | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (should_flush_(msg)) | ||||||
|  |     { | ||||||
|  |         backend_flush_(); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | SPDLOG_INLINE void spdlog::async_logger::backend_flush_() | ||||||
|  | { | ||||||
|  |     for (auto &sink : sinks_) | ||||||
|  |     { | ||||||
|  |         SPDLOG_TRY | ||||||
|  |         { | ||||||
|  |             sink->flush(); | ||||||
|  |         } | ||||||
|  |         SPDLOG_LOGGER_CATCH() | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | SPDLOG_INLINE std::shared_ptr<spdlog::logger> spdlog::async_logger::clone(std::string new_name) | ||||||
|  | { | ||||||
|  |     auto cloned = std::make_shared<spdlog::async_logger>(*this); | ||||||
|  |     cloned->name_ = std::move(new_name); | ||||||
|  |     return cloned; | ||||||
|  | } | ||||||
							
								
								
									
										31
									
								
								third_party/spdlog/include/spdlog/async_logger.h
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										31
									
								
								third_party/spdlog/include/spdlog/async_logger.h
									
									
									
									
										vendored
									
									
								
							| @@ -1,31 +1,21 @@ | |||||||
| // | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. | ||||||
| // Copyright(c) 2015 Gabi Melman. |  | ||||||
| // Distributed under the MIT License (http://opensource.org/licenses/MIT) | // Distributed under the MIT License (http://opensource.org/licenses/MIT) | ||||||
| // |  | ||||||
|  |  | ||||||
| #pragma once | #pragma once | ||||||
|  |  | ||||||
| // Very fast asynchronous logger (millions of logs per second on an average | // Fast asynchronous logger. | ||||||
| // desktop) | // Uses pre allocated queue. | ||||||
| // Uses pre allocated lockfree queue for maximum throughput even under large |  | ||||||
| // number of threads. |  | ||||||
| // Creates a single back thread to pop messages from the queue and log them. | // Creates a single back thread to pop messages from the queue and log them. | ||||||
| // | // | ||||||
| // Upon each log write the logger: | // Upon each log write the logger: | ||||||
| //    1. Checks if its log level is enough to log the message | //    1. Checks if its log level is enough to log the message | ||||||
| //    2. Push a new copy of the message to a queue (or block the caller until | //    2. Push a new copy of the message to a queue (or block the caller until | ||||||
| //    space is available in the queue) | //    space is available in the queue) | ||||||
| //    3. will throw spdlog_ex upon log exceptions |  | ||||||
| // Upon destruction, logs all remaining messages in the queue before | // Upon destruction, logs all remaining messages in the queue before | ||||||
| // destructing.. | // destructing.. | ||||||
|  |  | ||||||
| #include "spdlog/common.h" |  | ||||||
| #include "spdlog/logger.h" | #include "spdlog/logger.h" | ||||||
|  |  | ||||||
| #include <chrono> |  | ||||||
| #include <memory> |  | ||||||
| #include <string> |  | ||||||
|  |  | ||||||
| namespace spdlog { | namespace spdlog { | ||||||
|  |  | ||||||
| // Async overflow policy - block by default. | // Async overflow policy - block by default. | ||||||
| @@ -47,7 +37,11 @@ class async_logger final : public std::enable_shared_from_this<async_logger>, pu | |||||||
| public: | public: | ||||||
|     template<typename It> |     template<typename It> | ||||||
|     async_logger(std::string logger_name, It begin, It end, std::weak_ptr<details::thread_pool> tp, |     async_logger(std::string logger_name, It begin, It end, std::weak_ptr<details::thread_pool> tp, | ||||||
|         async_overflow_policy overflow_policy = async_overflow_policy::block); |         async_overflow_policy overflow_policy = async_overflow_policy::block) | ||||||
|  |         : logger(std::move(logger_name), begin, end) | ||||||
|  |         , thread_pool_(std::move(tp)) | ||||||
|  |         , overflow_policy_(overflow_policy) | ||||||
|  |     {} | ||||||
|  |  | ||||||
|     async_logger(std::string logger_name, sinks_init_list sinks_list, std::weak_ptr<details::thread_pool> tp, |     async_logger(std::string logger_name, sinks_init_list sinks_list, std::weak_ptr<details::thread_pool> tp, | ||||||
|         async_overflow_policy overflow_policy = async_overflow_policy::block); |         async_overflow_policy overflow_policy = async_overflow_policy::block); | ||||||
| @@ -58,10 +52,9 @@ public: | |||||||
|     std::shared_ptr<logger> clone(std::string new_name) override; |     std::shared_ptr<logger> clone(std::string new_name) override; | ||||||
|  |  | ||||||
| protected: | protected: | ||||||
|     void sink_it_(details::log_msg &msg) override; |     void sink_it_(const details::log_msg &msg) override; | ||||||
|     void flush_() override; |     void flush_() override; | ||||||
|  |     void backend_sink_it_(const details::log_msg &incoming_log_msg); | ||||||
|     void backend_log_(const details::log_msg &incoming_log_msg); |  | ||||||
|     void backend_flush_(); |     void backend_flush_(); | ||||||
|  |  | ||||||
| private: | private: | ||||||
| @@ -70,4 +63,6 @@ private: | |||||||
| }; | }; | ||||||
| } // namespace spdlog | } // namespace spdlog | ||||||
|  |  | ||||||
| #include "details/async_logger_impl.h" | #ifdef SPDLOG_HEADER_ONLY | ||||||
|  | #include "async_logger-inl.h" | ||||||
|  | #endif | ||||||
|   | |||||||
							
								
								
									
										57
									
								
								third_party/spdlog/include/spdlog/common-inl.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								third_party/spdlog/include/spdlog/common-inl.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,57 @@ | |||||||
|  | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. | ||||||
|  | // Distributed under the MIT License (http://opensource.org/licenses/MIT) | ||||||
|  |  | ||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #ifndef SPDLOG_HEADER_ONLY | ||||||
|  | #include "spdlog/common.h" | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | namespace spdlog { | ||||||
|  | namespace level { | ||||||
|  | static string_view_t level_string_views[] SPDLOG_LEVEL_NAMES; | ||||||
|  |  | ||||||
|  | static const char *short_level_names[] SPDLOG_SHORT_LEVEL_NAMES; | ||||||
|  |  | ||||||
|  | SPDLOG_INLINE string_view_t &to_string_view(spdlog::level::level_enum l) SPDLOG_NOEXCEPT | ||||||
|  | { | ||||||
|  |     return level_string_views[l]; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | SPDLOG_INLINE const char *to_short_c_str(spdlog::level::level_enum l) SPDLOG_NOEXCEPT | ||||||
|  | { | ||||||
|  |     return short_level_names[l]; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | SPDLOG_INLINE spdlog::level::level_enum from_str(const std::string &name) SPDLOG_NOEXCEPT | ||||||
|  | { | ||||||
|  |     int level = 0; | ||||||
|  |     for (const auto &level_str : level_string_views) | ||||||
|  |     { | ||||||
|  |         if (level_str == name) | ||||||
|  |         { | ||||||
|  |             return static_cast<level::level_enum>(level); | ||||||
|  |         } | ||||||
|  |         level++; | ||||||
|  |     } | ||||||
|  |     return level::off; | ||||||
|  | } | ||||||
|  | } // namespace level | ||||||
|  |  | ||||||
|  | SPDLOG_INLINE spdlog_ex::spdlog_ex(std::string msg) | ||||||
|  |     : msg_(std::move(msg)) | ||||||
|  | {} | ||||||
|  |  | ||||||
|  | SPDLOG_INLINE spdlog_ex::spdlog_ex(const std::string &msg, int last_errno) | ||||||
|  | { | ||||||
|  |     memory_buf_t outbuf; | ||||||
|  |     fmt::format_system_error(outbuf, last_errno, msg); | ||||||
|  |     msg_ = fmt::to_string(outbuf); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | SPDLOG_INLINE const char *spdlog_ex::what() const SPDLOG_NOEXCEPT | ||||||
|  | { | ||||||
|  |     return msg_.c_str(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | } // namespace spdlog | ||||||
							
								
								
									
										192
									
								
								third_party/spdlog/include/spdlog/common.h
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										192
									
								
								third_party/spdlog/include/spdlog/common.h
									
									
									
									
										vendored
									
									
								
							| @@ -1,35 +1,45 @@ | |||||||
| // | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. | ||||||
| // Copyright(c) 2015 Gabi Melman. |  | ||||||
| // Distributed under the MIT License (http://opensource.org/licenses/MIT) | // Distributed under the MIT License (http://opensource.org/licenses/MIT) | ||||||
| // |  | ||||||
|  |  | ||||||
| #pragma once | #pragma once | ||||||
|  |  | ||||||
| #include "spdlog/tweakme.h" | #include "spdlog/tweakme.h" | ||||||
|  | #include "spdlog/details/null_mutex.h" | ||||||
|  |  | ||||||
| #include <atomic> | #include <atomic> | ||||||
| #include <chrono> | #include <chrono> | ||||||
| #include <functional> |  | ||||||
| #include <initializer_list> | #include <initializer_list> | ||||||
| #include <memory> | #include <memory> | ||||||
| #include <stdexcept> | #include <exception> | ||||||
| #include <string> | #include <string> | ||||||
| #include <cstring> |  | ||||||
| #include <type_traits> | #include <type_traits> | ||||||
| #include <unordered_map> | #include <functional> | ||||||
|  |  | ||||||
| #if defined(SPDLOG_WCHAR_FILENAMES) || defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) | #ifdef _WIN32 | ||||||
| #include <codecvt> | #ifndef NOMINMAX | ||||||
| #include <locale> | #define NOMINMAX // prevent windows redefining min/max | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| #include "spdlog/details/null_mutex.h" | #ifndef WIN32_LEAN_AND_MEAN | ||||||
|  | #define WIN32_LEAN_AND_MEAN | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #include <windows.h> | ||||||
|  | #endif //_WIN32 | ||||||
|  |  | ||||||
|  | #ifdef SPDLOG_COMPILED_LIB | ||||||
|  | #undef SPDLOG_HEADER_ONLY | ||||||
|  | #define SPDLOG_INLINE | ||||||
|  | #else | ||||||
|  | #define SPDLOG_HEADER_ONLY | ||||||
|  | #define SPDLOG_INLINE inline | ||||||
|  | #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) | ||||||
| #define SPDLOG_NOEXCEPT throw() | #define SPDLOG_NOEXCEPT _NOEXCEPT | ||||||
| #define SPDLOG_CONSTEXPR | #define SPDLOG_CONSTEXPR | ||||||
| #else | #else | ||||||
| #define SPDLOG_NOEXCEPT noexcept | #define SPDLOG_NOEXCEPT noexcept | ||||||
| @@ -51,23 +61,25 @@ | |||||||
| #endif | #endif | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| // Get the basename of __FILE__ (at compile time if possible) |  | ||||||
| #if FMT_HAS_FEATURE(__builtin_strrchr) |  | ||||||
| #define SPDLOG_STRRCHR(str, sep) __builtin_strrchr(str, sep) |  | ||||||
| #else |  | ||||||
| #define SPDLOG_STRRCHR(str, sep) strrchr(str, sep) |  | ||||||
| #endif //__builtin_strrchr not defined |  | ||||||
|  |  | ||||||
| #ifdef _WIN32 |  | ||||||
| #define SPDLOG_FILE_BASENAME(file) SPDLOG_STRRCHR("\\" file, '\\') + 1 |  | ||||||
| #else |  | ||||||
| #define SPDLOG_FILE_BASENAME(file) SPDLOG_STRRCHR("/" file, '/') + 1 |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| #ifndef SPDLOG_FUNCTION | #ifndef SPDLOG_FUNCTION | ||||||
| #define SPDLOG_FUNCTION __FUNCTION__ | #define SPDLOG_FUNCTION __FUNCTION__ | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  | #ifdef SPDLOG_NO_EXCEPTIONS | ||||||
|  | #define SPDLOG_TRY | ||||||
|  | #define SPDLOG_THROW(ex)                                                                                                                   \ | ||||||
|  |     do                                                                                                                                     \ | ||||||
|  |     {                                                                                                                                      \ | ||||||
|  |         printf("spdlog fatal error: %s\n", ex.what());                                                                                     \ | ||||||
|  |         std::abort();                                                                                                                      \ | ||||||
|  |     } while (0) | ||||||
|  | #define SPDLOG_CATCH_ALL() | ||||||
|  | #else | ||||||
|  | #define SPDLOG_TRY try | ||||||
|  | #define SPDLOG_THROW(ex) throw(ex) | ||||||
|  | #define SPDLOG_CATCH_ALL() catch (...) | ||||||
|  | #endif | ||||||
|  |  | ||||||
| namespace spdlog { | namespace spdlog { | ||||||
|  |  | ||||||
| class formatter; | class formatter; | ||||||
| @@ -76,17 +88,35 @@ namespace sinks { | |||||||
| class sink; | class sink; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | #if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES) | ||||||
|  | using filename_t = std::wstring; | ||||||
|  | #define SPDLOG_FILENAME_T(s) L##s | ||||||
|  | #else | ||||||
|  | using filename_t = std::string; | ||||||
|  | #define SPDLOG_FILENAME_T(s) s | ||||||
|  | #endif | ||||||
|  |  | ||||||
| using log_clock = std::chrono::system_clock; | using log_clock = std::chrono::system_clock; | ||||||
| using sink_ptr = std::shared_ptr<sinks::sink>; | using sink_ptr = std::shared_ptr<sinks::sink>; | ||||||
| using sinks_init_list = std::initializer_list<sink_ptr>; | using sinks_init_list = std::initializer_list<sink_ptr>; | ||||||
| using log_err_handler = std::function<void(const std::string &err_msg)>; | using err_handler = std::function<void(const std::string &err_msg)>; | ||||||
|  | using string_view_t = fmt::basic_string_view<char>; | ||||||
|  | using wstring_view_t = fmt::basic_string_view<wchar_t>; | ||||||
|  | using memory_buf_t = fmt::basic_memory_buffer<char, 250>; | ||||||
|  |  | ||||||
| // string_view type - either std::string_view or fmt::string_view (pre c++17) | #ifdef SPDLOG_WCHAR_TO_UTF8_SUPPORT | ||||||
| #if defined(FMT_USE_STD_STRING_VIEW) | #ifndef _WIN32 | ||||||
| using string_view_t = std::string_view; | #error SPDLOG_WCHAR_TO_UTF8_SUPPORT only supported on windows | ||||||
| #else | #else | ||||||
| using string_view_t = fmt::string_view; | template<typename T> | ||||||
| #endif | struct is_convertible_to_wstring_view : std::is_convertible<T, wstring_view_t> | ||||||
|  | {}; | ||||||
|  | #endif // _WIN32 | ||||||
|  | #else | ||||||
|  | template<typename> | ||||||
|  | struct is_convertible_to_wstring_view : std::false_type | ||||||
|  | {}; | ||||||
|  | #endif // SPDLOG_WCHAR_TO_UTF8_SUPPORT | ||||||
|  |  | ||||||
| #if defined(SPDLOG_NO_ATOMIC_LEVELS) | #if defined(SPDLOG_NO_ATOMIC_LEVELS) | ||||||
| using level_t = details::null_atomic_int; | using level_t = details::null_atomic_int; | ||||||
| @@ -126,36 +156,31 @@ enum level_enum | |||||||
|     } |     } | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| static string_view_t level_string_views[] SPDLOG_LEVEL_NAMES; | #if !defined(SPDLOG_SHORT_LEVEL_NAMES) | ||||||
| static const char *short_level_names[]{"T", "D", "I", "W", "E", "C", "O"}; |  | ||||||
|  |  | ||||||
| inline string_view_t &to_string_view(spdlog::level::level_enum l) SPDLOG_NOEXCEPT | #define SPDLOG_SHORT_LEVEL_NAMES                                                                                                           \ | ||||||
| { |     {                                                                                                                                      \ | ||||||
|     return level_string_views[l]; |         "T", "D", "I", "W", "E", "C", "O"                                                                                                  \ | ||||||
| } |  | ||||||
|  |  | ||||||
| inline const char *to_short_c_str(spdlog::level::level_enum l) SPDLOG_NOEXCEPT |  | ||||||
| { |  | ||||||
|     return short_level_names[l]; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| inline spdlog::level::level_enum from_str(const std::string &name) SPDLOG_NOEXCEPT |  | ||||||
| { |  | ||||||
|     int level = 0; |  | ||||||
|     for (const auto &level_str : level_string_views) |  | ||||||
|     { |  | ||||||
|         if (level_str == name) |  | ||||||
|         { |  | ||||||
|             return static_cast<level::level_enum>(level); |  | ||||||
|         } |  | ||||||
|         level++; |  | ||||||
|     } |     } | ||||||
|     return level::off; | #endif | ||||||
| } |  | ||||||
|  | string_view_t &to_string_view(spdlog::level::level_enum l) SPDLOG_NOEXCEPT; | ||||||
|  | const char *to_short_c_str(spdlog::level::level_enum l) SPDLOG_NOEXCEPT; | ||||||
|  | spdlog::level::level_enum from_str(const std::string &name) SPDLOG_NOEXCEPT; | ||||||
|  |  | ||||||
| using level_hasher = std::hash<int>; | using level_hasher = std::hash<int>; | ||||||
| } // namespace level | } // namespace level | ||||||
|  |  | ||||||
|  | // | ||||||
|  | // Color mode used by sinks with color support. | ||||||
|  | // | ||||||
|  | enum class color_mode | ||||||
|  | { | ||||||
|  |     always, | ||||||
|  |     automatic, | ||||||
|  |     never | ||||||
|  | }; | ||||||
|  |  | ||||||
| // | // | ||||||
| // Pattern time - specific time getting to use for pattern_formatter. | // Pattern time - specific time getting to use for pattern_formatter. | ||||||
| // local time by default | // local time by default | ||||||
| @@ -172,58 +197,30 @@ enum class pattern_time_type | |||||||
| class spdlog_ex : public std::exception | class spdlog_ex : public std::exception | ||||||
| { | { | ||||||
| public: | public: | ||||||
|     explicit spdlog_ex(std::string msg) |     explicit spdlog_ex(std::string msg); | ||||||
|         : msg_(std::move(msg)) |     spdlog_ex(const std::string &msg, int last_errno); | ||||||
|     { |     const char *what() const SPDLOG_NOEXCEPT override; | ||||||
|     } |  | ||||||
|  |  | ||||||
|     spdlog_ex(const std::string &msg, int last_errno) |  | ||||||
|     { |  | ||||||
|         fmt::memory_buffer outbuf; |  | ||||||
|         fmt::format_system_error(outbuf, last_errno, msg); |  | ||||||
|         msg_ = fmt::to_string(outbuf); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     const char *what() const SPDLOG_NOEXCEPT override |  | ||||||
|     { |  | ||||||
|         return msg_.c_str(); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
| private: | private: | ||||||
|     std::string msg_; |     std::string msg_; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| // |  | ||||||
| // wchar support for windows file names (SPDLOG_WCHAR_FILENAMES must be defined) |  | ||||||
| // |  | ||||||
| #if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES) |  | ||||||
| using filename_t = std::wstring; |  | ||||||
| #else |  | ||||||
| using filename_t = std::string; |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| struct source_loc | struct source_loc | ||||||
| { | { | ||||||
|     SPDLOG_CONSTEXPR source_loc() |     SPDLOG_CONSTEXPR source_loc() = default; | ||||||
|         : filename{""} |     SPDLOG_CONSTEXPR source_loc(const char *filename_in, int line_in, const char *funcname_in) | ||||||
|         , line{0} |         : filename{filename_in} | ||||||
|         , funcname{""} |         , line{line_in} | ||||||
|     { |         , funcname{funcname_in} | ||||||
|     } |     {} | ||||||
|     SPDLOG_CONSTEXPR source_loc(const char *filename, int line, const char *funcname) |  | ||||||
|         : filename{filename} |  | ||||||
|         , line{static_cast<uint32_t>(line)} |  | ||||||
|         , funcname{funcname} |  | ||||||
|     { |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     SPDLOG_CONSTEXPR bool empty() const SPDLOG_NOEXCEPT |     SPDLOG_CONSTEXPR bool empty() const SPDLOG_NOEXCEPT | ||||||
|     { |     { | ||||||
|         return line == 0; |         return line == 0; | ||||||
|     } |     } | ||||||
|     const char *filename; |     const char *filename{nullptr}; | ||||||
|     uint32_t line; |     int line{0}; | ||||||
|     const char *funcname; |     const char *funcname{nullptr}; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| namespace details { | namespace details { | ||||||
| @@ -240,4 +237,9 @@ std::unique_ptr<T> make_unique(Args &&... args) | |||||||
| } | } | ||||||
| #endif | #endif | ||||||
| } // namespace details | } // namespace details | ||||||
|  |  | ||||||
| } // namespace spdlog | } // namespace spdlog | ||||||
|  |  | ||||||
|  | #ifdef SPDLOG_HEADER_ONLY | ||||||
|  | #include "common-inl.h" | ||||||
|  | #endif | ||||||
|   | |||||||
| @@ -1,110 +0,0 @@ | |||||||
| // |  | ||||||
| // Copyright(c) 2015 Gabi Melman. |  | ||||||
| // Distributed under the MIT License (http://opensource.org/licenses/MIT) |  | ||||||
| // |  | ||||||
|  |  | ||||||
| #pragma once |  | ||||||
|  |  | ||||||
| // async logger implementation |  | ||||||
| // uses a thread pool to perform the actual logging |  | ||||||
|  |  | ||||||
| #include "spdlog/details/thread_pool.h" |  | ||||||
|  |  | ||||||
| #include <chrono> |  | ||||||
| #include <memory> |  | ||||||
| #include <string> |  | ||||||
|  |  | ||||||
| template<typename It> |  | ||||||
| inline spdlog::async_logger::async_logger( |  | ||||||
|     std::string logger_name, It begin, It end, std::weak_ptr<details::thread_pool> tp, async_overflow_policy overflow_policy) |  | ||||||
|     : logger(std::move(logger_name), begin, end) |  | ||||||
|     , thread_pool_(std::move(tp)) |  | ||||||
|     , overflow_policy_(overflow_policy) |  | ||||||
| { |  | ||||||
| } |  | ||||||
|  |  | ||||||
| inline spdlog::async_logger::async_logger( |  | ||||||
|     std::string logger_name, sinks_init_list sinks_list, std::weak_ptr<details::thread_pool> tp, async_overflow_policy overflow_policy) |  | ||||||
|     : async_logger(std::move(logger_name), sinks_list.begin(), sinks_list.end(), std::move(tp), overflow_policy) |  | ||||||
| { |  | ||||||
| } |  | ||||||
|  |  | ||||||
| inline spdlog::async_logger::async_logger( |  | ||||||
|     std::string logger_name, sink_ptr single_sink, std::weak_ptr<details::thread_pool> tp, async_overflow_policy overflow_policy) |  | ||||||
|     : async_logger(std::move(logger_name), {std::move(single_sink)}, std::move(tp), overflow_policy) |  | ||||||
| { |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // send the log message to the thread pool |  | ||||||
| inline void spdlog::async_logger::sink_it_(details::log_msg &msg) |  | ||||||
| { |  | ||||||
| #if defined(SPDLOG_ENABLE_MESSAGE_COUNTER) |  | ||||||
|     incr_msg_counter_(msg); |  | ||||||
| #endif |  | ||||||
|     if (auto pool_ptr = thread_pool_.lock()) |  | ||||||
|     { |  | ||||||
|         pool_ptr->post_log(shared_from_this(), msg, overflow_policy_); |  | ||||||
|     } |  | ||||||
|     else |  | ||||||
|     { |  | ||||||
|         throw spdlog_ex("async log: thread pool doesn't exist anymore"); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // send flush request to the thread pool |  | ||||||
| inline void spdlog::async_logger::flush_() |  | ||||||
| { |  | ||||||
|     if (auto pool_ptr = thread_pool_.lock()) |  | ||||||
|     { |  | ||||||
|         pool_ptr->post_flush(shared_from_this(), overflow_policy_); |  | ||||||
|     } |  | ||||||
|     else |  | ||||||
|     { |  | ||||||
|         throw spdlog_ex("async flush: thread pool doesn't exist anymore"); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // |  | ||||||
| // backend functions - called from the thread pool to do the actual job |  | ||||||
| // |  | ||||||
| inline void spdlog::async_logger::backend_log_(const details::log_msg &incoming_log_msg) |  | ||||||
| { |  | ||||||
|     try |  | ||||||
|     { |  | ||||||
|         for (auto &s : sinks_) |  | ||||||
|         { |  | ||||||
|             if (s->should_log(incoming_log_msg.level)) |  | ||||||
|             { |  | ||||||
|                 s->log(incoming_log_msg); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|     SPDLOG_CATCH_AND_HANDLE |  | ||||||
|  |  | ||||||
|     if (should_flush_(incoming_log_msg)) |  | ||||||
|     { |  | ||||||
|         backend_flush_(); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| inline void spdlog::async_logger::backend_flush_() |  | ||||||
| { |  | ||||||
|     try |  | ||||||
|     { |  | ||||||
|         for (auto &sink : sinks_) |  | ||||||
|         { |  | ||||||
|             sink->flush(); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|     SPDLOG_CATCH_AND_HANDLE |  | ||||||
| } |  | ||||||
|  |  | ||||||
| inline std::shared_ptr<spdlog::logger> spdlog::async_logger::clone(std::string new_name) |  | ||||||
| { |  | ||||||
|     auto cloned = std::make_shared<spdlog::async_logger>(std::move(new_name), sinks_.begin(), sinks_.end(), thread_pool_, overflow_policy_); |  | ||||||
|  |  | ||||||
|     cloned->set_level(this->level()); |  | ||||||
|     cloned->flush_on(this->flush_level()); |  | ||||||
|     cloned->set_error_handler(this->error_handler()); |  | ||||||
|     return std::move(cloned); |  | ||||||
| } |  | ||||||
							
								
								
									
										74
									
								
								third_party/spdlog/include/spdlog/details/backtracer-inl.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								third_party/spdlog/include/spdlog/details/backtracer-inl.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,74 @@ | |||||||
|  | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. | ||||||
|  | // Distributed under the MIT License (http://opensource.org/licenses/MIT) | ||||||
|  |  | ||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #ifndef SPDLOG_HEADER_ONLY | ||||||
|  | #include "spdlog/details/backtracer.h" | ||||||
|  | #endif | ||||||
|  | namespace spdlog { | ||||||
|  | namespace details { | ||||||
|  | SPDLOG_INLINE backtracer::backtracer(const backtracer &other) | ||||||
|  | { | ||||||
|  |     std::lock_guard<std::mutex> lock(other.mutex_); | ||||||
|  |     enabled_ = other.enabled(); | ||||||
|  |     messages_ = other.messages_; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | SPDLOG_INLINE backtracer::backtracer(backtracer &&other) SPDLOG_NOEXCEPT | ||||||
|  | { | ||||||
|  |     std::lock_guard<std::mutex> lock(other.mutex_); | ||||||
|  |     enabled_ = other.enabled(); | ||||||
|  |     messages_ = std::move(other.messages_); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | SPDLOG_INLINE backtracer &backtracer::operator=(backtracer other) | ||||||
|  | { | ||||||
|  |     std::lock_guard<std::mutex> lock(mutex_); | ||||||
|  |     enabled_ = other.enabled(); | ||||||
|  |     messages_ = other.messages_; | ||||||
|  |     return *this; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | SPDLOG_INLINE void backtracer::enable(size_t size) | ||||||
|  | { | ||||||
|  |     std::lock_guard<std::mutex> lock{mutex_}; | ||||||
|  |     enabled_.store(true, std::memory_order_relaxed); | ||||||
|  |     messages_ = circular_q<log_msg_buffer>{size}; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | SPDLOG_INLINE void backtracer::disable() | ||||||
|  | { | ||||||
|  |     std::lock_guard<std::mutex> lock{mutex_}; | ||||||
|  |     enabled_.store(false, std::memory_order_relaxed); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | SPDLOG_INLINE bool backtracer::enabled() const | ||||||
|  | { | ||||||
|  |     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) | ||||||
|  | { | ||||||
|  |     std::lock_guard<std::mutex> lock{mutex_}; | ||||||
|  |     messages_.push_back(log_msg_buffer{msg}); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // pop all items in the q and apply the given fun on each of them. | ||||||
|  | SPDLOG_INLINE void backtracer::foreach_pop(std::function<void(const details::log_msg &)> fun) | ||||||
|  | { | ||||||
|  |     std::lock_guard<std::mutex> lock{mutex_}; | ||||||
|  |     while (!messages_.empty()) | ||||||
|  |     { | ||||||
|  |         auto &front_msg = messages_.front(); | ||||||
|  |         fun(front_msg); | ||||||
|  |         messages_.pop_front(); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | } // namespace details | ||||||
|  | } // namespace spdlog | ||||||
							
								
								
									
										46
									
								
								third_party/spdlog/include/spdlog/details/backtracer.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								third_party/spdlog/include/spdlog/details/backtracer.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,46 @@ | |||||||
|  | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. | ||||||
|  | // Distributed under the MIT License (http://opensource.org/licenses/MIT) | ||||||
|  |  | ||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #include "spdlog/details/log_msg_buffer.h" | ||||||
|  | #include "spdlog/details/circular_q.h" | ||||||
|  |  | ||||||
|  | #include <atomic> | ||||||
|  | #include <mutex> | ||||||
|  | #include <functional> | ||||||
|  |  | ||||||
|  | // Store log messages in circular buffer. | ||||||
|  | // Useful for storing debug data in case of error/warning happens. | ||||||
|  |  | ||||||
|  | namespace spdlog { | ||||||
|  | namespace details { | ||||||
|  | class backtracer | ||||||
|  | { | ||||||
|  |     mutable std::mutex mutex_; | ||||||
|  |     std::atomic<bool> enabled_{false}; | ||||||
|  |     circular_q<log_msg_buffer> messages_; | ||||||
|  |  | ||||||
|  | public: | ||||||
|  |     backtracer() = default; | ||||||
|  |     backtracer(const backtracer &other); | ||||||
|  |  | ||||||
|  |     backtracer(backtracer &&other) SPDLOG_NOEXCEPT; | ||||||
|  |     backtracer &operator=(backtracer other); | ||||||
|  |  | ||||||
|  |     void enable(size_t size); | ||||||
|  |     void disable(); | ||||||
|  |     bool enabled() const; | ||||||
|  |     explicit operator bool() const; | ||||||
|  |     void push_back(const log_msg &msg); | ||||||
|  |  | ||||||
|  |     // pop all items in the q and apply the given fun on each of them. | ||||||
|  |     void foreach_pop(std::function<void(const details::log_msg &)> fun); | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | } // namespace details | ||||||
|  | } // namespace spdlog | ||||||
|  |  | ||||||
|  | #ifdef SPDLOG_HEADER_ONLY | ||||||
|  | #include "backtracer-inl.h" | ||||||
|  | #endif | ||||||
| @@ -1,7 +1,5 @@ | |||||||
| // | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. | ||||||
| // Copyright(c) 2018 Gabi Melman. |  | ||||||
| // 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. | // cirucal q view of std::vector. | ||||||
| #pragma once | #pragma once | ||||||
| @@ -13,45 +11,87 @@ namespace details { | |||||||
| template<typename T> | template<typename T> | ||||||
| class circular_q | class circular_q | ||||||
| { | { | ||||||
|  |     size_t max_items_ = 0; | ||||||
|  |     typename std::vector<T>::size_type head_ = 0; | ||||||
|  |     typename std::vector<T>::size_type tail_ = 0; | ||||||
|  |     size_t overrun_counter_ = 0; | ||||||
|  |     std::vector<T> v_; | ||||||
|  |  | ||||||
| public: | public: | ||||||
|     using item_type = T; |     using value_type = T; | ||||||
|  |  | ||||||
|  |     // empty ctor - create a disabled queue with no elements allocated at all | ||||||
|  |     circular_q() = default; | ||||||
|  |  | ||||||
|     explicit circular_q(size_t max_items) |     explicit circular_q(size_t max_items) | ||||||
|         : max_items_(max_items + 1) // one item is reserved as marker for full q |         : max_items_(max_items + 1) // one item is reserved as marker for full q | ||||||
|         , v_(max_items_) |         , v_(max_items_) | ||||||
|  |     {} | ||||||
|  |  | ||||||
|  |     circular_q(const circular_q &) = default; | ||||||
|  |     circular_q &operator=(const circular_q &) = default; | ||||||
|  |  | ||||||
|  |     // move cannot be default, | ||||||
|  |     // since we need to reset head_, tail_, etc to zero in the moved object | ||||||
|  |     circular_q(circular_q &&other) SPDLOG_NOEXCEPT | ||||||
|     { |     { | ||||||
|  |         copy_moveable(std::move(other)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     circular_q &operator=(circular_q &&other) SPDLOG_NOEXCEPT | ||||||
|  |     { | ||||||
|  |         copy_moveable(std::move(other)); | ||||||
|  |         return *this; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     // push back, overrun (oldest) item if no room left |     // push back, overrun (oldest) item if no room left | ||||||
|     void push_back(T &&item) |     void push_back(T &&item) | ||||||
|     { |     { | ||||||
|         v_[tail_] = std::move(item); |         if (max_items_ > 0) | ||||||
|         tail_ = (tail_ + 1) % max_items_; |  | ||||||
|  |  | ||||||
|         if (tail_ == head_) // overrun last item if full |  | ||||||
|         { |         { | ||||||
|             head_ = (head_ + 1) % max_items_; |             v_[tail_] = std::move(item); | ||||||
|             ++overrun_counter_; |             tail_ = (tail_ + 1) % max_items_; | ||||||
|  |  | ||||||
|  |             if (tail_ == head_) // overrun last item if full | ||||||
|  |             { | ||||||
|  |                 head_ = (head_ + 1) % max_items_; | ||||||
|  |                 ++overrun_counter_; | ||||||
|  |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     // Return reference to the front item. | ||||||
|  |     // If there are no elements in the container, the behavior is undefined. | ||||||
|  |     const T &front() const | ||||||
|  |     { | ||||||
|  |         return v_[head_]; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     T &front() | ||||||
|  |     { | ||||||
|  |         return v_[head_]; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     // 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(T &popped_item) |     void pop_front() | ||||||
|     { |     { | ||||||
|         popped_item = std::move(v_[head_]); |  | ||||||
|         head_ = (head_ + 1) % max_items_; |         head_ = (head_ + 1) % max_items_; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     bool empty() |     bool empty() const | ||||||
|     { |     { | ||||||
|         return tail_ == head_; |         return tail_ == head_; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     bool full() |     bool full() const | ||||||
|     { |     { | ||||||
|         // head is ahead of the tail by 1 |         // head is ahead of the tail by 1 | ||||||
|         return ((tail_ + 1) % max_items_) == head_; |         if (max_items_ > 0) | ||||||
|  |         { | ||||||
|  |             return ((tail_ + 1) % max_items_) == head_; | ||||||
|  |         } | ||||||
|  |         return false; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     size_t overrun_counter() const |     size_t overrun_counter() const | ||||||
| @@ -60,13 +100,20 @@ public: | |||||||
|     } |     } | ||||||
|  |  | ||||||
| private: | private: | ||||||
|     size_t max_items_; |     // copy from other&& and reset it to disabled state | ||||||
|     typename std::vector<T>::size_type head_ = 0; |     void copy_moveable(circular_q &&other) SPDLOG_NOEXCEPT | ||||||
|     typename std::vector<T>::size_type tail_ = 0; |     { | ||||||
|  |         max_items_ = other.max_items_; | ||||||
|  |         head_ = other.head_; | ||||||
|  |         tail_ = other.tail_; | ||||||
|  |         overrun_counter_ = other.overrun_counter_; | ||||||
|  |         v_ = std::move(other.v_); | ||||||
|  |  | ||||||
|     std::vector<T> v_; |         // put &&other in disabled, but valid state | ||||||
|  |         other.max_items_ = 0; | ||||||
|     size_t overrun_counter_ = 0; |         other.head_ = other.tail_ = 0; | ||||||
|  |         other.overrun_counter_ = 0; | ||||||
|  |     } | ||||||
| }; | }; | ||||||
| } // namespace details | } // namespace details | ||||||
| } // namespace spdlog | } // namespace spdlog | ||||||
|   | |||||||
| @@ -1,55 +1,13 @@ | |||||||
| #pragma once | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. | ||||||
| // |  | ||||||
| // Copyright(c) 2018 Gabi Melman. |  | ||||||
| // Distributed under the MIT License (http://opensource.org/licenses/MIT) | // Distributed under the MIT License (http://opensource.org/licenses/MIT) | ||||||
| // |  | ||||||
|  | #pragma once | ||||||
|  |  | ||||||
| #include "spdlog/details/null_mutex.h" | #include "spdlog/details/null_mutex.h" | ||||||
| #include <cstdio> |  | ||||||
| #include <mutex> | #include <mutex> | ||||||
|  |  | ||||||
| #ifdef _WIN32 |  | ||||||
|  |  | ||||||
| #ifndef NOMINMAX |  | ||||||
| #define NOMINMAX // prevent windows redefining min/max |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| #ifndef WIN32_LEAN_AND_MEAN |  | ||||||
| #define WIN32_LEAN_AND_MEAN |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| #include <windows.h> |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| namespace spdlog { | namespace spdlog { | ||||||
| namespace details { | namespace details { | ||||||
| struct console_stdout |  | ||||||
| { |  | ||||||
|     static std::FILE *stream() |  | ||||||
|     { |  | ||||||
|         return stdout; |  | ||||||
|     } |  | ||||||
| #ifdef _WIN32 |  | ||||||
|     static HANDLE handle() |  | ||||||
|     { |  | ||||||
|         return ::GetStdHandle(STD_OUTPUT_HANDLE); |  | ||||||
|     } |  | ||||||
| #endif |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| struct console_stderr |  | ||||||
| { |  | ||||||
|     static std::FILE *stream() |  | ||||||
|     { |  | ||||||
|         return stderr; |  | ||||||
|     } |  | ||||||
| #ifdef _WIN32 |  | ||||||
|     static HANDLE handle() |  | ||||||
|     { |  | ||||||
|         return ::GetStdHandle(STD_ERROR_HANDLE); |  | ||||||
|     } |  | ||||||
| #endif |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| struct console_mutex | struct console_mutex | ||||||
| { | { | ||||||
|   | |||||||
							
								
								
									
										133
									
								
								third_party/spdlog/include/spdlog/details/file_helper-inl.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										133
									
								
								third_party/spdlog/include/spdlog/details/file_helper-inl.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,133 @@ | |||||||
|  | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. | ||||||
|  | // Distributed under the MIT License (http://opensource.org/licenses/MIT) | ||||||
|  |  | ||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #ifndef SPDLOG_HEADER_ONLY | ||||||
|  | #include "spdlog/details/file_helper.h" | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #include "spdlog/details/os.h" | ||||||
|  | #include "spdlog/common.h" | ||||||
|  |  | ||||||
|  | #include <cerrno> | ||||||
|  | #include <chrono> | ||||||
|  | #include <cstdio> | ||||||
|  | #include <string> | ||||||
|  | #include <thread> | ||||||
|  | #include <tuple> | ||||||
|  |  | ||||||
|  | namespace spdlog { | ||||||
|  | namespace details { | ||||||
|  |  | ||||||
|  | SPDLOG_INLINE file_helper::~file_helper() | ||||||
|  | { | ||||||
|  |     close(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | SPDLOG_INLINE void file_helper::open(const filename_t &fname, bool truncate) | ||||||
|  | { | ||||||
|  |     close(); | ||||||
|  |     auto *mode = truncate ? SPDLOG_FILENAME_T("wb") : SPDLOG_FILENAME_T("ab"); | ||||||
|  |     _filename = fname; | ||||||
|  |     for (int tries = 0; tries < open_tries; ++tries) | ||||||
|  |     { | ||||||
|  |         if (!os::fopen_s(&fd_, fname, mode)) | ||||||
|  |         { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         details::os::sleep_for_millis(open_interval); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     SPDLOG_THROW(spdlog_ex("Failed opening file " + os::filename_to_str(_filename) + " for writing", errno)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | SPDLOG_INLINE void file_helper::reopen(bool truncate) | ||||||
|  | { | ||||||
|  |     if (_filename.empty()) | ||||||
|  |     { | ||||||
|  |         SPDLOG_THROW(spdlog_ex("Failed re opening file - was not opened before")); | ||||||
|  |     } | ||||||
|  |     open(_filename, truncate); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | SPDLOG_INLINE void file_helper::flush() | ||||||
|  | { | ||||||
|  |     std::fflush(fd_); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | SPDLOG_INLINE void file_helper::close() | ||||||
|  | { | ||||||
|  |     if (fd_ != nullptr) | ||||||
|  |     { | ||||||
|  |         std::fclose(fd_); | ||||||
|  |         fd_ = nullptr; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | SPDLOG_INLINE void file_helper::write(const memory_buf_t &buf) | ||||||
|  | { | ||||||
|  |     size_t msg_size = buf.size(); | ||||||
|  |     auto data = buf.data(); | ||||||
|  |     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_INLINE size_t file_helper::size() const | ||||||
|  | { | ||||||
|  |     if (fd_ == nullptr) | ||||||
|  |     { | ||||||
|  |         SPDLOG_THROW(spdlog_ex("Cannot use size() on closed file " + os::filename_to_str(_filename))); | ||||||
|  |     } | ||||||
|  |     return os::filesize(fd_); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | SPDLOG_INLINE const filename_t &file_helper::filename() const | ||||||
|  | { | ||||||
|  |     return _filename; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | SPDLOG_INLINE bool file_helper::file_exists(const filename_t &fname) | ||||||
|  | { | ||||||
|  |     return os::file_exists(fname); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // | ||||||
|  | // return file path and its extension: | ||||||
|  | // | ||||||
|  | // "mylog.txt" => ("mylog", ".txt") | ||||||
|  | // "mylog" => ("mylog", "") | ||||||
|  | // "mylog." => ("mylog.", "") | ||||||
|  | // "/dir1/dir2/mylog.txt" => ("/dir1/dir2/mylog", ".txt") | ||||||
|  | // | ||||||
|  | // the starting dot in filenames is ignored (hidden files): | ||||||
|  | // | ||||||
|  | // ".mylog" => (".mylog". "") | ||||||
|  | // "my_folder/.mylog" => ("my_folder/.mylog", "") | ||||||
|  | // "my_folder/.mylog.txt" => ("my_folder/.mylog", ".txt") | ||||||
|  | SPDLOG_INLINE std::tuple<filename_t, filename_t> file_helper::split_by_extension(const filename_t &fname) | ||||||
|  | { | ||||||
|  |     auto ext_index = fname.rfind('.'); | ||||||
|  |  | ||||||
|  |     // no valid extension found - return whole path and empty string as | ||||||
|  |     // extension | ||||||
|  |     if (ext_index == filename_t::npos || ext_index == 0 || ext_index == fname.size() - 1) | ||||||
|  |     { | ||||||
|  |         return std::make_tuple(fname, filename_t()); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // treat casese like "/etc/rc.d/somelogfile or "/abc/.hiddenfile" | ||||||
|  |     auto folder_index = fname.rfind(details::os::folder_sep); | ||||||
|  |     if (folder_index != filename_t::npos && folder_index >= ext_index - 1) | ||||||
|  |     { | ||||||
|  |         return std::make_tuple(fname, filename_t()); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // finally - return a valid base and extension tuple | ||||||
|  |     return std::make_tuple(fname.substr(0, ext_index), fname.substr(ext_index)); | ||||||
|  | } | ||||||
|  | } // namespace details | ||||||
|  | } // namespace spdlog | ||||||
| @@ -1,113 +1,35 @@ | |||||||
| // | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. | ||||||
| // Copyright(c) 2015 Gabi Melman. |  | ||||||
| // Distributed under the MIT License (http://opensource.org/licenses/MIT) | // Distributed under the MIT License (http://opensource.org/licenses/MIT) | ||||||
| // |  | ||||||
|  |  | ||||||
| #pragma once | #pragma once | ||||||
|  |  | ||||||
| // Helper class for file sinks. | #include "spdlog/common.h" | ||||||
| // When failing to open a file, retry several times(5) with a delay interval(10 ms). |  | ||||||
| // Throw spdlog_ex exception on errors. |  | ||||||
|  |  | ||||||
| #include "spdlog/details/log_msg.h" |  | ||||||
| #include "spdlog/details/os.h" |  | ||||||
|  |  | ||||||
| #include <cerrno> |  | ||||||
| #include <chrono> |  | ||||||
| #include <cstdio> |  | ||||||
| #include <string> |  | ||||||
| #include <thread> |  | ||||||
| #include <tuple> | #include <tuple> | ||||||
|  |  | ||||||
| namespace spdlog { | namespace spdlog { | ||||||
| namespace details { | namespace details { | ||||||
|  |  | ||||||
|  | // Helper class for file sinks. | ||||||
|  | // When failing to open a file, retry several times(5) with a delay interval(10 ms). | ||||||
|  | // Throw spdlog_ex exception on errors. | ||||||
|  |  | ||||||
| class file_helper | class file_helper | ||||||
| { | { | ||||||
|  |  | ||||||
| public: | public: | ||||||
|     const int open_tries = 5; |  | ||||||
|     const int open_interval = 10; |  | ||||||
|  |  | ||||||
|     explicit file_helper() = default; |     explicit file_helper() = default; | ||||||
|  |  | ||||||
|     file_helper(const file_helper &) = delete; |     file_helper(const file_helper &) = delete; | ||||||
|     file_helper &operator=(const file_helper &) = delete; |     file_helper &operator=(const file_helper &) = delete; | ||||||
|  |     ~file_helper(); | ||||||
|  |  | ||||||
|     ~file_helper() |     void open(const filename_t &fname, bool truncate = false); | ||||||
|     { |     void reopen(bool truncate); | ||||||
|         close(); |     void flush(); | ||||||
|     } |     void close(); | ||||||
|  |     void write(const memory_buf_t &buf); | ||||||
|     void open(const filename_t &fname, bool truncate = false) |     size_t size() const; | ||||||
|     { |     const filename_t &filename() const; | ||||||
|         close(); |     static bool file_exists(const filename_t &fname); | ||||||
|         auto *mode = truncate ? SPDLOG_FILENAME_T("wb") : SPDLOG_FILENAME_T("ab"); |  | ||||||
|         _filename = fname; |  | ||||||
|         for (int tries = 0; tries < open_tries; ++tries) |  | ||||||
|         { |  | ||||||
|             if (!os::fopen_s(&fd_, fname, mode)) |  | ||||||
|             { |  | ||||||
|                 return; |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             details::os::sleep_for_millis(open_interval); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         throw spdlog_ex("Failed opening file " + os::filename_to_str(_filename) + " for writing", errno); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     void reopen(bool truncate) |  | ||||||
|     { |  | ||||||
|         if (_filename.empty()) |  | ||||||
|         { |  | ||||||
|             throw spdlog_ex("Failed re opening file - was not opened before"); |  | ||||||
|         } |  | ||||||
|         open(_filename, truncate); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     void flush() |  | ||||||
|     { |  | ||||||
|         std::fflush(fd_); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     void close() |  | ||||||
|     { |  | ||||||
|         if (fd_ != nullptr) |  | ||||||
|         { |  | ||||||
|             std::fclose(fd_); |  | ||||||
|             fd_ = nullptr; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     void write(const fmt::memory_buffer &buf) |  | ||||||
|     { |  | ||||||
|         size_t msg_size = buf.size(); |  | ||||||
|         auto data = buf.data(); |  | ||||||
|         if (std::fwrite(data, 1, msg_size, fd_) != msg_size) |  | ||||||
|         { |  | ||||||
|             throw spdlog_ex("Failed writing to file " + os::filename_to_str(_filename), errno); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     size_t size() const |  | ||||||
|     { |  | ||||||
|         if (fd_ == nullptr) |  | ||||||
|         { |  | ||||||
|             throw spdlog_ex("Cannot use size() on closed file " + os::filename_to_str(_filename)); |  | ||||||
|         } |  | ||||||
|         return os::filesize(fd_); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     const filename_t &filename() const |  | ||||||
|     { |  | ||||||
|         return _filename; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     static bool file_exists(const filename_t &fname) |  | ||||||
|     { |  | ||||||
|         return os::file_exists(fname); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     // |     // | ||||||
|     // return file path and its extension: |     // return file path and its extension: | ||||||
| @@ -122,31 +44,17 @@ public: | |||||||
|     // ".mylog" => (".mylog". "") |     // ".mylog" => (".mylog". "") | ||||||
|     // "my_folder/.mylog" => ("my_folder/.mylog", "") |     // "my_folder/.mylog" => ("my_folder/.mylog", "") | ||||||
|     // "my_folder/.mylog.txt" => ("my_folder/.mylog", ".txt") |     // "my_folder/.mylog.txt" => ("my_folder/.mylog", ".txt") | ||||||
|     static std::tuple<filename_t, filename_t> split_by_extension(const spdlog::filename_t &fname) |     static std::tuple<filename_t, filename_t> split_by_extension(const filename_t &fname); | ||||||
|     { |  | ||||||
|         auto ext_index = fname.rfind('.'); |  | ||||||
|  |  | ||||||
|         // no valid extension found - return whole path and empty string as |  | ||||||
|         // extension |  | ||||||
|         if (ext_index == filename_t::npos || ext_index == 0 || ext_index == fname.size() - 1) |  | ||||||
|         { |  | ||||||
|             return std::make_tuple(fname, spdlog::filename_t()); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         // treat casese like "/etc/rc.d/somelogfile or "/abc/.hiddenfile" |  | ||||||
|         auto folder_index = fname.rfind(details::os::folder_sep); |  | ||||||
|         if (folder_index != filename_t::npos && folder_index >= ext_index - 1) |  | ||||||
|         { |  | ||||||
|             return std::make_tuple(fname, spdlog::filename_t()); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         // finally - return a valid base and extension tuple |  | ||||||
|         return std::make_tuple(fname.substr(0, ext_index), fname.substr(ext_index)); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
| private: | private: | ||||||
|  |     const int open_tries = 5; | ||||||
|  |     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 | ||||||
|  |  | ||||||
|  | #ifdef SPDLOG_HEADER_ONLY | ||||||
|  | #include "file_helper-inl.h" | ||||||
|  | #endif | ||||||
|   | |||||||
| @@ -1,33 +1,23 @@ | |||||||
| // | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. | ||||||
| // Created by gabi on 6/15/18. | // Distributed under the MIT License (http://opensource.org/licenses/MIT) | ||||||
| // |  | ||||||
|  |  | ||||||
| #pragma once | #pragma once | ||||||
|  |  | ||||||
| #include <chrono> | #include <chrono> | ||||||
| #include <type_traits> | #include <type_traits> | ||||||
| #include "spdlog/fmt/fmt.h" | #include "spdlog/fmt/fmt.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 { | ||||||
| namespace details { | namespace details { | ||||||
| namespace fmt_helper { | namespace fmt_helper { | ||||||
|  |  | ||||||
| template<size_t Buffer_Size> | inline spdlog::string_view_t to_string_view(const memory_buf_t &buf) SPDLOG_NOEXCEPT | ||||||
| inline spdlog::string_view_t to_string_view(const fmt::basic_memory_buffer<char, Buffer_Size> &buf) SPDLOG_NOEXCEPT |  | ||||||
| { | { | ||||||
|     return spdlog::string_view_t(buf.data(), buf.size()); |     return spdlog::string_view_t{buf.data(), buf.size()}; | ||||||
| } | } | ||||||
|  |  | ||||||
| template<size_t Buffer_Size1, size_t Buffer_Size2> | inline void append_string_view(spdlog::string_view_t view, memory_buf_t &dest) | ||||||
| inline void append_buf(const fmt::basic_memory_buffer<char, Buffer_Size1> &buf, fmt::basic_memory_buffer<char, Buffer_Size2> &dest) |  | ||||||
| { |  | ||||||
|     auto *buf_ptr = buf.data(); |  | ||||||
|     dest.append(buf_ptr, buf_ptr + buf.size()); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| template<size_t Buffer_Size> |  | ||||||
| inline void append_string_view(spdlog::string_view_t view, fmt::basic_memory_buffer<char, Buffer_Size> &dest) |  | ||||||
| { | { | ||||||
|     auto *buf_ptr = view.data(); |     auto *buf_ptr = view.data(); | ||||||
|     if (buf_ptr != nullptr) |     if (buf_ptr != nullptr) | ||||||
| @@ -36,8 +26,8 @@ inline void append_string_view(spdlog::string_view_t view, fmt::basic_memory_buf | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| template<typename T, size_t Buffer_Size> | template<typename T> | ||||||
| inline void append_int(T n, fmt::basic_memory_buffer<char, Buffer_Size> &dest) | inline void append_int(T n, memory_buf_t &dest) | ||||||
| { | { | ||||||
|     fmt::format_int i(n); |     fmt::format_int i(n); | ||||||
|     dest.append(i.data(), i.data() + i.size()); |     dest.append(i.data(), i.data() + i.size()); | ||||||
| @@ -50,8 +40,7 @@ inline unsigned count_digits(T n) | |||||||
|     return static_cast<unsigned>(fmt::internal::count_digits(static_cast<count_type>(n))); |     return static_cast<unsigned>(fmt::internal::count_digits(static_cast<count_type>(n))); | ||||||
| } | } | ||||||
|  |  | ||||||
| template<size_t Buffer_Size> | inline void pad2(int n, memory_buf_t &dest) | ||||||
| inline void pad2(int n, fmt::basic_memory_buffer<char, Buffer_Size> &dest) |  | ||||||
| { | { | ||||||
|     if (n > 99) |     if (n > 99) | ||||||
|     { |     { | ||||||
| @@ -73,8 +62,8 @@ inline void pad2(int n, fmt::basic_memory_buffer<char, Buffer_Size> &dest) | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| template<typename T, size_t Buffer_Size> | template<typename T> | ||||||
| inline void pad_uint(T n, unsigned int width, fmt::basic_memory_buffer<char, Buffer_Size> &dest) | inline void pad_uint(T n, unsigned int width, memory_buf_t &dest) | ||||||
| { | { | ||||||
|     static_assert(std::is_unsigned<T>::value, "pad_uint must get unsigned T"); |     static_assert(std::is_unsigned<T>::value, "pad_uint must get unsigned T"); | ||||||
|     auto digits = count_digits(n); |     auto digits = count_digits(n); | ||||||
| @@ -86,20 +75,20 @@ inline void pad_uint(T n, unsigned int width, fmt::basic_memory_buffer<char, Buf | |||||||
|     append_int(n, dest); |     append_int(n, dest); | ||||||
| } | } | ||||||
|  |  | ||||||
| template<typename T, size_t Buffer_Size> | template<typename T> | ||||||
| inline void pad3(T n, fmt::basic_memory_buffer<char, Buffer_Size> &dest) | inline void pad3(T n, memory_buf_t &dest) | ||||||
| { | { | ||||||
|     pad_uint(n, 3, dest); |     pad_uint(n, 3, dest); | ||||||
| } | } | ||||||
|  |  | ||||||
| template<typename T, size_t Buffer_Size> | template<typename T> | ||||||
| inline void pad6(T n, fmt::basic_memory_buffer<char, Buffer_Size> &dest) | inline void pad6(T n, memory_buf_t &dest) | ||||||
| { | { | ||||||
|     pad_uint(n, 6, dest); |     pad_uint(n, 6, dest); | ||||||
| } | } | ||||||
|  |  | ||||||
| template<typename T, size_t Buffer_Size> | template<typename T> | ||||||
| inline void pad9(T n, fmt::basic_memory_buffer<char, Buffer_Size> &dest) | inline void pad9(T n, memory_buf_t &dest) | ||||||
| { | { | ||||||
|     pad_uint(n, 9, dest); |     pad_uint(n, 9, dest); | ||||||
| } | } | ||||||
| @@ -108,7 +97,7 @@ inline void pad9(T n, fmt::basic_memory_buffer<char, Buffer_Size> &dest) | |||||||
| // e.g. | // e.g. | ||||||
| // fraction<std::milliseconds>(tp) -> will return the millis part of the second | // fraction<std::milliseconds>(tp) -> will return the millis part of the second | ||||||
| template<typename ToDuration> | template<typename ToDuration> | ||||||
| inline ToDuration time_fraction(const log_clock::time_point &tp) | inline ToDuration time_fraction(log_clock::time_point tp) | ||||||
| { | { | ||||||
|     using std::chrono::duration_cast; |     using std::chrono::duration_cast; | ||||||
|     using std::chrono::seconds; |     using std::chrono::seconds; | ||||||
|   | |||||||
							
								
								
									
										34
									
								
								third_party/spdlog/include/spdlog/details/log_msg-inl.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								third_party/spdlog/include/spdlog/details/log_msg-inl.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,34 @@ | |||||||
|  | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. | ||||||
|  | // Distributed under the MIT License (http://opensource.org/licenses/MIT) | ||||||
|  |  | ||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #ifndef SPDLOG_HEADER_ONLY | ||||||
|  | #include "spdlog/details/log_msg.h" | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #include "spdlog/details/os.h" | ||||||
|  |  | ||||||
|  | namespace spdlog { | ||||||
|  | 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) | ||||||
|  |     : logger_name(logger_name) | ||||||
|  |     , level(lvl) | ||||||
|  | #ifndef SPDLOG_NO_DATETIME | ||||||
|  |     , time(os::now()) | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #ifndef SPDLOG_NO_THREAD_ID | ||||||
|  |     , thread_id(os::thread_id()) | ||||||
|  | #endif | ||||||
|  |     , source(loc) | ||||||
|  |     , payload(msg) | ||||||
|  | {} | ||||||
|  |  | ||||||
|  | SPDLOG_INLINE log_msg::log_msg(string_view_t logger_name, spdlog::level::level_enum lvl, spdlog::string_view_t msg) | ||||||
|  |     : log_msg(source_loc{}, logger_name, lvl, msg) | ||||||
|  | {} | ||||||
|  |  | ||||||
|  | } // namespace details | ||||||
|  | } // namespace spdlog | ||||||
| @@ -1,55 +1,35 @@ | |||||||
| // | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. | ||||||
| // Copyright(c) 2015 Gabi Melman. |  | ||||||
| // Distributed under the MIT License (http://opensource.org/licenses/MIT) | // Distributed under the MIT License (http://opensource.org/licenses/MIT) | ||||||
| // |  | ||||||
|  |  | ||||||
| #pragma once | #pragma once | ||||||
|  |  | ||||||
| #include "spdlog/common.h" | #include "spdlog/common.h" | ||||||
| #include "spdlog/details/os.h" |  | ||||||
|  |  | ||||||
| #include <string> | #include <string> | ||||||
| #include <utility> |  | ||||||
|  |  | ||||||
| namespace spdlog { | namespace spdlog { | ||||||
| namespace details { | namespace details { | ||||||
| struct log_msg | struct log_msg | ||||||
| { | { | ||||||
|  |     log_msg() = default; | ||||||
|     log_msg(source_loc loc, const std::string *loggers_name, level::level_enum lvl, string_view_t view) |     log_msg(source_loc loc, string_view_t logger_name, level::level_enum lvl, string_view_t msg); | ||||||
|         : logger_name(loggers_name) |     log_msg(string_view_t logger_name, level::level_enum lvl, string_view_t msg); | ||||||
|         , level(lvl) |  | ||||||
| #ifndef SPDLOG_NO_DATETIME |  | ||||||
|         , time(os::now()) |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| #ifndef SPDLOG_NO_THREAD_ID |  | ||||||
|         , thread_id(os::thread_id()) |  | ||||||
| #endif |  | ||||||
|         , source(loc) |  | ||||||
|         , payload(view) |  | ||||||
|     { |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     log_msg(const std::string *loggers_name, level::level_enum lvl, string_view_t view) |  | ||||||
|         : log_msg(source_loc{}, loggers_name, lvl, view) |  | ||||||
|     { |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     log_msg(const log_msg &other) = default; |     log_msg(const log_msg &other) = default; | ||||||
|  |  | ||||||
|     const std::string *logger_name{nullptr}; |     string_view_t logger_name; | ||||||
|     level::level_enum level{level::off}; |     level::level_enum level{level::off}; | ||||||
|     log_clock::time_point time; |     log_clock::time_point time; | ||||||
|     size_t thread_id{0}; |     size_t thread_id{0}; | ||||||
|     size_t msg_id{0}; |  | ||||||
|  |  | ||||||
|     // wrapping the formatted text with color (updated by pattern_formatter). |     // wrapping the formatted text with color (updated by pattern_formatter). | ||||||
|     mutable size_t color_range_start{0}; |     mutable size_t color_range_start{0}; | ||||||
|     mutable size_t color_range_end{0}; |     mutable size_t color_range_end{0}; | ||||||
|  |  | ||||||
|     source_loc source; |     source_loc source; | ||||||
|     const string_view_t payload; |     string_view_t payload; | ||||||
| }; | }; | ||||||
| } // namespace details | } // namespace details | ||||||
| } // namespace spdlog | } // namespace spdlog | ||||||
|  |  | ||||||
|  | #ifdef SPDLOG_HEADER_ONLY | ||||||
|  | #include "log_msg-inl.h" | ||||||
|  | #endif | ||||||
|   | |||||||
							
								
								
									
										60
									
								
								third_party/spdlog/include/spdlog/details/log_msg_buffer-inl.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								third_party/spdlog/include/spdlog/details/log_msg_buffer-inl.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,60 @@ | |||||||
|  | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. | ||||||
|  | // Distributed under the MIT License (http://opensource.org/licenses/MIT) | ||||||
|  |  | ||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #ifndef SPDLOG_HEADER_ONLY | ||||||
|  | #include "spdlog/details/log_msg_buffer.h" | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | namespace spdlog { | ||||||
|  | namespace details { | ||||||
|  |  | ||||||
|  | SPDLOG_INLINE log_msg_buffer::log_msg_buffer(const log_msg &orig_msg) | ||||||
|  |     : log_msg{orig_msg} | ||||||
|  | { | ||||||
|  |     buffer.append(logger_name.begin(), logger_name.end()); | ||||||
|  |     buffer.append(payload.begin(), payload.end()); | ||||||
|  |     update_string_views(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | SPDLOG_INLINE log_msg_buffer::log_msg_buffer(const log_msg_buffer &other) | ||||||
|  |     : log_msg{other} | ||||||
|  | { | ||||||
|  |     buffer.append(logger_name.begin(), logger_name.end()); | ||||||
|  |     buffer.append(payload.begin(), payload.end()); | ||||||
|  |     update_string_views(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | SPDLOG_INLINE log_msg_buffer::log_msg_buffer(log_msg_buffer &&other) | ||||||
|  |     : log_msg{std::move(other)} | ||||||
|  |     , buffer{std::move(other.buffer)} | ||||||
|  | { | ||||||
|  |     update_string_views(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | SPDLOG_INLINE log_msg_buffer &log_msg_buffer::operator=(const log_msg_buffer &other) | ||||||
|  | { | ||||||
|  |     log_msg::operator=(other); | ||||||
|  |     buffer.clear(); | ||||||
|  |     buffer.append(other.buffer.data(), other.buffer.data() + other.buffer.size()); | ||||||
|  |     update_string_views(); | ||||||
|  |     return *this; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | SPDLOG_INLINE log_msg_buffer &log_msg_buffer::operator=(log_msg_buffer &&other) | ||||||
|  | { | ||||||
|  |     log_msg::operator=(std::move(other)); | ||||||
|  |     buffer = std::move(other.buffer); | ||||||
|  |     update_string_views(); | ||||||
|  |     return *this; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | SPDLOG_INLINE void log_msg_buffer::update_string_views() | ||||||
|  | { | ||||||
|  |     logger_name = string_view_t{buffer.data(), logger_name.size()}; | ||||||
|  |     payload = string_view_t{buffer.data() + logger_name.size(), payload.size()}; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | } // namespace details | ||||||
|  | } // namespace spdlog | ||||||
							
								
								
									
										33
									
								
								third_party/spdlog/include/spdlog/details/log_msg_buffer.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								third_party/spdlog/include/spdlog/details/log_msg_buffer.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,33 @@ | |||||||
|  | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. | ||||||
|  | // Distributed under the MIT License (http://opensource.org/licenses/MIT) | ||||||
|  |  | ||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #include "spdlog/details/log_msg.h" | ||||||
|  |  | ||||||
|  | namespace spdlog { | ||||||
|  | namespace details { | ||||||
|  |  | ||||||
|  | // Extend log_msg with internal buffer to store its payload. | ||||||
|  | // THis is needed since log_msg holds string_views that points to stack data. | ||||||
|  |  | ||||||
|  | class log_msg_buffer : public log_msg | ||||||
|  | { | ||||||
|  |     memory_buf_t buffer; | ||||||
|  |     void update_string_views(); | ||||||
|  |  | ||||||
|  | public: | ||||||
|  |     log_msg_buffer() = default; | ||||||
|  |     explicit log_msg_buffer(const log_msg &orig_msg); | ||||||
|  |     log_msg_buffer(const log_msg_buffer &other); | ||||||
|  |     log_msg_buffer(log_msg_buffer &&other); | ||||||
|  |     log_msg_buffer &operator=(const log_msg_buffer &other); | ||||||
|  |     log_msg_buffer &operator=(log_msg_buffer &&other); | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | } // namespace details | ||||||
|  | } // namespace spdlog | ||||||
|  |  | ||||||
|  | #ifdef SPDLOG_HEADER_ONLY | ||||||
|  | #include "log_msg_buffer-inl.h" | ||||||
|  | #endif | ||||||
| @@ -1,441 +0,0 @@ | |||||||
| // |  | ||||||
| // Copyright(c) 2015 Gabi Melman. |  | ||||||
| // Distributed under the MIT License (http://opensource.org/licenses/MIT) |  | ||||||
| // |  | ||||||
|  |  | ||||||
| #pragma once |  | ||||||
|  |  | ||||||
| #include "spdlog/details/fmt_helper.h" |  | ||||||
|  |  | ||||||
| #include <memory> |  | ||||||
| #include <string> |  | ||||||
|  |  | ||||||
| #define SPDLOG_CATCH_AND_HANDLE                                                                                                            \ |  | ||||||
|     catch (const std::exception &ex)                                                                                                       \ |  | ||||||
|     {                                                                                                                                      \ |  | ||||||
|         err_handler_(ex.what());                                                                                                           \ |  | ||||||
|     }                                                                                                                                      \ |  | ||||||
|     catch (...)                                                                                                                            \ |  | ||||||
|     {                                                                                                                                      \ |  | ||||||
|         err_handler_("Unknown exception in logger");                                                                                       \ |  | ||||||
|     } |  | ||||||
|  |  | ||||||
| // create logger with given name, sinks and the default pattern formatter |  | ||||||
| // all other ctors will call this one |  | ||||||
| template<typename It> |  | ||||||
| inline spdlog::logger::logger(std::string logger_name, It begin, It end) |  | ||||||
|     : name_(std::move(logger_name)) |  | ||||||
|     , sinks_(begin, end) |  | ||||||
| { |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // ctor with sinks as init list |  | ||||||
| inline spdlog::logger::logger(std::string logger_name, sinks_init_list sinks_list) |  | ||||||
|     : logger(std::move(logger_name), sinks_list.begin(), sinks_list.end()) |  | ||||||
| { |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // ctor with single sink |  | ||||||
| inline spdlog::logger::logger(std::string logger_name, spdlog::sink_ptr single_sink) |  | ||||||
|     : logger(std::move(logger_name), {std::move(single_sink)}) |  | ||||||
| { |  | ||||||
| } |  | ||||||
|  |  | ||||||
| inline spdlog::logger::~logger() = default; |  | ||||||
|  |  | ||||||
| inline void spdlog::logger::set_formatter(std::unique_ptr<spdlog::formatter> f) |  | ||||||
| { |  | ||||||
|     for (auto &sink : sinks_) |  | ||||||
|     { |  | ||||||
|         sink->set_formatter(f->clone()); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| inline void spdlog::logger::set_pattern(std::string pattern, pattern_time_type time_type) |  | ||||||
| { |  | ||||||
|     auto new_formatter = details::make_unique<spdlog::pattern_formatter>(std::move(pattern), time_type); |  | ||||||
|     set_formatter(std::move(new_formatter)); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| template<typename... Args> |  | ||||||
| inline void spdlog::logger::log(source_loc source, level::level_enum lvl, const char *fmt, const Args &... args) |  | ||||||
| { |  | ||||||
|     if (!should_log(lvl)) |  | ||||||
|     { |  | ||||||
|         return; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     try |  | ||||||
|     { |  | ||||||
|         using details::fmt_helper::to_string_view; |  | ||||||
|         fmt::memory_buffer buf; |  | ||||||
|         fmt::format_to(buf, fmt, args...); |  | ||||||
|         details::log_msg log_msg(source, &name_, lvl, to_string_view(buf)); |  | ||||||
|         sink_it_(log_msg); |  | ||||||
|     } |  | ||||||
|     SPDLOG_CATCH_AND_HANDLE |  | ||||||
| } |  | ||||||
|  |  | ||||||
| template<typename... Args> |  | ||||||
| inline void spdlog::logger::log(level::level_enum lvl, const char *fmt, const Args &... args) |  | ||||||
| { |  | ||||||
|     log(source_loc{}, lvl, fmt, args...); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| inline void spdlog::logger::log(source_loc source, level::level_enum lvl, const char *msg) |  | ||||||
| { |  | ||||||
|     if (!should_log(lvl)) |  | ||||||
|     { |  | ||||||
|         return; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     try |  | ||||||
|     { |  | ||||||
|         details::log_msg log_msg(source, &name_, lvl, spdlog::string_view_t(msg)); |  | ||||||
|         sink_it_(log_msg); |  | ||||||
|     } |  | ||||||
|     SPDLOG_CATCH_AND_HANDLE |  | ||||||
| } |  | ||||||
|  |  | ||||||
| inline void spdlog::logger::log(level::level_enum lvl, const char *msg) |  | ||||||
| { |  | ||||||
|     log(source_loc{}, lvl, msg); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| template<class T, typename std::enable_if<std::is_convertible<T, spdlog::string_view_t>::value, T>::type *> |  | ||||||
| inline void spdlog::logger::log(source_loc source, level::level_enum lvl, const T &msg) |  | ||||||
| { |  | ||||||
|     if (!should_log(lvl)) |  | ||||||
|     { |  | ||||||
|         return; |  | ||||||
|     } |  | ||||||
|     try |  | ||||||
|     { |  | ||||||
|         details::log_msg log_msg(source, &name_, lvl, msg); |  | ||||||
|         sink_it_(log_msg); |  | ||||||
|     } |  | ||||||
|     SPDLOG_CATCH_AND_HANDLE |  | ||||||
| } |  | ||||||
|  |  | ||||||
| template<class T, typename std::enable_if<std::is_convertible<T, spdlog::string_view_t>::value, T>::type *> |  | ||||||
| inline void spdlog::logger::log(level::level_enum lvl, const T &msg) |  | ||||||
| { |  | ||||||
|     log(source_loc{}, lvl, msg); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| template<class T, typename std::enable_if<!std::is_convertible<T, spdlog::string_view_t>::value, T>::type *> |  | ||||||
| inline void spdlog::logger::log(source_loc source, level::level_enum lvl, const T &msg) |  | ||||||
| { |  | ||||||
|     if (!should_log(lvl)) |  | ||||||
|     { |  | ||||||
|         return; |  | ||||||
|     } |  | ||||||
|     try |  | ||||||
|     { |  | ||||||
|         using details::fmt_helper::to_string_view; |  | ||||||
|         fmt::memory_buffer buf; |  | ||||||
|         fmt::format_to(buf, "{}", msg); |  | ||||||
|         details::log_msg log_msg(source, &name_, lvl, to_string_view(buf)); |  | ||||||
|         sink_it_(log_msg); |  | ||||||
|     } |  | ||||||
|     SPDLOG_CATCH_AND_HANDLE |  | ||||||
| } |  | ||||||
|  |  | ||||||
| template<class T, typename std::enable_if<!std::is_convertible<T, spdlog::string_view_t>::value, T>::type *> |  | ||||||
| inline void spdlog::logger::log(level::level_enum lvl, const T &msg) |  | ||||||
| { |  | ||||||
|     log(source_loc{}, lvl, msg); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| template<typename... Args> |  | ||||||
| inline void spdlog::logger::trace(const char *fmt, const Args &... args) |  | ||||||
| { |  | ||||||
|     log(level::trace, fmt, args...); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| template<typename... Args> |  | ||||||
| inline void spdlog::logger::debug(const char *fmt, const Args &... args) |  | ||||||
| { |  | ||||||
|     log(level::debug, fmt, args...); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| template<typename... Args> |  | ||||||
| inline void spdlog::logger::info(const char *fmt, const Args &... args) |  | ||||||
| { |  | ||||||
|     log(level::info, fmt, args...); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| template<typename... Args> |  | ||||||
| inline void spdlog::logger::warn(const char *fmt, const Args &... args) |  | ||||||
| { |  | ||||||
|     log(level::warn, fmt, args...); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| template<typename... Args> |  | ||||||
| inline void spdlog::logger::error(const char *fmt, const Args &... args) |  | ||||||
| { |  | ||||||
|     log(level::err, fmt, args...); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| template<typename... Args> |  | ||||||
| inline void spdlog::logger::critical(const char *fmt, const Args &... args) |  | ||||||
| { |  | ||||||
|     log(level::critical, fmt, args...); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| template<typename T> |  | ||||||
| inline void spdlog::logger::trace(const T &msg) |  | ||||||
| { |  | ||||||
|     log(level::trace, msg); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| template<typename T> |  | ||||||
| inline void spdlog::logger::debug(const T &msg) |  | ||||||
| { |  | ||||||
|     log(level::debug, msg); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| template<typename T> |  | ||||||
| inline void spdlog::logger::info(const T &msg) |  | ||||||
| { |  | ||||||
|     log(level::info, msg); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| template<typename T> |  | ||||||
| inline void spdlog::logger::warn(const T &msg) |  | ||||||
| { |  | ||||||
|     log(level::warn, msg); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| template<typename T> |  | ||||||
| inline void spdlog::logger::error(const T &msg) |  | ||||||
| { |  | ||||||
|     log(level::err, msg); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| template<typename T> |  | ||||||
| inline void spdlog::logger::critical(const T &msg) |  | ||||||
| { |  | ||||||
|     log(level::critical, msg); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| #ifdef SPDLOG_WCHAR_TO_UTF8_SUPPORT |  | ||||||
|  |  | ||||||
| inline void wbuf_to_utf8buf(const fmt::wmemory_buffer &wbuf, fmt::memory_buffer &target) |  | ||||||
| { |  | ||||||
|     int wbuf_size = static_cast<int>(wbuf.size()); |  | ||||||
|     if (wbuf_size == 0) |  | ||||||
|     { |  | ||||||
|         return; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     auto result_size = ::WideCharToMultiByte(CP_UTF8, 0, wbuf.data(), wbuf_size, NULL, 0, NULL, NULL); |  | ||||||
|  |  | ||||||
|     if (result_size > 0) |  | ||||||
|     { |  | ||||||
|         target.resize(result_size); |  | ||||||
|         ::WideCharToMultiByte(CP_UTF8, 0, wbuf.data(), wbuf_size, &target.data()[0], result_size, NULL, NULL); |  | ||||||
|     } |  | ||||||
|     else |  | ||||||
|     { |  | ||||||
|         throw spdlog::spdlog_ex(fmt::format("WideCharToMultiByte failed. Last error: {}", ::GetLastError())); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| template<typename... Args> |  | ||||||
| inline void spdlog::logger::log(source_loc source, level::level_enum lvl, const wchar_t *fmt, const Args &... args) |  | ||||||
| { |  | ||||||
|     if (!should_log(lvl)) |  | ||||||
|     { |  | ||||||
|         return; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     try |  | ||||||
|     { |  | ||||||
|         // format to wmemory_buffer and convert to utf8 |  | ||||||
|         using details::fmt_helper::to_string_view; |  | ||||||
|         fmt::wmemory_buffer wbuf; |  | ||||||
|         fmt::format_to(wbuf, fmt, args...); |  | ||||||
|         fmt::memory_buffer buf; |  | ||||||
|         wbuf_to_utf8buf(wbuf, buf); |  | ||||||
|         details::log_msg log_msg(source, &name_, lvl, to_string_view(buf)); |  | ||||||
|         sink_it_(log_msg); |  | ||||||
|     } |  | ||||||
|     SPDLOG_CATCH_AND_HANDLE |  | ||||||
| } |  | ||||||
|  |  | ||||||
| template<typename... Args> |  | ||||||
| inline void spdlog::logger::log(level::level_enum lvl, const wchar_t *fmt, const Args &... args) |  | ||||||
| { |  | ||||||
|     log(source_loc{}, lvl, fmt, args...); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| template<typename... Args> |  | ||||||
| inline void spdlog::logger::trace(const wchar_t *fmt, const Args &... args) |  | ||||||
| { |  | ||||||
|     log(level::trace, fmt, args...); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| template<typename... Args> |  | ||||||
| inline void spdlog::logger::debug(const wchar_t *fmt, const Args &... args) |  | ||||||
| { |  | ||||||
|     log(level::debug, fmt, args...); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| template<typename... Args> |  | ||||||
| inline void spdlog::logger::info(const wchar_t *fmt, const Args &... args) |  | ||||||
| { |  | ||||||
|     log(level::info, fmt, args...); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| template<typename... Args> |  | ||||||
| inline void spdlog::logger::warn(const wchar_t *fmt, const Args &... args) |  | ||||||
| { |  | ||||||
|     log(level::warn, fmt, args...); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| template<typename... Args> |  | ||||||
| inline void spdlog::logger::error(const wchar_t *fmt, const Args &... args) |  | ||||||
| { |  | ||||||
|     log(level::err, fmt, args...); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| template<typename... Args> |  | ||||||
| inline void spdlog::logger::critical(const wchar_t *fmt, const Args &... args) |  | ||||||
| { |  | ||||||
|     log(level::critical, fmt, args...); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| #endif // SPDLOG_WCHAR_TO_UTF8_SUPPORT |  | ||||||
|  |  | ||||||
| // |  | ||||||
| // name and level |  | ||||||
| // |  | ||||||
| inline const std::string &spdlog::logger::name() const |  | ||||||
| { |  | ||||||
|     return name_; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| inline void spdlog::logger::set_level(spdlog::level::level_enum log_level) |  | ||||||
| { |  | ||||||
|     level_.store(log_level); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| inline void spdlog::logger::set_error_handler(spdlog::log_err_handler err_handler) |  | ||||||
| { |  | ||||||
|     err_handler_ = std::move(err_handler); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| inline spdlog::log_err_handler spdlog::logger::error_handler() const |  | ||||||
| { |  | ||||||
|     return err_handler_; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| inline void spdlog::logger::flush() |  | ||||||
| { |  | ||||||
|     try |  | ||||||
|     { |  | ||||||
|         flush_(); |  | ||||||
|     } |  | ||||||
|     SPDLOG_CATCH_AND_HANDLE |  | ||||||
| } |  | ||||||
|  |  | ||||||
| inline void spdlog::logger::flush_on(level::level_enum log_level) |  | ||||||
| { |  | ||||||
|     flush_level_.store(log_level); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| inline spdlog::level::level_enum spdlog::logger::flush_level() const |  | ||||||
| { |  | ||||||
|     return static_cast<spdlog::level::level_enum>(flush_level_.load(std::memory_order_relaxed)); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| inline bool spdlog::logger::should_flush_(const details::log_msg &msg) |  | ||||||
| { |  | ||||||
|     auto flush_level = flush_level_.load(std::memory_order_relaxed); |  | ||||||
|     return (msg.level >= flush_level) && (msg.level != level::off); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| inline spdlog::level::level_enum spdlog::logger::default_level() |  | ||||||
| { |  | ||||||
|     return static_cast<spdlog::level::level_enum>(SPDLOG_ACTIVE_LEVEL); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| inline spdlog::level::level_enum spdlog::logger::level() const |  | ||||||
| { |  | ||||||
|     return static_cast<spdlog::level::level_enum>(level_.load(std::memory_order_relaxed)); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| inline bool spdlog::logger::should_log(spdlog::level::level_enum msg_level) const |  | ||||||
| { |  | ||||||
|     return msg_level >= level_.load(std::memory_order_relaxed); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // |  | ||||||
| // protected virtual called at end of each user log call (if enabled) by the |  | ||||||
| // line_logger |  | ||||||
| // |  | ||||||
| inline void spdlog::logger::sink_it_(details::log_msg &msg) |  | ||||||
| { |  | ||||||
| #if defined(SPDLOG_ENABLE_MESSAGE_COUNTER) |  | ||||||
|     incr_msg_counter_(msg); |  | ||||||
| #endif |  | ||||||
|     for (auto &sink : sinks_) |  | ||||||
|     { |  | ||||||
|         if (sink->should_log(msg.level)) |  | ||||||
|         { |  | ||||||
|             sink->log(msg); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     if (should_flush_(msg)) |  | ||||||
|     { |  | ||||||
|         flush_(); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| inline void spdlog::logger::flush_() |  | ||||||
| { |  | ||||||
|     for (auto &sink : sinks_) |  | ||||||
|     { |  | ||||||
|         sink->flush(); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| inline void spdlog::logger::default_err_handler_(const std::string &msg) |  | ||||||
| { |  | ||||||
|     auto now = time(nullptr); |  | ||||||
|     if (now - last_err_time_ < 60) |  | ||||||
|     { |  | ||||||
|         return; |  | ||||||
|     } |  | ||||||
|     last_err_time_ = now; |  | ||||||
|     auto tm_time = details::os::localtime(now); |  | ||||||
|     char date_buf[100]; |  | ||||||
|     std::strftime(date_buf, sizeof(date_buf), "%Y-%m-%d %H:%M:%S", &tm_time); |  | ||||||
|     fmt::print(stderr, "[*** LOG ERROR ***] [{}] [{}] {}\n", date_buf, name(), msg); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| inline void spdlog::logger::incr_msg_counter_(details::log_msg &msg) |  | ||||||
| { |  | ||||||
|     msg.msg_id = msg_counter_.fetch_add(1, std::memory_order_relaxed); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| inline const std::vector<spdlog::sink_ptr> &spdlog::logger::sinks() const |  | ||||||
| { |  | ||||||
|     return sinks_; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| inline std::vector<spdlog::sink_ptr> &spdlog::logger::sinks() |  | ||||||
| { |  | ||||||
|     return sinks_; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| inline std::shared_ptr<spdlog::logger> spdlog::logger::clone(std::string logger_name) |  | ||||||
| { |  | ||||||
|     auto cloned = std::make_shared<spdlog::logger>(std::move(logger_name), sinks_.begin(), sinks_.end()); |  | ||||||
|     cloned->set_level(this->level()); |  | ||||||
|     cloned->flush_on(this->flush_level()); |  | ||||||
|     cloned->set_error_handler(this->error_handler()); |  | ||||||
|     return cloned; |  | ||||||
| } |  | ||||||
| @@ -1,9 +1,7 @@ | |||||||
| #pragma once | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. | ||||||
|  |  | ||||||
| // |  | ||||||
| // Copyright(c) 2018 Gabi Melman. |  | ||||||
| // Distributed under the MIT License (http://opensource.org/licenses/MIT) | // Distributed under the MIT License (http://opensource.org/licenses/MIT) | ||||||
| // |  | ||||||
|  | #pragma once | ||||||
|  |  | ||||||
| // multi producer-multi consumer blocking queue. | // multi producer-multi consumer blocking queue. | ||||||
| // enqueue(..) - will block until room found to put the new message. | // enqueue(..) - will block until room found to put the new message. | ||||||
| @@ -27,8 +25,7 @@ public: | |||||||
|     using item_type = T; |     using item_type = T; | ||||||
|     explicit mpmc_blocking_queue(size_t max_items) |     explicit mpmc_blocking_queue(size_t max_items) | ||||||
|         : q_(max_items) |         : q_(max_items) | ||||||
|     { |     {} | ||||||
|     } |  | ||||||
|  |  | ||||||
| #ifndef __MINGW32__ | #ifndef __MINGW32__ | ||||||
|     // try to enqueue and block if no room left |     // try to enqueue and block if no room left | ||||||
| @@ -62,7 +59,8 @@ public: | |||||||
|             { |             { | ||||||
|                 return false; |                 return false; | ||||||
|             } |             } | ||||||
|             q_.pop_front(popped_item); |             popped_item = std::move(q_.front()); | ||||||
|  |             q_.pop_front(); | ||||||
|         } |         } | ||||||
|         pop_cv_.notify_one(); |         pop_cv_.notify_one(); | ||||||
|         return true; |         return true; | ||||||
| @@ -98,7 +96,8 @@ public: | |||||||
|         { |         { | ||||||
|             return false; |             return false; | ||||||
|         } |         } | ||||||
|         q_.pop_front(popped_item); |         popped_item = std::move(q_.front()); | ||||||
|  |         q_.pop_front(); | ||||||
|         pop_cv_.notify_one(); |         pop_cv_.notify_one(); | ||||||
|         return true; |         return true; | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -1,20 +1,19 @@ | |||||||
| // | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. | ||||||
| // Copyright(c) 2015 Gabi Melman. |  | ||||||
| // Distributed under the MIT License (http://opensource.org/licenses/MIT) | // Distributed under the MIT License (http://opensource.org/licenses/MIT) | ||||||
| // |  | ||||||
|  |  | ||||||
| #pragma once | #pragma once | ||||||
|  |  | ||||||
| #include <atomic> | #include <atomic> | ||||||
|  | #include <utility> | ||||||
| // null, no cost dummy "mutex" and dummy "atomic" int | // null, no cost dummy "mutex" and dummy "atomic" int | ||||||
|  |  | ||||||
| namespace spdlog { | namespace spdlog { | ||||||
| namespace details { | namespace details { | ||||||
| struct null_mutex | struct null_mutex | ||||||
| { | { | ||||||
|     void lock() {} |     void lock() const {} | ||||||
|     void unlock() {} |     void unlock() const {} | ||||||
|     bool try_lock() |     bool try_lock() const | ||||||
|     { |     { | ||||||
|         return true; |         return true; | ||||||
|     } |     } | ||||||
| @@ -25,19 +24,24 @@ struct null_atomic_int | |||||||
|     int value; |     int value; | ||||||
|     null_atomic_int() = default; |     null_atomic_int() = default; | ||||||
|  |  | ||||||
|     explicit null_atomic_int(int val) |     explicit null_atomic_int(int new_value) | ||||||
|         : value(val) |         : value(new_value) | ||||||
|     { |     {} | ||||||
|     } |  | ||||||
|  |  | ||||||
|     int load(std::memory_order) const |     int load(std::memory_order = std::memory_order_relaxed) const | ||||||
|     { |     { | ||||||
|         return value; |         return value; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     void store(int val) |     void store(int new_value, std::memory_order = std::memory_order_relaxed) | ||||||
|     { |     { | ||||||
|         value = val; |         value = new_value; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     int exchange(int new_value, std::memory_order = std::memory_order_relaxed) | ||||||
|  |     { | ||||||
|  |         std::swap(new_value, value); | ||||||
|  |         return new_value; // return value before the call | ||||||
|     } |     } | ||||||
| }; | }; | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										465
									
								
								third_party/spdlog/include/spdlog/details/os-inl.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										465
									
								
								third_party/spdlog/include/spdlog/details/os-inl.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,465 @@ | |||||||
|  | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. | ||||||
|  | // Distributed under the MIT License (http://opensource.org/licenses/MIT) | ||||||
|  |  | ||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #ifndef SPDLOG_HEADER_ONLY | ||||||
|  | #include "spdlog/details/os.h" | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #include "spdlog/common.h" | ||||||
|  |  | ||||||
|  | #include <algorithm> | ||||||
|  | #include <chrono> | ||||||
|  | #include <cstdio> | ||||||
|  | #include <cstdlib> | ||||||
|  | #include <cstring> | ||||||
|  | #include <ctime> | ||||||
|  | #include <string> | ||||||
|  | #include <thread> | ||||||
|  | #include <array> | ||||||
|  | #include <sys/stat.h> | ||||||
|  | #include <sys/types.h> | ||||||
|  |  | ||||||
|  | #ifdef _WIN32 | ||||||
|  |  | ||||||
|  | #ifndef NOMINMAX | ||||||
|  | #define NOMINMAX // prevent windows redefining min/max | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #ifndef WIN32_LEAN_AND_MEAN | ||||||
|  | #define WIN32_LEAN_AND_MEAN | ||||||
|  | #endif | ||||||
|  | #include <io.h>      // _get_osfhandle and _isatty support | ||||||
|  | #include <process.h> //  _get_pid support | ||||||
|  | #include <windows.h> | ||||||
|  |  | ||||||
|  | #ifdef __MINGW32__ | ||||||
|  | #include <share.h> | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #if defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) || defined(SPDLOG_WCHAR_FILENAMES) | ||||||
|  | #include <limits> | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #else // unix | ||||||
|  |  | ||||||
|  | #include <fcntl.h> | ||||||
|  | #include <unistd.h> | ||||||
|  |  | ||||||
|  | #ifdef __linux__ | ||||||
|  | #include <sys/syscall.h> //Use gettid() syscall under linux to get thread id | ||||||
|  |  | ||||||
|  | #elif defined(_AIX) | ||||||
|  | #include <pthread.h> // for pthread_getthreadid_np | ||||||
|  |  | ||||||
|  | #elif defined(__DragonFly__) || defined(__FreeBSD__) | ||||||
|  | #include <pthread_np.h> // for pthread_getthreadid_np | ||||||
|  |  | ||||||
|  | #elif defined(__NetBSD__) | ||||||
|  | #include <lwp.h> // for _lwp_self | ||||||
|  |  | ||||||
|  | #elif defined(__sun) | ||||||
|  | #include <thread.h> // for thr_self | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #endif // unix | ||||||
|  |  | ||||||
|  | #ifndef __has_feature      // Clang - feature checking macros. | ||||||
|  | #define __has_feature(x) 0 // Compatibility with non-clang compilers. | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | namespace spdlog { | ||||||
|  | namespace details { | ||||||
|  | namespace os { | ||||||
|  |  | ||||||
|  | SPDLOG_INLINE spdlog::log_clock::time_point now() SPDLOG_NOEXCEPT | ||||||
|  | { | ||||||
|  |  | ||||||
|  | #if defined __linux__ && defined SPDLOG_CLOCK_COARSE | ||||||
|  |     timespec ts; | ||||||
|  |     ::clock_gettime(CLOCK_REALTIME_COARSE, &ts); | ||||||
|  |     return std::chrono::time_point<log_clock, typename log_clock::duration>( | ||||||
|  |         std::chrono::duration_cast<typename log_clock::duration>(std::chrono::seconds(ts.tv_sec) + std::chrono::nanoseconds(ts.tv_nsec))); | ||||||
|  |  | ||||||
|  | #else | ||||||
|  |     return log_clock::now(); | ||||||
|  | #endif | ||||||
|  | } | ||||||
|  | SPDLOG_INLINE std::tm localtime(const std::time_t &time_tt) SPDLOG_NOEXCEPT | ||||||
|  | { | ||||||
|  |  | ||||||
|  | #ifdef _WIN32 | ||||||
|  |     std::tm tm; | ||||||
|  |     localtime_s(&tm, &time_tt); | ||||||
|  | #else | ||||||
|  |     std::tm tm; | ||||||
|  |     localtime_r(&time_tt, &tm); | ||||||
|  | #endif | ||||||
|  |     return tm; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | SPDLOG_INLINE std::tm localtime() SPDLOG_NOEXCEPT | ||||||
|  | { | ||||||
|  |     std::time_t now_t = time(nullptr); | ||||||
|  |     return localtime(now_t); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | SPDLOG_INLINE std::tm gmtime(const std::time_t &time_tt) SPDLOG_NOEXCEPT | ||||||
|  | { | ||||||
|  |  | ||||||
|  | #ifdef _WIN32 | ||||||
|  |     std::tm tm; | ||||||
|  |     gmtime_s(&tm, &time_tt); | ||||||
|  | #else | ||||||
|  |     std::tm tm; | ||||||
|  |     gmtime_r(&time_tt, &tm); | ||||||
|  | #endif | ||||||
|  |     return tm; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | SPDLOG_INLINE std::tm gmtime() SPDLOG_NOEXCEPT | ||||||
|  | { | ||||||
|  |     std::time_t now_t = time(nullptr); | ||||||
|  |     return gmtime(now_t); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | SPDLOG_INLINE void prevent_child_fd(FILE *f) | ||||||
|  | { | ||||||
|  |  | ||||||
|  | #ifdef _WIN32 | ||||||
|  | #if !defined(__cplusplus_winrt) | ||||||
|  |     auto file_handle = reinterpret_cast<HANDLE>(_get_osfhandle(_fileno(f))); | ||||||
|  |     if (!::SetHandleInformation(file_handle, HANDLE_FLAG_INHERIT, 0)) | ||||||
|  |         SPDLOG_THROW(spdlog_ex("SetHandleInformation failed", errno)); | ||||||
|  | #endif | ||||||
|  | #else | ||||||
|  |     auto fd = fileno(f); | ||||||
|  |     if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) | ||||||
|  |     { | ||||||
|  |         SPDLOG_THROW(spdlog_ex("fcntl with FD_CLOEXEC failed", errno)); | ||||||
|  |     } | ||||||
|  | #endif | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // fopen_s on non windows for writing | ||||||
|  | SPDLOG_INLINE bool fopen_s(FILE **fp, const filename_t &filename, const filename_t &mode) | ||||||
|  | { | ||||||
|  | #ifdef _WIN32 | ||||||
|  | #ifdef SPDLOG_WCHAR_FILENAMES | ||||||
|  |     *fp = _wfsopen((filename.c_str()), mode.c_str(), _SH_DENYNO); | ||||||
|  | #else | ||||||
|  |     *fp = _fsopen((filename.c_str()), mode.c_str(), _SH_DENYNO); | ||||||
|  | #endif | ||||||
|  | #else // unix | ||||||
|  |     *fp = fopen((filename.c_str()), mode.c_str()); | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #ifdef SPDLOG_PREVENT_CHILD_FD | ||||||
|  |     if (*fp != nullptr) | ||||||
|  |     { | ||||||
|  |         prevent_child_fd(*fp); | ||||||
|  |     } | ||||||
|  | #endif | ||||||
|  |     return *fp == nullptr; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | SPDLOG_INLINE int remove(const filename_t &filename) SPDLOG_NOEXCEPT | ||||||
|  | { | ||||||
|  | #if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES) | ||||||
|  |     return _wremove(filename.c_str()); | ||||||
|  | #else | ||||||
|  |     return std::remove(filename.c_str()); | ||||||
|  | #endif | ||||||
|  | } | ||||||
|  |  | ||||||
|  | SPDLOG_INLINE int remove_if_exists(const filename_t &filename) SPDLOG_NOEXCEPT | ||||||
|  | { | ||||||
|  |     return file_exists(filename) ? remove(filename) : 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | SPDLOG_INLINE int rename(const filename_t &filename1, const filename_t &filename2) SPDLOG_NOEXCEPT | ||||||
|  | { | ||||||
|  | #if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES) | ||||||
|  |     return _wrename(filename1.c_str(), filename2.c_str()); | ||||||
|  | #else | ||||||
|  |     return std::rename(filename1.c_str(), filename2.c_str()); | ||||||
|  | #endif | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Return true if file exists | ||||||
|  | SPDLOG_INLINE bool file_exists(const filename_t &filename) SPDLOG_NOEXCEPT | ||||||
|  | { | ||||||
|  | #ifdef _WIN32 | ||||||
|  | #ifdef SPDLOG_WCHAR_FILENAMES | ||||||
|  |     auto attribs = GetFileAttributesW(filename.c_str()); | ||||||
|  | #else | ||||||
|  |     auto attribs = GetFileAttributesA(filename.c_str()); | ||||||
|  | #endif | ||||||
|  |     return (attribs != INVALID_FILE_ATTRIBUTES && !(attribs & FILE_ATTRIBUTE_DIRECTORY)); | ||||||
|  | #else // common linux/unix all have the stat system call | ||||||
|  |     struct stat buffer; | ||||||
|  |     return (::stat(filename.c_str(), &buffer) == 0); | ||||||
|  | #endif | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Return file size according to open FILE* object | ||||||
|  | SPDLOG_INLINE size_t filesize(FILE *f) | ||||||
|  | { | ||||||
|  |     if (f == nullptr) | ||||||
|  |     { | ||||||
|  |         SPDLOG_THROW(spdlog_ex("Failed getting file size. fd is null")); | ||||||
|  |     } | ||||||
|  | #if defined(_WIN32) && !defined(__CYGWIN__) | ||||||
|  |     int fd = _fileno(f); | ||||||
|  | #if _WIN64 // 64 bits | ||||||
|  |     __int64 ret = _filelengthi64(fd); | ||||||
|  |     if (ret >= 0) | ||||||
|  |     { | ||||||
|  |         return static_cast<size_t>(ret); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | #else // windows 32 bits | ||||||
|  |     long ret = _filelength(fd); | ||||||
|  |     if (ret >= 0) | ||||||
|  |     { | ||||||
|  |         return static_cast<size_t>(ret); | ||||||
|  |     } | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #else // unix | ||||||
|  |     int fd = fileno(f); | ||||||
|  | // 64 bits(but not in osx or cygwin, where fstat64 is deprecated) | ||||||
|  | #if (defined(__linux__) || defined(__sun) || defined(_AIX)) && (defined(__LP64__) || defined(_LP64)) | ||||||
|  |     struct stat64 st; | ||||||
|  |     if (::fstat64(fd, &st) == 0) | ||||||
|  |     { | ||||||
|  |         return static_cast<size_t>(st.st_size); | ||||||
|  |     } | ||||||
|  | #else // unix 32 bits or cygwin | ||||||
|  |     struct stat st; | ||||||
|  |  | ||||||
|  |     if (::fstat(fd, &st) == 0) | ||||||
|  |     { | ||||||
|  |         return static_cast<size_t>(st.st_size); | ||||||
|  |     } | ||||||
|  | #endif | ||||||
|  | #endif | ||||||
|  |     SPDLOG_THROW(spdlog_ex("Failed getting file size from fd", errno)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Return utc offset in minutes or throw spdlog_ex on failure | ||||||
|  | SPDLOG_INLINE int utc_minutes_offset(const std::tm &tm) | ||||||
|  | { | ||||||
|  |  | ||||||
|  | #ifdef _WIN32 | ||||||
|  | #if _WIN32_WINNT < _WIN32_WINNT_WS08 | ||||||
|  |     TIME_ZONE_INFORMATION tzinfo; | ||||||
|  |     auto rv = GetTimeZoneInformation(&tzinfo); | ||||||
|  | #else | ||||||
|  |     DYNAMIC_TIME_ZONE_INFORMATION tzinfo; | ||||||
|  |     auto rv = GetDynamicTimeZoneInformation(&tzinfo); | ||||||
|  | #endif | ||||||
|  |     if (rv == TIME_ZONE_ID_INVALID) | ||||||
|  |         SPDLOG_THROW(spdlog::spdlog_ex("Failed getting timezone info. ", errno)); | ||||||
|  |  | ||||||
|  |     int offset = -tzinfo.Bias; | ||||||
|  |     if (tm.tm_isdst) | ||||||
|  |     { | ||||||
|  |         offset -= tzinfo.DaylightBias; | ||||||
|  |     } | ||||||
|  |     else | ||||||
|  |     { | ||||||
|  |         offset -= tzinfo.StandardBias; | ||||||
|  |     } | ||||||
|  |     return offset; | ||||||
|  | #else | ||||||
|  |  | ||||||
|  | #if defined(sun) || defined(__sun) || defined(_AIX) | ||||||
|  |     // 'tm_gmtoff' field is BSD extension and it's missing on SunOS/Solaris | ||||||
|  |     struct helper | ||||||
|  |     { | ||||||
|  |         static long int calculate_gmt_offset(const std::tm &localtm = details::os::localtime(), const std::tm &gmtm = details::os::gmtime()) | ||||||
|  |         { | ||||||
|  |             int local_year = localtm.tm_year + (1900 - 1); | ||||||
|  |             int gmt_year = gmtm.tm_year + (1900 - 1); | ||||||
|  |  | ||||||
|  |             long int days = ( | ||||||
|  |                 // difference in day of year | ||||||
|  |                 localtm.tm_yday - | ||||||
|  |                 gmtm.tm_yday | ||||||
|  |  | ||||||
|  |                 // + intervening leap days | ||||||
|  |                 + ((local_year >> 2) - (gmt_year >> 2)) - (local_year / 100 - gmt_year / 100) + | ||||||
|  |                 ((local_year / 100 >> 2) - (gmt_year / 100 >> 2)) | ||||||
|  |  | ||||||
|  |                 // + difference in years * 365 */ | ||||||
|  |                 + (long int)(local_year - gmt_year) * 365); | ||||||
|  |  | ||||||
|  |             long int hours = (24 * days) + (localtm.tm_hour - gmtm.tm_hour); | ||||||
|  |             long int mins = (60 * hours) + (localtm.tm_min - gmtm.tm_min); | ||||||
|  |             long int secs = (60 * mins) + (localtm.tm_sec - gmtm.tm_sec); | ||||||
|  |  | ||||||
|  |             return secs; | ||||||
|  |         } | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     auto offset_seconds = helper::calculate_gmt_offset(tm); | ||||||
|  | #else | ||||||
|  |     auto offset_seconds = tm.tm_gmtoff; | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  |     return static_cast<int>(offset_seconds / 60); | ||||||
|  | #endif | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Return current thread id as size_t | ||||||
|  | // It exists because the std::this_thread::get_id() is much slower(especially | ||||||
|  | // under VS 2013) | ||||||
|  | SPDLOG_INLINE size_t _thread_id() SPDLOG_NOEXCEPT | ||||||
|  | { | ||||||
|  | #ifdef _WIN32 | ||||||
|  |     return static_cast<size_t>(::GetCurrentThreadId()); | ||||||
|  | #elif defined(__linux__) | ||||||
|  | #if defined(__ANDROID__) && defined(__ANDROID_API__) && (__ANDROID_API__ < 21) | ||||||
|  | #define SYS_gettid __NR_gettid | ||||||
|  | #endif | ||||||
|  |     return static_cast<size_t>(syscall(SYS_gettid)); | ||||||
|  | #elif defined(_AIX) || defined(__DragonFly__) || defined(__FreeBSD__) | ||||||
|  |     return static_cast<size_t>(pthread_getthreadid_np()); | ||||||
|  | #elif defined(__NetBSD__) | ||||||
|  |     return static_cast<size_t>(_lwp_self()); | ||||||
|  | #elif defined(__OpenBSD__) | ||||||
|  |     return static_cast<size_t>(getthrid()); | ||||||
|  | #elif defined(__sun) | ||||||
|  |     return static_cast<size_t>(thr_self()); | ||||||
|  | #elif __APPLE__ | ||||||
|  |     uint64_t tid; | ||||||
|  |     pthread_threadid_np(nullptr, &tid); | ||||||
|  |     return static_cast<size_t>(tid); | ||||||
|  | #else // Default to standard C++11 (other Unix) | ||||||
|  |     return static_cast<size_t>(std::hash<std::thread::id>()(std::this_thread::get_id())); | ||||||
|  | #endif | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Return current thread id as size_t (from thread local storage) | ||||||
|  | SPDLOG_INLINE size_t thread_id() SPDLOG_NOEXCEPT | ||||||
|  | { | ||||||
|  | #if defined(SPDLOG_NO_TLS) | ||||||
|  |     return _thread_id(); | ||||||
|  | #else // cache thread id in tls | ||||||
|  |     static thread_local const size_t tid = _thread_id(); | ||||||
|  |     return tid; | ||||||
|  | #endif | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // This is avoid msvc issue in sleep_for that happens if the clock changes. | ||||||
|  | // See https://github.com/gabime/spdlog/issues/609 | ||||||
|  | SPDLOG_INLINE void sleep_for_millis(int milliseconds) SPDLOG_NOEXCEPT | ||||||
|  | { | ||||||
|  | #if defined(_WIN32) | ||||||
|  |     ::Sleep(milliseconds); | ||||||
|  | #else | ||||||
|  |     std::this_thread::sleep_for(std::chrono::milliseconds(milliseconds)); | ||||||
|  | #endif | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // wchar support for windows file names (SPDLOG_WCHAR_FILENAMES must be defined) | ||||||
|  | #if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES) | ||||||
|  | SPDLOG_INLINE std::string filename_to_str(const filename_t &filename) | ||||||
|  | { | ||||||
|  |     memory_buf_t buf; | ||||||
|  |     wstr_to_utf8buf(filename, buf); | ||||||
|  |     return fmt::to_string(buf); | ||||||
|  | } | ||||||
|  | #else | ||||||
|  | SPDLOG_INLINE std::string filename_to_str(const filename_t &filename) | ||||||
|  | { | ||||||
|  |     return filename; | ||||||
|  | } | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | SPDLOG_INLINE int pid() SPDLOG_NOEXCEPT | ||||||
|  | { | ||||||
|  |  | ||||||
|  | #ifdef _WIN32 | ||||||
|  |     return static_cast<int>(::GetCurrentProcessId()); | ||||||
|  | #else | ||||||
|  |     return static_cast<int>(::getpid()); | ||||||
|  | #endif | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Determine if the terminal supports colors | ||||||
|  | // Source: https://github.com/agauniyal/rang/ | ||||||
|  | SPDLOG_INLINE bool is_color_terminal() SPDLOG_NOEXCEPT | ||||||
|  | { | ||||||
|  | #ifdef _WIN32 | ||||||
|  |     return true; | ||||||
|  | #else | ||||||
|  |     static constexpr std::array<const char *, 14> Terms = { | ||||||
|  |         {"ansi", "color", "console", "cygwin", "gnome", "konsole", "kterm", "linux", "msys", "putty", "rxvt", "screen", "vt100", "xterm"}}; | ||||||
|  |  | ||||||
|  |     const char *env_p = std::getenv("TERM"); | ||||||
|  |     if (env_p == nullptr) | ||||||
|  |     { | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     static const bool result = | ||||||
|  |         std::any_of(std::begin(Terms), std::end(Terms), [&](const char *term) { return std::strstr(env_p, term) != nullptr; }); | ||||||
|  |     return result; | ||||||
|  | #endif | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Detrmine if the terminal attached | ||||||
|  | // Source: https://github.com/agauniyal/rang/ | ||||||
|  | SPDLOG_INLINE bool in_terminal(FILE *file) SPDLOG_NOEXCEPT | ||||||
|  | { | ||||||
|  |  | ||||||
|  | #ifdef _WIN32 | ||||||
|  |     return _isatty(_fileno(file)) != 0; | ||||||
|  | #else | ||||||
|  |     return isatty(fileno(file)) != 0; | ||||||
|  | #endif | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #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) | ||||||
|  | { | ||||||
|  |     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")); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     int wstr_size = static_cast<int>(wstr.size()); | ||||||
|  |     if (wstr_size == 0) | ||||||
|  |     { | ||||||
|  |         target.resize(0); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     int result_size = static_cast<int>(target.capacity()); | ||||||
|  |     if ((wstr_size + 1) * 2 > result_size) | ||||||
|  |     { | ||||||
|  |         result_size = ::WideCharToMultiByte(CP_UTF8, 0, wstr.data(), wstr_size, NULL, 0, NULL, NULL); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (result_size > 0) | ||||||
|  |     { | ||||||
|  |         target.resize(result_size); | ||||||
|  |         result_size = ::WideCharToMultiByte(CP_UTF8, 0, wstr.data(), wstr_size, target.data(), result_size, NULL, NULL); | ||||||
|  |  | ||||||
|  |         if (result_size > 0) | ||||||
|  |         { | ||||||
|  |             target.resize(result_size); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     SPDLOG_THROW(spdlog::spdlog_ex(fmt::format("WideCharToMultiByte failed. Last error: {}", ::GetLastError()))); | ||||||
|  | } | ||||||
|  | #endif // (defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) || defined(SPDLOG_WCHAR_FILENAMES)) && defined(_WIN32) | ||||||
|  |  | ||||||
|  | } // namespace os | ||||||
|  | } // namespace details | ||||||
|  | } // namespace spdlog | ||||||
							
								
								
									
										395
									
								
								third_party/spdlog/include/spdlog/details/os.h
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										395
									
								
								third_party/spdlog/include/spdlog/details/os.h
									
									
									
									
										vendored
									
									
								
							| @@ -1,112 +1,24 @@ | |||||||
| // | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. | ||||||
| // Copyright(c) 2015 Gabi Melman. |  | ||||||
| // Distributed under the MIT License (http://opensource.org/licenses/MIT) | // Distributed under the MIT License (http://opensource.org/licenses/MIT) | ||||||
| // |  | ||||||
| #pragma once | #pragma once | ||||||
|  |  | ||||||
| #include "../common.h" | #include "spdlog/common.h" | ||||||
|  | #include <ctime> // std::time_t | ||||||
| #include <algorithm> |  | ||||||
| #include <chrono> |  | ||||||
| #include <cstdio> |  | ||||||
| #include <cstdlib> |  | ||||||
| #include <cstring> |  | ||||||
| #include <ctime> |  | ||||||
| #include <functional> |  | ||||||
| #include <string> |  | ||||||
| #include <sys/stat.h> |  | ||||||
| #include <sys/types.h> |  | ||||||
| #include <thread> |  | ||||||
|  |  | ||||||
| #ifdef _WIN32 |  | ||||||
|  |  | ||||||
| #ifndef NOMINMAX |  | ||||||
| #define NOMINMAX // prevent windows redefining min/max |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| #ifndef WIN32_LEAN_AND_MEAN |  | ||||||
| #define WIN32_LEAN_AND_MEAN |  | ||||||
| #endif |  | ||||||
| #include <io.h>      // _get_osfhandle and _isatty support |  | ||||||
| #include <process.h> //  _get_pid support |  | ||||||
| #include <windows.h> |  | ||||||
|  |  | ||||||
| #ifdef __MINGW32__ |  | ||||||
| #include <share.h> |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| #else // unix |  | ||||||
|  |  | ||||||
| #include <fcntl.h> |  | ||||||
| #include <unistd.h> |  | ||||||
|  |  | ||||||
| #ifdef __linux__ |  | ||||||
| #include <sys/syscall.h> //Use gettid() syscall under linux to get thread id |  | ||||||
|  |  | ||||||
| #elif __FreeBSD__ |  | ||||||
| #include <sys/thr.h> //Use thr_self() syscall under FreeBSD to get thread id |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| #endif // unix |  | ||||||
|  |  | ||||||
| #ifndef __has_feature      // Clang - feature checking macros. |  | ||||||
| #define __has_feature(x) 0 // Compatibility with non-clang compilers. |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| namespace spdlog { | namespace spdlog { | ||||||
| namespace details { | namespace details { | ||||||
| namespace os { | namespace os { | ||||||
|  |  | ||||||
| inline spdlog::log_clock::time_point now() SPDLOG_NOEXCEPT | spdlog::log_clock::time_point now() SPDLOG_NOEXCEPT; | ||||||
| { |  | ||||||
|  |  | ||||||
| #if defined __linux__ && defined SPDLOG_CLOCK_COARSE | std::tm localtime(const std::time_t &time_tt) SPDLOG_NOEXCEPT; | ||||||
|     timespec ts; |  | ||||||
|     ::clock_gettime(CLOCK_REALTIME_COARSE, &ts); |  | ||||||
|     return std::chrono::time_point<log_clock, typename log_clock::duration>( |  | ||||||
|         std::chrono::duration_cast<typename log_clock::duration>(std::chrono::seconds(ts.tv_sec) + std::chrono::nanoseconds(ts.tv_nsec))); |  | ||||||
|  |  | ||||||
| #else | std::tm localtime() SPDLOG_NOEXCEPT; | ||||||
|     return log_clock::now(); |  | ||||||
| #endif |  | ||||||
| } |  | ||||||
| inline std::tm localtime(const std::time_t &time_tt) SPDLOG_NOEXCEPT |  | ||||||
| { |  | ||||||
|  |  | ||||||
| #ifdef _WIN32 | std::tm gmtime(const std::time_t &time_tt) SPDLOG_NOEXCEPT; | ||||||
|     std::tm tm; |  | ||||||
|     localtime_s(&tm, &time_tt); |  | ||||||
| #else |  | ||||||
|     std::tm tm; |  | ||||||
|     localtime_r(&time_tt, &tm); |  | ||||||
| #endif |  | ||||||
|     return tm; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| inline std::tm localtime() SPDLOG_NOEXCEPT | std::tm gmtime() SPDLOG_NOEXCEPT; | ||||||
| { |  | ||||||
|     std::time_t now_t = time(nullptr); |  | ||||||
|     return localtime(now_t); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| inline std::tm gmtime(const std::time_t &time_tt) SPDLOG_NOEXCEPT |  | ||||||
| { |  | ||||||
|  |  | ||||||
| #ifdef _WIN32 |  | ||||||
|     std::tm tm; |  | ||||||
|     gmtime_s(&tm, &time_tt); |  | ||||||
| #else |  | ||||||
|     std::tm tm; |  | ||||||
|     gmtime_r(&time_tt, &tm); |  | ||||||
| #endif |  | ||||||
|     return tm; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| inline std::tm gmtime() SPDLOG_NOEXCEPT |  | ||||||
| { |  | ||||||
|     std::time_t now_t = time(nullptr); |  | ||||||
|     return gmtime(now_t); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // eol definition | // eol definition | ||||||
| #if !defined(SPDLOG_EOL) | #if !defined(SPDLOG_EOL) | ||||||
| @@ -121,301 +33,66 @@ SPDLOG_CONSTEXPR static const char *default_eol = SPDLOG_EOL; | |||||||
|  |  | ||||||
| // folder separator | // folder separator | ||||||
| #ifdef _WIN32 | #ifdef _WIN32 | ||||||
| SPDLOG_CONSTEXPR static const char folder_sep = '\\'; | const char folder_sep = '\\'; | ||||||
| #else | #else | ||||||
| SPDLOG_CONSTEXPR static const char folder_sep = '/'; | SPDLOG_CONSTEXPR static const char folder_sep = '/'; | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| inline void prevent_child_fd(FILE *f) | void prevent_child_fd(FILE *f); | ||||||
| { |  | ||||||
|  |  | ||||||
| #ifdef _WIN32 |  | ||||||
| #if !defined(__cplusplus_winrt) |  | ||||||
|     auto file_handle = (HANDLE)_get_osfhandle(_fileno(f)); |  | ||||||
|     if (!::SetHandleInformation(file_handle, HANDLE_FLAG_INHERIT, 0)) |  | ||||||
|         throw spdlog_ex("SetHandleInformation failed", errno); |  | ||||||
| #endif |  | ||||||
| #else |  | ||||||
|     auto fd = fileno(f); |  | ||||||
|     if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) |  | ||||||
|     { |  | ||||||
|         throw spdlog_ex("fcntl with FD_CLOEXEC failed", errno); |  | ||||||
|     } |  | ||||||
| #endif |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // fopen_s on non windows for writing | // fopen_s on non windows for writing | ||||||
| inline 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); | ||||||
| { |  | ||||||
| #ifdef _WIN32 |  | ||||||
| #ifdef SPDLOG_WCHAR_FILENAMES |  | ||||||
|     *fp = _wfsopen((filename.c_str()), mode.c_str(), _SH_DENYNO); |  | ||||||
| #else |  | ||||||
|     *fp = _fsopen((filename.c_str()), mode.c_str(), _SH_DENYNO); |  | ||||||
| #endif |  | ||||||
| #else // unix |  | ||||||
|     *fp = fopen((filename.c_str()), mode.c_str()); |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| #ifdef SPDLOG_PREVENT_CHILD_FD | // Remove filename. return 0 on success | ||||||
|     if (*fp != nullptr) | int remove(const filename_t &filename) SPDLOG_NOEXCEPT; | ||||||
|     { |  | ||||||
|         prevent_child_fd(*fp); |  | ||||||
|     } |  | ||||||
| #endif |  | ||||||
|     return *fp == nullptr; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| inline int remove(const filename_t &filename) SPDLOG_NOEXCEPT | // Remove file if exists. return 0 on success | ||||||
| { | // Note: Non atomic (might return failure to delete if concurrently deleted by other process/thread) | ||||||
| #if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES) | int remove_if_exists(const filename_t &filename) SPDLOG_NOEXCEPT; | ||||||
|     return _wremove(filename.c_str()); |  | ||||||
| #else |  | ||||||
|     return std::remove(filename.c_str()); |  | ||||||
| #endif |  | ||||||
| } |  | ||||||
|  |  | ||||||
| inline int rename(const filename_t &filename1, const filename_t &filename2) SPDLOG_NOEXCEPT | int rename(const filename_t &filename1, const filename_t &filename2) SPDLOG_NOEXCEPT; | ||||||
| { |  | ||||||
| #if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES) |  | ||||||
|     return _wrename(filename1.c_str(), filename2.c_str()); |  | ||||||
| #else |  | ||||||
|     return std::rename(filename1.c_str(), filename2.c_str()); |  | ||||||
| #endif |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Return if file exists | // Return if file exists. | ||||||
| inline bool file_exists(const filename_t &filename) SPDLOG_NOEXCEPT | bool file_exists(const filename_t &filename) SPDLOG_NOEXCEPT; | ||||||
| { |  | ||||||
| #ifdef _WIN32 |  | ||||||
| #ifdef SPDLOG_WCHAR_FILENAMES |  | ||||||
|     auto attribs = GetFileAttributesW(filename.c_str()); |  | ||||||
| #else |  | ||||||
|     auto attribs = GetFileAttributesA(filename.c_str()); |  | ||||||
| #endif |  | ||||||
|     return (attribs != INVALID_FILE_ATTRIBUTES && !(attribs & FILE_ATTRIBUTE_DIRECTORY)); |  | ||||||
| #else // common linux/unix all have the stat system call |  | ||||||
|     struct stat buffer; |  | ||||||
|     return (stat(filename.c_str(), &buffer) == 0); |  | ||||||
| #endif |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Return file size according to open FILE* object | // Return file size according to open FILE* object | ||||||
| inline size_t filesize(FILE *f) | size_t filesize(FILE *f); | ||||||
| { |  | ||||||
|     if (f == nullptr) |  | ||||||
|     { |  | ||||||
|         throw spdlog_ex("Failed getting file size. fd is null"); |  | ||||||
|     } |  | ||||||
| #if defined(_WIN32) && !defined(__CYGWIN__) |  | ||||||
|     int fd = _fileno(f); |  | ||||||
| #if _WIN64 // 64 bits |  | ||||||
|     __int64 ret = _filelengthi64(fd); |  | ||||||
|     if (ret >= 0) |  | ||||||
|     { |  | ||||||
|         return static_cast<size_t>(ret); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
| #else // windows 32 bits |  | ||||||
|     long ret = _filelength(fd); |  | ||||||
|     if (ret >= 0) |  | ||||||
|     { |  | ||||||
|         return static_cast<size_t>(ret); |  | ||||||
|     } |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| #else // unix |  | ||||||
|     int fd = fileno(f); |  | ||||||
| // 64 bits(but not in osx or cygwin, where fstat64 is deprecated) |  | ||||||
| #if !defined(__FreeBSD__) && !defined(__APPLE__) && (defined(__x86_64__) || defined(__ppc64__)) && !defined(__CYGWIN__) |  | ||||||
|     struct stat64 st; |  | ||||||
|     if (fstat64(fd, &st) == 0) |  | ||||||
|     { |  | ||||||
|         return static_cast<size_t>(st.st_size); |  | ||||||
|     } |  | ||||||
| #else // unix 32 bits or cygwin |  | ||||||
|     struct stat st; |  | ||||||
|  |  | ||||||
|     if (fstat(fd, &st) == 0) |  | ||||||
|     { |  | ||||||
|         return static_cast<size_t>(st.st_size); |  | ||||||
|     } |  | ||||||
| #endif |  | ||||||
| #endif |  | ||||||
|     throw spdlog_ex("Failed getting file size from fd", errno); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Return utc offset in minutes or throw spdlog_ex on failure | // Return utc offset in minutes or throw spdlog_ex on failure | ||||||
| inline int utc_minutes_offset(const std::tm &tm = details::os::localtime()) | int utc_minutes_offset(const std::tm &tm = details::os::localtime()); | ||||||
| { |  | ||||||
|  |  | ||||||
| #ifdef _WIN32 |  | ||||||
| #if _WIN32_WINNT < _WIN32_WINNT_WS08 |  | ||||||
|     TIME_ZONE_INFORMATION tzinfo; |  | ||||||
|     auto rv = GetTimeZoneInformation(&tzinfo); |  | ||||||
| #else |  | ||||||
|     DYNAMIC_TIME_ZONE_INFORMATION tzinfo; |  | ||||||
|     auto rv = GetDynamicTimeZoneInformation(&tzinfo); |  | ||||||
| #endif |  | ||||||
|     if (rv == TIME_ZONE_ID_INVALID) |  | ||||||
|         throw spdlog::spdlog_ex("Failed getting timezone info. ", errno); |  | ||||||
|  |  | ||||||
|     int offset = -tzinfo.Bias; |  | ||||||
|     if (tm.tm_isdst) |  | ||||||
|     { |  | ||||||
|         offset -= tzinfo.DaylightBias; |  | ||||||
|     } |  | ||||||
|     else |  | ||||||
|     { |  | ||||||
|         offset -= tzinfo.StandardBias; |  | ||||||
|     } |  | ||||||
|     return offset; |  | ||||||
| #else |  | ||||||
|  |  | ||||||
| #if defined(sun) || defined(__sun) || defined(_AIX) |  | ||||||
|     // 'tm_gmtoff' field is BSD extension and it's missing on SunOS/Solaris |  | ||||||
|     struct helper |  | ||||||
|     { |  | ||||||
|         static long int calculate_gmt_offset(const std::tm &localtm = details::os::localtime(), const std::tm &gmtm = details::os::gmtime()) |  | ||||||
|         { |  | ||||||
|             int local_year = localtm.tm_year + (1900 - 1); |  | ||||||
|             int gmt_year = gmtm.tm_year + (1900 - 1); |  | ||||||
|  |  | ||||||
|             long int days = ( |  | ||||||
|                 // difference in day of year |  | ||||||
|                 localtm.tm_yday - |  | ||||||
|                 gmtm.tm_yday |  | ||||||
|  |  | ||||||
|                 // + intervening leap days |  | ||||||
|                 + ((local_year >> 2) - (gmt_year >> 2)) - (local_year / 100 - gmt_year / 100) + |  | ||||||
|                 ((local_year / 100 >> 2) - (gmt_year / 100 >> 2)) |  | ||||||
|  |  | ||||||
|                 // + difference in years * 365 */ |  | ||||||
|                 + (long int)(local_year - gmt_year) * 365); |  | ||||||
|  |  | ||||||
|             long int hours = (24 * days) + (localtm.tm_hour - gmtm.tm_hour); |  | ||||||
|             long int mins = (60 * hours) + (localtm.tm_min - gmtm.tm_min); |  | ||||||
|             long int secs = (60 * mins) + (localtm.tm_sec - gmtm.tm_sec); |  | ||||||
|  |  | ||||||
|             return secs; |  | ||||||
|         } |  | ||||||
|     }; |  | ||||||
|  |  | ||||||
|     auto offset_seconds = helper::calculate_gmt_offset(tm); |  | ||||||
| #else |  | ||||||
|     auto offset_seconds = tm.tm_gmtoff; |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
|     return static_cast<int>(offset_seconds / 60); |  | ||||||
| #endif |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Return current thread id as size_t | // Return current thread id as size_t | ||||||
| // It exists because the std::this_thread::get_id() is much slower(especially | // It exists because the std::this_thread::get_id() is much slower(especially | ||||||
| // under VS 2013) | // under VS 2013) | ||||||
| inline size_t _thread_id() SPDLOG_NOEXCEPT | size_t _thread_id() SPDLOG_NOEXCEPT; | ||||||
| { |  | ||||||
| #ifdef _WIN32 |  | ||||||
|     return static_cast<size_t>(::GetCurrentThreadId()); |  | ||||||
| #elif __linux__ |  | ||||||
| #if defined(__ANDROID__) && defined(__ANDROID_API__) && (__ANDROID_API__ < 21) |  | ||||||
| #define SYS_gettid __NR_gettid |  | ||||||
| #endif |  | ||||||
|     return static_cast<size_t>(syscall(SYS_gettid)); |  | ||||||
| #elif __FreeBSD__ |  | ||||||
|     long tid; |  | ||||||
|     thr_self(&tid); |  | ||||||
|     return static_cast<size_t>(tid); |  | ||||||
| #elif __APPLE__ |  | ||||||
|     uint64_t tid; |  | ||||||
|     pthread_threadid_np(nullptr, &tid); |  | ||||||
|     return static_cast<size_t>(tid); |  | ||||||
| #else // Default to standard C++11 (other Unix) |  | ||||||
|     return static_cast<size_t>(std::hash<std::thread::id>()(std::this_thread::get_id())); |  | ||||||
| #endif |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Return current thread id as size_t (from thread local storage) | // Return current thread id as size_t (from thread local storage) | ||||||
| inline size_t thread_id() SPDLOG_NOEXCEPT | size_t thread_id() SPDLOG_NOEXCEPT; | ||||||
| { |  | ||||||
| #if defined(SPDLOG_NO_TLS) |  | ||||||
|     return _thread_id(); |  | ||||||
| #else // cache thread id in tls |  | ||||||
|     static thread_local const size_t tid = _thread_id(); |  | ||||||
|     return tid; |  | ||||||
| #endif |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // This is avoid msvc issue in sleep_for that happens if the clock changes. | // This is avoid msvc issue in sleep_for that happens if the clock changes. | ||||||
| // See https://github.com/gabime/spdlog/issues/609 | // See https://github.com/gabime/spdlog/issues/609 | ||||||
| inline void sleep_for_millis(int milliseconds) SPDLOG_NOEXCEPT | void sleep_for_millis(int milliseconds) SPDLOG_NOEXCEPT; | ||||||
| { |  | ||||||
| #if defined(_WIN32) |  | ||||||
|     ::Sleep(milliseconds); |  | ||||||
| #else |  | ||||||
|     std::this_thread::sleep_for(std::chrono::milliseconds(milliseconds)); |  | ||||||
| #endif |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // wchar support for windows file names (SPDLOG_WCHAR_FILENAMES must be defined) | std::string filename_to_str(const filename_t &filename); | ||||||
| #if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES) |  | ||||||
| #define SPDLOG_FILENAME_T(s) L##s |  | ||||||
| inline std::string filename_to_str(const filename_t &filename) |  | ||||||
| { |  | ||||||
|     std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> c; |  | ||||||
|     return c.to_bytes(filename); |  | ||||||
| } |  | ||||||
| #else |  | ||||||
| #define SPDLOG_FILENAME_T(s) s |  | ||||||
| inline std::string filename_to_str(const filename_t &filename) |  | ||||||
| { |  | ||||||
|     return filename; |  | ||||||
| } |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| inline int pid() | int pid() SPDLOG_NOEXCEPT; | ||||||
| { |  | ||||||
|  |  | ||||||
| #ifdef _WIN32 |  | ||||||
|     return static_cast<int>(::GetCurrentProcessId()); |  | ||||||
| #else |  | ||||||
|     return static_cast<int>(::getpid()); |  | ||||||
| #endif |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Determine if the terminal supports colors | // Determine if the terminal supports colors | ||||||
| // Source: https://github.com/agauniyal/rang/ | // Source: https://github.com/agauniyal/rang/ | ||||||
| inline bool is_color_terminal() SPDLOG_NOEXCEPT | bool is_color_terminal() SPDLOG_NOEXCEPT; | ||||||
| { |  | ||||||
| #ifdef _WIN32 |  | ||||||
|     return true; |  | ||||||
| #else |  | ||||||
|     static constexpr const char *Terms[] = { |  | ||||||
|         "ansi", "color", "console", "cygwin", "gnome", "konsole", "kterm", "linux", "msys", "putty", "rxvt", "screen", "vt100", "xterm"}; |  | ||||||
|  |  | ||||||
|     const char *env_p = std::getenv("TERM"); |  | ||||||
|     if (env_p == nullptr) |  | ||||||
|     { |  | ||||||
|         return false; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     static const bool result = |  | ||||||
|         std::any_of(std::begin(Terms), std::end(Terms), [&](const char *term) { return std::strstr(env_p, term) != nullptr; }); |  | ||||||
|     return result; |  | ||||||
| #endif |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Detrmine if the terminal attached | // Detrmine if the terminal attached | ||||||
| // Source: https://github.com/agauniyal/rang/ | // Source: https://github.com/agauniyal/rang/ | ||||||
| inline bool in_terminal(FILE *file) SPDLOG_NOEXCEPT | bool in_terminal(FILE *file) SPDLOG_NOEXCEPT; | ||||||
| { |  | ||||||
|  |  | ||||||
| #ifdef _WIN32 | #if (defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) || defined(SPDLOG_WCHAR_FILENAMES)) && defined(_WIN32) | ||||||
|     return _isatty(_fileno(file)) != 0; | void wstr_to_utf8buf(wstring_view_t wstr, memory_buf_t &target); | ||||||
| #else |  | ||||||
|     return isatty(fileno(file)) != 0; |  | ||||||
| #endif | #endif | ||||||
| } |  | ||||||
| } // namespace os | } // namespace os | ||||||
| } // namespace details | } // namespace details | ||||||
| } // namespace spdlog | } // namespace spdlog | ||||||
|  |  | ||||||
|  | #ifdef SPDLOG_HEADER_ONLY | ||||||
|  | #include "os-inl.h" | ||||||
|  | #endif | ||||||
|   | |||||||
							
								
								
									
										1317
									
								
								third_party/spdlog/include/spdlog/details/pattern_formatter-inl.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1317
									
								
								third_party/spdlog/include/spdlog/details/pattern_formatter-inl.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										49
									
								
								third_party/spdlog/include/spdlog/details/periodic_worker-inl.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								third_party/spdlog/include/spdlog/details/periodic_worker-inl.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,49 @@ | |||||||
|  | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. | ||||||
|  | // Distributed under the MIT License (http://opensource.org/licenses/MIT) | ||||||
|  |  | ||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #ifndef SPDLOG_HEADER_ONLY | ||||||
|  | #include "spdlog/details/periodic_worker.h" | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | namespace spdlog { | ||||||
|  | namespace details { | ||||||
|  |  | ||||||
|  | SPDLOG_INLINE periodic_worker::periodic_worker(const std::function<void()> &callback_fun, std::chrono::seconds interval) | ||||||
|  | { | ||||||
|  |     active_ = (interval > std::chrono::seconds::zero()); | ||||||
|  |     if (!active_) | ||||||
|  |     { | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     worker_thread_ = std::thread([this, callback_fun, interval]() { | ||||||
|  |         for (;;) | ||||||
|  |         { | ||||||
|  |             std::unique_lock<std::mutex> lock(this->mutex_); | ||||||
|  |             if (this->cv_.wait_for(lock, interval, [this] { return !this->active_; })) | ||||||
|  |             { | ||||||
|  |                 return; // active_ == false, so exit this thread | ||||||
|  |             } | ||||||
|  |             callback_fun(); | ||||||
|  |         } | ||||||
|  |     }); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // stop the worker thread and join it | ||||||
|  | SPDLOG_INLINE periodic_worker::~periodic_worker() | ||||||
|  | { | ||||||
|  |     if (worker_thread_.joinable()) | ||||||
|  |     { | ||||||
|  |         { | ||||||
|  |             std::lock_guard<std::mutex> lock(mutex_); | ||||||
|  |             active_ = false; | ||||||
|  |         } | ||||||
|  |         cv_.notify_one(); | ||||||
|  |         worker_thread_.join(); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | } // namespace details | ||||||
|  | } // namespace spdlog | ||||||
| @@ -1,8 +1,5 @@ | |||||||
|  | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. | ||||||
| // |  | ||||||
| // Copyright(c) 2018 Gabi Melman. |  | ||||||
| // Distributed under the MIT License (http://opensource.org/licenses/MIT) | // Distributed under the MIT License (http://opensource.org/licenses/MIT) | ||||||
| // |  | ||||||
|  |  | ||||||
| #pragma once | #pragma once | ||||||
|  |  | ||||||
| @@ -23,43 +20,11 @@ namespace details { | |||||||
| class periodic_worker | class periodic_worker | ||||||
| { | { | ||||||
| public: | public: | ||||||
|     periodic_worker(const std::function<void()> &callback_fun, std::chrono::seconds interval) |     periodic_worker(const std::function<void()> &callback_fun, std::chrono::seconds interval); | ||||||
|     { |  | ||||||
|         active_ = (interval > std::chrono::seconds::zero()); |  | ||||||
|         if (!active_) |  | ||||||
|         { |  | ||||||
|             return; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         worker_thread_ = std::thread([this, callback_fun, interval]() { |  | ||||||
|             for (;;) |  | ||||||
|             { |  | ||||||
|                 std::unique_lock<std::mutex> lock(this->mutex_); |  | ||||||
|                 if (this->cv_.wait_for(lock, interval, [this] { return !this->active_; })) |  | ||||||
|                 { |  | ||||||
|                     return; // active_ == false, so exit this thread |  | ||||||
|                 } |  | ||||||
|                 callback_fun(); |  | ||||||
|             } |  | ||||||
|         }); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     periodic_worker(const periodic_worker &) = delete; |     periodic_worker(const periodic_worker &) = delete; | ||||||
|     periodic_worker &operator=(const periodic_worker &) = delete; |     periodic_worker &operator=(const periodic_worker &) = delete; | ||||||
|  |  | ||||||
|     // stop the worker thread and join it |     // stop the worker thread and join it | ||||||
|     ~periodic_worker() |     ~periodic_worker(); | ||||||
|     { |  | ||||||
|         if (worker_thread_.joinable()) |  | ||||||
|         { |  | ||||||
|             { |  | ||||||
|                 std::lock_guard<std::mutex> lock(mutex_); |  | ||||||
|                 active_ = false; |  | ||||||
|             } |  | ||||||
|             cv_.notify_one(); |  | ||||||
|             worker_thread_.join(); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
| private: | private: | ||||||
|     bool active_; |     bool active_; | ||||||
| @@ -69,3 +34,7 @@ private: | |||||||
| }; | }; | ||||||
| } // namespace details | } // namespace details | ||||||
| } // namespace spdlog | } // namespace spdlog | ||||||
|  |  | ||||||
|  | #ifdef SPDLOG_HEADER_ONLY | ||||||
|  | #include "periodic_worker-inl.h" | ||||||
|  | #endif | ||||||
|   | |||||||
							
								
								
									
										284
									
								
								third_party/spdlog/include/spdlog/details/registry-inl.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										284
									
								
								third_party/spdlog/include/spdlog/details/registry-inl.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,284 @@ | |||||||
|  | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. | ||||||
|  | // Distributed under the MIT License (http://opensource.org/licenses/MIT) | ||||||
|  |  | ||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #ifndef SPDLOG_HEADER_ONLY | ||||||
|  | #include "spdlog/details/registry.h" | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #include "spdlog/common.h" | ||||||
|  | #include "spdlog/details/periodic_worker.h" | ||||||
|  | #include "spdlog/logger.h" | ||||||
|  | #include "spdlog/details/pattern_formatter.h" | ||||||
|  |  | ||||||
|  | #ifndef SPDLOG_DISABLE_DEFAULT_LOGGER | ||||||
|  | // support for the default stdout color logger | ||||||
|  | #ifdef _WIN32 | ||||||
|  | #include "spdlog/sinks/wincolor_sink.h" | ||||||
|  | #else | ||||||
|  | #include "spdlog/sinks/ansicolor_sink.h" | ||||||
|  | #endif | ||||||
|  | #endif // SPDLOG_DISABLE_DEFAULT_LOGGER | ||||||
|  |  | ||||||
|  | #include <chrono> | ||||||
|  | #include <functional> | ||||||
|  | #include <memory> | ||||||
|  | #include <string> | ||||||
|  | #include <unordered_map> | ||||||
|  |  | ||||||
|  | namespace spdlog { | ||||||
|  | namespace details { | ||||||
|  |  | ||||||
|  | SPDLOG_INLINE registry::registry() | ||||||
|  |     : formatter_(new pattern_formatter()) | ||||||
|  | { | ||||||
|  |  | ||||||
|  | #ifndef SPDLOG_DISABLE_DEFAULT_LOGGER | ||||||
|  |     // create default logger (ansicolor_stdout_sink_mt or wincolor_stdout_sink_mt in windows). | ||||||
|  | #ifdef _WIN32 | ||||||
|  |     auto color_sink = std::make_shared<sinks::wincolor_stdout_sink_mt>(); | ||||||
|  | #else | ||||||
|  |     auto color_sink = std::make_shared<sinks::ansicolor_stdout_sink_mt>(); | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  |     const char *default_logger_name = ""; | ||||||
|  |     default_logger_ = std::make_shared<spdlog::logger>(default_logger_name, std::move(color_sink)); | ||||||
|  |     loggers_[default_logger_name] = default_logger_; | ||||||
|  |  | ||||||
|  | #endif // SPDLOG_DISABLE_DEFAULT_LOGGER | ||||||
|  | } | ||||||
|  | SPDLOG_INLINE void registry::register_logger(std::shared_ptr<logger> new_logger) | ||||||
|  | { | ||||||
|  |     std::lock_guard<std::mutex> lock(logger_map_mutex_); | ||||||
|  |     register_logger_(std::move(new_logger)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | SPDLOG_INLINE void registry::initialize_logger(std::shared_ptr<logger> new_logger) | ||||||
|  | { | ||||||
|  |     std::lock_guard<std::mutex> lock(logger_map_mutex_); | ||||||
|  |     new_logger->set_formatter(formatter_->clone()); | ||||||
|  |  | ||||||
|  |     if (err_handler_) | ||||||
|  |     { | ||||||
|  |         new_logger->set_error_handler(err_handler_); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     new_logger->set_level(level_); | ||||||
|  |     new_logger->flush_on(flush_level_); | ||||||
|  |  | ||||||
|  |     if (backtrace_n_messages_ > 0) | ||||||
|  |     { | ||||||
|  |         new_logger->enable_backtrace(backtrace_n_messages_); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (automatic_registration_) | ||||||
|  |     { | ||||||
|  |         register_logger_(std::move(new_logger)); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | SPDLOG_INLINE std::shared_ptr<logger> registry::get(const std::string &logger_name) | ||||||
|  | { | ||||||
|  |     std::lock_guard<std::mutex> lock(logger_map_mutex_); | ||||||
|  |     auto found = loggers_.find(logger_name); | ||||||
|  |     return found == loggers_.end() ? nullptr : found->second; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | SPDLOG_INLINE std::shared_ptr<logger> registry::default_logger() | ||||||
|  | { | ||||||
|  |     std::lock_guard<std::mutex> lock(logger_map_mutex_); | ||||||
|  |     return default_logger_; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Return raw ptr to the default logger. | ||||||
|  | // To be used directly by the spdlog default api (e.g. spdlog::info) | ||||||
|  | // This make the default API faster, but cannot be used concurrently with set_default_logger(). | ||||||
|  | // e.g do not call set_default_logger() from one thread while calling spdlog::info() from another. | ||||||
|  | SPDLOG_INLINE logger *registry::get_default_raw() | ||||||
|  | { | ||||||
|  |     return default_logger_.get(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // set default logger. | ||||||
|  | // default logger is stored in default_logger_ (for faster retrieval) and in the loggers_ map. | ||||||
|  | SPDLOG_INLINE void registry::set_default_logger(std::shared_ptr<logger> new_default_logger) | ||||||
|  | { | ||||||
|  |     std::lock_guard<std::mutex> lock(logger_map_mutex_); | ||||||
|  |     // remove previous default logger from the map | ||||||
|  |     if (default_logger_ != nullptr) | ||||||
|  |     { | ||||||
|  |         loggers_.erase(default_logger_->name()); | ||||||
|  |     } | ||||||
|  |     if (new_default_logger != nullptr) | ||||||
|  |     { | ||||||
|  |         loggers_[new_default_logger->name()] = new_default_logger; | ||||||
|  |     } | ||||||
|  |     default_logger_ = std::move(new_default_logger); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | SPDLOG_INLINE void registry::set_tp(std::shared_ptr<thread_pool> tp) | ||||||
|  | { | ||||||
|  |     std::lock_guard<std::recursive_mutex> lock(tp_mutex_); | ||||||
|  |     tp_ = std::move(tp); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | SPDLOG_INLINE std::shared_ptr<thread_pool> registry::get_tp() | ||||||
|  | { | ||||||
|  |     std::lock_guard<std::recursive_mutex> lock(tp_mutex_); | ||||||
|  |     return tp_; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Set global formatter. Each sink in each logger will get a clone of this object | ||||||
|  | SPDLOG_INLINE void registry::set_formatter(std::unique_ptr<formatter> formatter) | ||||||
|  | { | ||||||
|  |     std::lock_guard<std::mutex> lock(logger_map_mutex_); | ||||||
|  |     formatter_ = std::move(formatter); | ||||||
|  |     for (auto &l : loggers_) | ||||||
|  |     { | ||||||
|  |         l.second->set_formatter(formatter_->clone()); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | SPDLOG_INLINE void registry::enable_backtrace(size_t n_messages) | ||||||
|  | { | ||||||
|  |     std::lock_guard<std::mutex> lock(logger_map_mutex_); | ||||||
|  |     backtrace_n_messages_ = n_messages; | ||||||
|  |  | ||||||
|  |     for (auto &l : loggers_) | ||||||
|  |     { | ||||||
|  |         l.second->enable_backtrace(n_messages); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | SPDLOG_INLINE void registry::disable_backtrace() | ||||||
|  | { | ||||||
|  |     std::lock_guard<std::mutex> lock(logger_map_mutex_); | ||||||
|  |     backtrace_n_messages_ = 0; | ||||||
|  |     for (auto &l : loggers_) | ||||||
|  |     { | ||||||
|  |         l.second->disable_backtrace(); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | SPDLOG_INLINE void registry::set_level(level::level_enum log_level) | ||||||
|  | { | ||||||
|  |     std::lock_guard<std::mutex> lock(logger_map_mutex_); | ||||||
|  |     for (auto &l : loggers_) | ||||||
|  |     { | ||||||
|  |         l.second->set_level(log_level); | ||||||
|  |     } | ||||||
|  |     level_ = log_level; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | SPDLOG_INLINE void registry::flush_on(level::level_enum log_level) | ||||||
|  | { | ||||||
|  |     std::lock_guard<std::mutex> lock(logger_map_mutex_); | ||||||
|  |     for (auto &l : loggers_) | ||||||
|  |     { | ||||||
|  |         l.second->flush_on(log_level); | ||||||
|  |     } | ||||||
|  |     flush_level_ = log_level; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | SPDLOG_INLINE void registry::flush_every(std::chrono::seconds interval) | ||||||
|  | { | ||||||
|  |     std::lock_guard<std::mutex> lock(flusher_mutex_); | ||||||
|  |     std::function<void()> clbk = std::bind(®istry::flush_all, this); | ||||||
|  |     periodic_flusher_ = details::make_unique<periodic_worker>(clbk, interval); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | SPDLOG_INLINE void registry::set_error_handler(void (*handler)(const std::string &msg)) | ||||||
|  | { | ||||||
|  |     std::lock_guard<std::mutex> lock(logger_map_mutex_); | ||||||
|  |     for (auto &l : loggers_) | ||||||
|  |     { | ||||||
|  |         l.second->set_error_handler(handler); | ||||||
|  |     } | ||||||
|  |     err_handler_ = handler; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | SPDLOG_INLINE void registry::apply_all(const std::function<void(const std::shared_ptr<logger>)> &fun) | ||||||
|  | { | ||||||
|  |     std::lock_guard<std::mutex> lock(logger_map_mutex_); | ||||||
|  |     for (auto &l : loggers_) | ||||||
|  |     { | ||||||
|  |         fun(l.second); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | SPDLOG_INLINE void registry::flush_all() | ||||||
|  | { | ||||||
|  |     std::lock_guard<std::mutex> lock(logger_map_mutex_); | ||||||
|  |     for (auto &l : loggers_) | ||||||
|  |     { | ||||||
|  |         l.second->flush(); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | SPDLOG_INLINE void registry::drop(const std::string &logger_name) | ||||||
|  | { | ||||||
|  |     std::lock_guard<std::mutex> lock(logger_map_mutex_); | ||||||
|  |     loggers_.erase(logger_name); | ||||||
|  |     if (default_logger_ && default_logger_->name() == logger_name) | ||||||
|  |     { | ||||||
|  |         default_logger_.reset(); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | SPDLOG_INLINE void registry::drop_all() | ||||||
|  | { | ||||||
|  |     std::lock_guard<std::mutex> lock(logger_map_mutex_); | ||||||
|  |     loggers_.clear(); | ||||||
|  |     default_logger_.reset(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // clean all resources and threads started by the registry | ||||||
|  | SPDLOG_INLINE void registry::shutdown() | ||||||
|  | { | ||||||
|  |     { | ||||||
|  |         std::lock_guard<std::mutex> lock(flusher_mutex_); | ||||||
|  |         periodic_flusher_.reset(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     drop_all(); | ||||||
|  |  | ||||||
|  |     { | ||||||
|  |         std::lock_guard<std::recursive_mutex> lock(tp_mutex_); | ||||||
|  |         tp_.reset(); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | SPDLOG_INLINE std::recursive_mutex ®istry::tp_mutex() | ||||||
|  | { | ||||||
|  |     return tp_mutex_; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | SPDLOG_INLINE void registry::set_automatic_registration(bool automatic_regsistration) | ||||||
|  | { | ||||||
|  |     std::lock_guard<std::mutex> lock(logger_map_mutex_); | ||||||
|  |     automatic_registration_ = automatic_regsistration; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | SPDLOG_INLINE registry ®istry::instance() | ||||||
|  | { | ||||||
|  |     static registry s_instance; | ||||||
|  |     return s_instance; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | SPDLOG_INLINE void registry::throw_if_exists_(const std::string &logger_name) | ||||||
|  | { | ||||||
|  |     if (loggers_.find(logger_name) != loggers_.end()) | ||||||
|  |     { | ||||||
|  |         SPDLOG_THROW(spdlog_ex("logger with name '" + logger_name + "' already exists")); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | SPDLOG_INLINE void registry::register_logger_(std::shared_ptr<logger> new_logger) | ||||||
|  | { | ||||||
|  |     auto logger_name = new_logger->name(); | ||||||
|  |     throw_if_exists_(logger_name); | ||||||
|  |     loggers_[logger_name] = std::move(new_logger); | ||||||
|  | } | ||||||
|  | } // namespace details | ||||||
|  | } // namespace spdlog | ||||||
							
								
								
									
										260
									
								
								third_party/spdlog/include/spdlog/details/registry.h
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										260
									
								
								third_party/spdlog/include/spdlog/details/registry.h
									
									
									
									
										vendored
									
									
								
							| @@ -1,37 +1,28 @@ | |||||||
| // | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. | ||||||
| // Copyright(c) 2015 Gabi Melman. |  | ||||||
| // Distributed under the MIT License (http://opensource.org/licenses/MIT) | // Distributed under the MIT License (http://opensource.org/licenses/MIT) | ||||||
| // |  | ||||||
|  |  | ||||||
| #pragma once | #pragma once | ||||||
|  |  | ||||||
| // Loggers registy of unique name->logger pointer | // Loggers registry of unique name->logger pointer | ||||||
| // An attempt to create a logger with an already existing name will be ignored | // An attempt to create a logger with an already existing name will result with spdlog_ex exception. | ||||||
| // 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 "spdlog/details/periodic_worker.h" |  | ||||||
| #include "spdlog/logger.h" |  | ||||||
|  |  | ||||||
| #ifndef SPDLOG_DISABLE_DEFAULT_LOGGER |  | ||||||
| // support for the default stdout color logger |  | ||||||
| #ifdef _WIN32 |  | ||||||
| #include "spdlog/sinks/wincolor_sink.h" |  | ||||||
| #else |  | ||||||
| #include "spdlog/sinks/ansicolor_sink.h" |  | ||||||
| #endif |  | ||||||
| #endif // SPDLOG_DISABLE_DEFAULT_LOGGER |  | ||||||
|  |  | ||||||
| #include <chrono> | #include <chrono> | ||||||
| #include <functional> | #include <functional> | ||||||
| #include <memory> | #include <memory> | ||||||
| #include <string> | #include <string> | ||||||
| #include <unordered_map> | #include <unordered_map> | ||||||
|  | #include <mutex> | ||||||
|  |  | ||||||
| namespace spdlog { | namespace spdlog { | ||||||
|  | class logger; | ||||||
|  |  | ||||||
| namespace details { | namespace details { | ||||||
| class thread_pool; | class thread_pool; | ||||||
|  | class periodic_worker; | ||||||
|  |  | ||||||
| class registry | class registry | ||||||
| { | { | ||||||
| @@ -39,247 +30,80 @@ public: | |||||||
|     registry(const registry &) = delete; |     registry(const registry &) = delete; | ||||||
|     registry &operator=(const registry &) = delete; |     registry &operator=(const registry &) = delete; | ||||||
|  |  | ||||||
|     void register_logger(std::shared_ptr<logger> new_logger) |     void register_logger(std::shared_ptr<logger> new_logger); | ||||||
|     { |     void initialize_logger(std::shared_ptr<logger> new_logger); | ||||||
|         std::lock_guard<std::mutex> lock(logger_map_mutex_); |     std::shared_ptr<logger> get(const std::string &logger_name); | ||||||
|         register_logger_(std::move(new_logger)); |     std::shared_ptr<logger> default_logger(); | ||||||
|     } |  | ||||||
|  |  | ||||||
|     void initialize_logger(std::shared_ptr<logger> new_logger) |  | ||||||
|     { |  | ||||||
|         std::lock_guard<std::mutex> lock(logger_map_mutex_); |  | ||||||
|         new_logger->set_formatter(formatter_->clone()); |  | ||||||
|  |  | ||||||
|         if (err_handler_) |  | ||||||
|         { |  | ||||||
|             new_logger->set_error_handler(err_handler_); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         new_logger->set_level(level_); |  | ||||||
|         new_logger->flush_on(flush_level_); |  | ||||||
|  |  | ||||||
|         if (automatic_registration_) |  | ||||||
|         { |  | ||||||
|             register_logger_(std::move(new_logger)); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     std::shared_ptr<logger> get(const std::string &logger_name) |  | ||||||
|     { |  | ||||||
|         std::lock_guard<std::mutex> lock(logger_map_mutex_); |  | ||||||
|         auto found = loggers_.find(logger_name); |  | ||||||
|         return found == loggers_.end() ? nullptr : found->second; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     std::shared_ptr<logger> default_logger() |  | ||||||
|     { |  | ||||||
|         std::lock_guard<std::mutex> lock(logger_map_mutex_); |  | ||||||
|         return default_logger_; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     // Return raw ptr to the default logger. |     // Return raw ptr to the default logger. | ||||||
|     // To be used directly by the spdlog default api (e.g. spdlog::info) |     // To be used directly by the spdlog default api (e.g. spdlog::info) | ||||||
|     // This make the default API faster, but cannot be used concurrently with set_default_logger(). |     // This make the default API faster, but cannot be used concurrently with set_default_logger(). | ||||||
|     // e.g do not call set_default_logger() from one thread while calling spdlog::info() from another. |     // e.g do not call set_default_logger() from one thread while calling spdlog::info() from another. | ||||||
|     logger *get_default_raw() |     logger *get_default_raw(); | ||||||
|     { |  | ||||||
|         return default_logger_.get(); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     // set default logger. |     // set default logger. | ||||||
|     // default logger is stored in default_logger_ (for faster retrieval) and in the loggers_ map. |     // default logger is stored in default_logger_ (for faster retrieval) and in the loggers_ map. | ||||||
|     void set_default_logger(std::shared_ptr<logger> new_default_logger) |     void set_default_logger(std::shared_ptr<logger> new_default_logger); | ||||||
|     { |  | ||||||
|         std::lock_guard<std::mutex> lock(logger_map_mutex_); |  | ||||||
|         // remove previous default logger from the map |  | ||||||
|         if (default_logger_ != nullptr) |  | ||||||
|         { |  | ||||||
|             loggers_.erase(default_logger_->name()); |  | ||||||
|         } |  | ||||||
|         if (new_default_logger != nullptr) |  | ||||||
|         { |  | ||||||
|             loggers_[new_default_logger->name()] = new_default_logger; |  | ||||||
|         } |  | ||||||
|         default_logger_ = std::move(new_default_logger); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     void set_tp(std::shared_ptr<thread_pool> tp) |     void set_tp(std::shared_ptr<thread_pool> tp); | ||||||
|     { |  | ||||||
|         std::lock_guard<std::recursive_mutex> lock(tp_mutex_); |  | ||||||
|         tp_ = std::move(tp); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     std::shared_ptr<thread_pool> get_tp() |     std::shared_ptr<thread_pool> get_tp(); | ||||||
|     { |  | ||||||
|         std::lock_guard<std::recursive_mutex> lock(tp_mutex_); |  | ||||||
|         return tp_; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     // Set global formatter. Each sink in each logger will get a clone of this object |     // Set global formatter. Each sink in each logger will get a clone of this object | ||||||
|     void set_formatter(std::unique_ptr<formatter> formatter) |     void set_formatter(std::unique_ptr<formatter> formatter); | ||||||
|     { |  | ||||||
|         std::lock_guard<std::mutex> lock(logger_map_mutex_); |  | ||||||
|         formatter_ = std::move(formatter); |  | ||||||
|         for (auto &l : loggers_) |  | ||||||
|         { |  | ||||||
|             l.second->set_formatter(formatter_->clone()); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     void set_level(level::level_enum log_level) |     void enable_backtrace(size_t n_messages); | ||||||
|     { |  | ||||||
|         std::lock_guard<std::mutex> lock(logger_map_mutex_); |  | ||||||
|         for (auto &l : loggers_) |  | ||||||
|         { |  | ||||||
|             l.second->set_level(log_level); |  | ||||||
|         } |  | ||||||
|         level_ = log_level; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     void flush_on(level::level_enum log_level) |     void disable_backtrace(); | ||||||
|     { |  | ||||||
|         std::lock_guard<std::mutex> lock(logger_map_mutex_); |  | ||||||
|         for (auto &l : loggers_) |  | ||||||
|         { |  | ||||||
|             l.second->flush_on(log_level); |  | ||||||
|         } |  | ||||||
|         flush_level_ = log_level; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     void flush_every(std::chrono::seconds interval) |     void set_level(level::level_enum log_level); | ||||||
|     { |  | ||||||
|         std::lock_guard<std::mutex> lock(flusher_mutex_); |  | ||||||
|         std::function<void()> clbk = std::bind(®istry::flush_all, this); |  | ||||||
|         periodic_flusher_ = details::make_unique<periodic_worker>(clbk, interval); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     void set_error_handler(log_err_handler handler) |     void flush_on(level::level_enum log_level); | ||||||
|     { |  | ||||||
|         std::lock_guard<std::mutex> lock(logger_map_mutex_); |  | ||||||
|         for (auto &l : loggers_) |  | ||||||
|         { |  | ||||||
|             l.second->set_error_handler(handler); |  | ||||||
|         } |  | ||||||
|         err_handler_ = handler; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     void apply_all(const std::function<void(const std::shared_ptr<logger>)> &fun) |     void flush_every(std::chrono::seconds interval); | ||||||
|     { |  | ||||||
|         std::lock_guard<std::mutex> lock(logger_map_mutex_); |  | ||||||
|         for (auto &l : loggers_) |  | ||||||
|         { |  | ||||||
|             fun(l.second); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     void flush_all() |     void set_error_handler(void (*handler)(const std::string &msg)); | ||||||
|     { |  | ||||||
|         std::lock_guard<std::mutex> lock(logger_map_mutex_); |  | ||||||
|         for (auto &l : loggers_) |  | ||||||
|         { |  | ||||||
|             l.second->flush(); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     void drop(const std::string &logger_name) |     void apply_all(const std::function<void(const std::shared_ptr<logger>)> &fun); | ||||||
|     { |  | ||||||
|         std::lock_guard<std::mutex> lock(logger_map_mutex_); |  | ||||||
|         loggers_.erase(logger_name); |  | ||||||
|         if (default_logger_ && default_logger_->name() == logger_name) |  | ||||||
|         { |  | ||||||
|             default_logger_.reset(); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     void drop_all() |     void flush_all(); | ||||||
|     { |  | ||||||
|         std::lock_guard<std::mutex> lock(logger_map_mutex_); |     void drop(const std::string &logger_name); | ||||||
|         loggers_.clear(); |  | ||||||
|         default_logger_.reset(); |     void drop_all(); | ||||||
|     } |  | ||||||
|  |  | ||||||
|     // clean all resources and threads started by the registry |     // clean all resources and threads started by the registry | ||||||
|     void shutdown() |     void shutdown(); | ||||||
|     { |  | ||||||
|         { |  | ||||||
|             std::lock_guard<std::mutex> lock(flusher_mutex_); |  | ||||||
|             periodic_flusher_.reset(); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         drop_all(); |     std::recursive_mutex &tp_mutex(); | ||||||
|  |  | ||||||
|         { |     void set_automatic_registration(bool automatic_regsistration); | ||||||
|             std::lock_guard<std::recursive_mutex> lock(tp_mutex_); |  | ||||||
|             tp_.reset(); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     std::recursive_mutex &tp_mutex() |     static registry &instance(); | ||||||
|     { |  | ||||||
|         return tp_mutex_; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     void set_automatic_registration(bool automatic_regsistration) |  | ||||||
|     { |  | ||||||
|         std::lock_guard<std::mutex> lock(logger_map_mutex_); |  | ||||||
|         automatic_registration_ = automatic_regsistration; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     static registry &instance() |  | ||||||
|     { |  | ||||||
|         static registry s_instance; |  | ||||||
|         return s_instance; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
| private: | private: | ||||||
|     registry() |     registry(); | ||||||
|         : formatter_(new pattern_formatter()) |  | ||||||
|     { |  | ||||||
|  |  | ||||||
| #ifndef SPDLOG_DISABLE_DEFAULT_LOGGER |  | ||||||
|         // create default logger (ansicolor_stdout_sink_mt or wincolor_stdout_sink_mt in windows). |  | ||||||
| #ifdef _WIN32 |  | ||||||
|         auto color_sink = std::make_shared<sinks::wincolor_stdout_sink_mt>(); |  | ||||||
| #else |  | ||||||
|         auto color_sink = std::make_shared<sinks::ansicolor_stdout_sink_mt>(); |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
|         const char *default_logger_name = ""; |  | ||||||
|         default_logger_ = std::make_shared<spdlog::logger>(default_logger_name, std::move(color_sink)); |  | ||||||
|         loggers_[default_logger_name] = default_logger_; |  | ||||||
|  |  | ||||||
| #endif // SPDLOG_DISABLE_DEFAULT_LOGGER |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     ~registry() = default; |     ~registry() = default; | ||||||
|  |  | ||||||
|     void throw_if_exists_(const std::string &logger_name) |     void throw_if_exists_(const std::string &logger_name); | ||||||
|     { |     void register_logger_(std::shared_ptr<logger> new_logger); | ||||||
|         if (loggers_.find(logger_name) != loggers_.end()) |  | ||||||
|         { |  | ||||||
|             throw spdlog_ex("logger with name '" + logger_name + "' already exists"); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     void register_logger_(std::shared_ptr<logger> new_logger) |  | ||||||
|     { |  | ||||||
|         auto logger_name = new_logger->name(); |  | ||||||
|         throw_if_exists_(logger_name); |  | ||||||
|         loggers_[logger_name] = std::move(new_logger); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     std::mutex logger_map_mutex_, flusher_mutex_; |     std::mutex logger_map_mutex_, flusher_mutex_; | ||||||
|     std::recursive_mutex tp_mutex_; |     std::recursive_mutex tp_mutex_; | ||||||
|     std::unordered_map<std::string, std::shared_ptr<logger>> loggers_; |     std::unordered_map<std::string, std::shared_ptr<logger>> loggers_; | ||||||
|     std::unique_ptr<formatter> formatter_; |     std::unique_ptr<formatter> formatter_; | ||||||
|     level::level_enum level_ = spdlog::logger::default_level(); |     level::level_enum level_ = level::info; | ||||||
|     level::level_enum flush_level_ = level::off; |     level::level_enum flush_level_ = level::off; | ||||||
|     log_err_handler err_handler_; |     void (*err_handler_)(const std::string &msg); | ||||||
|     std::shared_ptr<thread_pool> tp_; |     std::shared_ptr<thread_pool> tp_; | ||||||
|     std::unique_ptr<periodic_worker> periodic_flusher_; |     std::unique_ptr<periodic_worker> periodic_flusher_; | ||||||
|     std::shared_ptr<logger> default_logger_; |     std::shared_ptr<logger> default_logger_; | ||||||
|     bool automatic_registration_ = true; |     bool automatic_registration_ = true; | ||||||
|  |     size_t backtrace_n_messages_ = 0; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| } // namespace details | } // namespace details | ||||||
| } // namespace spdlog | } // namespace spdlog | ||||||
|  |  | ||||||
|  | #ifdef SPDLOG_HEADER_ONLY | ||||||
|  | #include "registry-inl.h" | ||||||
|  | #endif | ||||||
|   | |||||||
							
								
								
									
										24
									
								
								third_party/spdlog/include/spdlog/details/synchronous_factory.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								third_party/spdlog/include/spdlog/details/synchronous_factory.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,24 @@ | |||||||
|  | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. | ||||||
|  | // Distributed under the MIT License (http://opensource.org/licenses/MIT) | ||||||
|  |  | ||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #include "registry.h" | ||||||
|  |  | ||||||
|  | namespace spdlog { | ||||||
|  |  | ||||||
|  | // Default logger factory-  creates synchronous loggers | ||||||
|  | class logger; | ||||||
|  |  | ||||||
|  | struct synchronous_factory | ||||||
|  | { | ||||||
|  |     template<typename Sink, typename... SinkArgs> | ||||||
|  |     static std::shared_ptr<spdlog::logger> create(std::string logger_name, SinkArgs &&... args) | ||||||
|  |     { | ||||||
|  |         auto sink = std::make_shared<Sink>(std::forward<SinkArgs>(args)...); | ||||||
|  |         auto new_logger = std::make_shared<spdlog::logger>(std::move(logger_name), std::move(sink)); | ||||||
|  |         details::registry::instance().initialize_logger(new_logger); | ||||||
|  |         return new_logger; | ||||||
|  |     } | ||||||
|  | }; | ||||||
|  | } // namespace spdlog | ||||||
							
								
								
									
										127
									
								
								third_party/spdlog/include/spdlog/details/thread_pool-inl.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										127
									
								
								third_party/spdlog/include/spdlog/details/thread_pool-inl.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,127 @@ | |||||||
|  | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. | ||||||
|  | // Distributed under the MIT License (http://opensource.org/licenses/MIT) | ||||||
|  |  | ||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #ifndef SPDLOG_HEADER_ONLY | ||||||
|  | #include "spdlog/details/thread_pool.h" | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #include "spdlog/common.h" | ||||||
|  |  | ||||||
|  | namespace spdlog { | ||||||
|  | namespace details { | ||||||
|  |  | ||||||
|  | SPDLOG_INLINE thread_pool::thread_pool(size_t q_max_items, size_t threads_n, std::function<void()> on_thread_start) | ||||||
|  |     : q_(q_max_items) | ||||||
|  | { | ||||||
|  |     if (threads_n == 0 || threads_n > 1000) | ||||||
|  |     { | ||||||
|  |         SPDLOG_THROW(spdlog_ex("spdlog::thread_pool(): invalid threads_n param (valid " | ||||||
|  |                                "range is 1-1000)")); | ||||||
|  |     } | ||||||
|  |     for (size_t i = 0; i < threads_n; i++) | ||||||
|  |     { | ||||||
|  |         threads_.emplace_back([this, on_thread_start] { | ||||||
|  |             on_thread_start(); | ||||||
|  |             this->thread_pool::worker_loop_(); | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | SPDLOG_INLINE thread_pool::thread_pool(size_t q_max_items, size_t threads_n) | ||||||
|  |     : thread_pool(q_max_items, threads_n, [] {}) | ||||||
|  | {} | ||||||
|  |  | ||||||
|  | // message all threads to terminate gracefully join them | ||||||
|  | SPDLOG_INLINE thread_pool::~thread_pool() | ||||||
|  | { | ||||||
|  |     SPDLOG_TRY | ||||||
|  |     { | ||||||
|  |         for (size_t i = 0; i < threads_.size(); i++) | ||||||
|  |         { | ||||||
|  |             post_async_msg_(async_msg(async_msg_type::terminate), async_overflow_policy::block); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         for (auto &t : threads_) | ||||||
|  |         { | ||||||
|  |             t.join(); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     SPDLOG_CATCH_ALL() {} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void SPDLOG_INLINE thread_pool::post_log(async_logger_ptr &&worker_ptr, const details::log_msg &msg, async_overflow_policy overflow_policy) | ||||||
|  | { | ||||||
|  |     async_msg async_m(std::move(worker_ptr), async_msg_type::log, msg); | ||||||
|  |     post_async_msg_(std::move(async_m), overflow_policy); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void SPDLOG_INLINE thread_pool::post_flush(async_logger_ptr &&worker_ptr, async_overflow_policy overflow_policy) | ||||||
|  | { | ||||||
|  |     post_async_msg_(async_msg(std::move(worker_ptr), async_msg_type::flush), overflow_policy); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | size_t SPDLOG_INLINE thread_pool::overrun_counter() | ||||||
|  | { | ||||||
|  |     return q_.overrun_counter(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void SPDLOG_INLINE thread_pool::post_async_msg_(async_msg &&new_msg, async_overflow_policy overflow_policy) | ||||||
|  | { | ||||||
|  |     if (overflow_policy == async_overflow_policy::block) | ||||||
|  |     { | ||||||
|  |         q_.enqueue(std::move(new_msg)); | ||||||
|  |     } | ||||||
|  |     else | ||||||
|  |     { | ||||||
|  |         q_.enqueue_nowait(std::move(new_msg)); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void SPDLOG_INLINE thread_pool::worker_loop_() | ||||||
|  | { | ||||||
|  |     while (process_next_msg_()) {}; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // process next message in the queue | ||||||
|  | // return true if this thread should still be active (while no terminate msg | ||||||
|  | // was received) | ||||||
|  | bool SPDLOG_INLINE thread_pool::process_next_msg_() | ||||||
|  | { | ||||||
|  |     async_msg incoming_async_msg; | ||||||
|  |     bool dequeued = q_.dequeue_for(incoming_async_msg, std::chrono::seconds(10)); | ||||||
|  |     if (!dequeued) | ||||||
|  |     { | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     switch (incoming_async_msg.msg_type) | ||||||
|  |     { | ||||||
|  |     case async_msg_type::log: | ||||||
|  |     { | ||||||
|  |         incoming_async_msg.worker_ptr->backend_sink_it_(incoming_async_msg); | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |     case async_msg_type::flush: | ||||||
|  |     { | ||||||
|  |         incoming_async_msg.worker_ptr->backend_flush_(); | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     case async_msg_type::terminate: | ||||||
|  |     { | ||||||
|  |         return false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     default: | ||||||
|  |     { | ||||||
|  |         assert(false && "Unexpected async_msg_type"); | ||||||
|  |     } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return true; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | } // namespace details | ||||||
|  | } // namespace spdlog | ||||||
| @@ -1,7 +1,9 @@ | |||||||
|  | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. | ||||||
|  | // Distributed under the MIT License (http://opensource.org/licenses/MIT) | ||||||
|  |  | ||||||
| #pragma once | #pragma once | ||||||
|  |  | ||||||
| #include "spdlog/details/fmt_helper.h" | #include "spdlog/details/log_msg_buffer.h" | ||||||
| #include "spdlog/details/log_msg.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" | ||||||
|  |  | ||||||
| @@ -9,8 +11,11 @@ | |||||||
| #include <memory> | #include <memory> | ||||||
| #include <thread> | #include <thread> | ||||||
| #include <vector> | #include <vector> | ||||||
|  | #include <functional> | ||||||
|  |  | ||||||
| namespace spdlog { | namespace spdlog { | ||||||
|  | class async_logger; | ||||||
|  |  | ||||||
| namespace details { | namespace details { | ||||||
|  |  | ||||||
| using async_logger_ptr = std::shared_ptr<spdlog::async_logger>; | using async_logger_ptr = std::shared_ptr<spdlog::async_logger>; | ||||||
| @@ -22,18 +27,12 @@ enum class async_msg_type | |||||||
|     terminate |     terminate | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | #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 | struct async_msg : log_msg_buffer | ||||||
| { | { | ||||||
|     async_msg_type msg_type; |     async_msg_type msg_type{async_msg_type::log}; | ||||||
|     level::level_enum level; |  | ||||||
|     log_clock::time_point time; |  | ||||||
|     size_t thread_id; |  | ||||||
|     fmt::basic_memory_buffer<char, 176> raw; |  | ||||||
|  |  | ||||||
|     size_t msg_id; |  | ||||||
|     source_loc source; |  | ||||||
|     async_logger_ptr worker_ptr; |     async_logger_ptr worker_ptr; | ||||||
|  |  | ||||||
|     async_msg() = default; |     async_msg() = default; | ||||||
| @@ -44,26 +43,16 @@ struct async_msg | |||||||
|  |  | ||||||
| // support for vs2013 move | // support for vs2013 move | ||||||
| #if defined(_MSC_VER) && _MSC_VER <= 1800 | #if defined(_MSC_VER) && _MSC_VER <= 1800 | ||||||
|     async_msg(async_msg &&other) SPDLOG_NOEXCEPT : msg_type(other.msg_type), |     async_msg(async_msg &&other) | ||||||
|                                                    level(other.level), |         : log_msg_buffer(std::move(other)) | ||||||
|                                                    time(other.time), |         , msg_type(other.msg_type) | ||||||
|                                                    thread_id(other.thread_id), |         , worker_ptr(std::move(other.worker_ptr)) | ||||||
|                                                    raw(move(other.raw)), |     {} | ||||||
|                                                    msg_id(other.msg_id), |  | ||||||
|                                                    source(other.source), |  | ||||||
|                                                    worker_ptr(std::move(other.worker_ptr)) |  | ||||||
|     { |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     async_msg &operator=(async_msg &&other) SPDLOG_NOEXCEPT |     async_msg &operator=(async_msg &&other) | ||||||
|     { |     { | ||||||
|  |         *static_cast<log_msg_buffer *>(this) = std::move(other); | ||||||
|         msg_type = other.msg_type; |         msg_type = other.msg_type; | ||||||
|         level = other.level; |  | ||||||
|         time = other.time; |  | ||||||
|         thread_id = other.thread_id; |  | ||||||
|         raw = std::move(other.raw); |  | ||||||
|         msg_id = other.msg_id; |  | ||||||
|         source = other.source; |  | ||||||
|         worker_ptr = std::move(other.worker_ptr); |         worker_ptr = std::move(other.worker_ptr); | ||||||
|         return *this; |         return *this; | ||||||
|     } |     } | ||||||
| @@ -73,46 +62,21 @@ struct async_msg | |||||||
| #endif | #endif | ||||||
|  |  | ||||||
|     // construct from log_msg with given type |     // construct from log_msg with given type | ||||||
|     async_msg(async_logger_ptr &&worker, async_msg_type the_type, details::log_msg &m) |     async_msg(async_logger_ptr &&worker, async_msg_type the_type, const details::log_msg &m) | ||||||
|         : msg_type(the_type) |         : log_msg_buffer{m} | ||||||
|         , level(m.level) |         , msg_type{the_type} | ||||||
|         , time(m.time) |         , worker_ptr{std::move(worker)} | ||||||
|         , thread_id(m.thread_id) |     {} | ||||||
|         , msg_id(m.msg_id) |  | ||||||
|         , source(m.source) |  | ||||||
|         , worker_ptr(std::move(worker)) |  | ||||||
|     { |  | ||||||
|         fmt_helper::append_string_view(m.payload, raw); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     async_msg(async_logger_ptr &&worker, async_msg_type the_type) |     async_msg(async_logger_ptr &&worker, async_msg_type the_type) | ||||||
|         : msg_type(the_type) |         : log_msg_buffer{} | ||||||
|         , level(level::off) |         , msg_type{the_type} | ||||||
|         , time() |         , worker_ptr{std::move(worker)} | ||||||
|         , thread_id(0) |     {} | ||||||
|         , msg_id(0) |  | ||||||
|         , source() |  | ||||||
|         , worker_ptr(std::move(worker)) |  | ||||||
|     { |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     explicit async_msg(async_msg_type the_type) |     explicit async_msg(async_msg_type the_type) | ||||||
|         : async_msg(nullptr, the_type) |         : async_msg{nullptr, the_type} | ||||||
|     { |     {} | ||||||
|     } |  | ||||||
|  |  | ||||||
|     // copy into log_msg |  | ||||||
|     log_msg to_log_msg() |  | ||||||
|     { |  | ||||||
|         log_msg msg(&worker_ptr->name(), level, string_view_t(raw.data(), raw.size())); |  | ||||||
|         msg.time = time; |  | ||||||
|         msg.thread_id = thread_id; |  | ||||||
|         msg.msg_id = msg_id; |  | ||||||
|         msg.source = source; |  | ||||||
|         msg.color_range_start = 0; |  | ||||||
|         msg.color_range_end = 0; |  | ||||||
|         return msg; |  | ||||||
|     } |  | ||||||
| }; | }; | ||||||
|  |  | ||||||
| class thread_pool | class thread_pool | ||||||
| @@ -121,118 +85,36 @@ public: | |||||||
|     using item_type = async_msg; |     using item_type = async_msg; | ||||||
|     using q_type = details::mpmc_blocking_queue<item_type>; |     using q_type = details::mpmc_blocking_queue<item_type>; | ||||||
|  |  | ||||||
|     thread_pool(size_t q_max_items, size_t threads_n) |     thread_pool(size_t q_max_items, size_t threads_n, std::function<void()> on_thread_start); | ||||||
|         : q_(q_max_items) |     thread_pool(size_t q_max_items, size_t threads_n); | ||||||
|     { |  | ||||||
|         // std::cout << "thread_pool()  q_size_bytes: " << q_size_bytes << |  | ||||||
|         // "\tthreads_n: " << threads_n << std::endl; |  | ||||||
|         if (threads_n == 0 || threads_n > 1000) |  | ||||||
|         { |  | ||||||
|             throw spdlog_ex("spdlog::thread_pool(): invalid threads_n param (valid " |  | ||||||
|                             "range is 1-1000)"); |  | ||||||
|         } |  | ||||||
|         for (size_t i = 0; i < threads_n; i++) |  | ||||||
|         { |  | ||||||
|             threads_.emplace_back(&thread_pool::worker_loop_, this); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     // message all threads to terminate gracefully join them |     // message all threads to terminate gracefully join them | ||||||
|     ~thread_pool() |     ~thread_pool(); | ||||||
|     { |  | ||||||
|         try |  | ||||||
|         { |  | ||||||
|             for (size_t i = 0; i < threads_.size(); i++) |  | ||||||
|             { |  | ||||||
|                 post_async_msg_(async_msg(async_msg_type::terminate), async_overflow_policy::block); |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             for (auto &t : threads_) |  | ||||||
|             { |  | ||||||
|                 t.join(); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         catch (...) |  | ||||||
|         { |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     thread_pool(const thread_pool &) = delete; |     thread_pool(const thread_pool &) = delete; | ||||||
|     thread_pool &operator=(thread_pool &&) = delete; |     thread_pool &operator=(thread_pool &&) = delete; | ||||||
|  |  | ||||||
|     void post_log(async_logger_ptr &&worker_ptr, details::log_msg &msg, async_overflow_policy overflow_policy) |     void post_log(async_logger_ptr &&worker_ptr, const details::log_msg &msg, async_overflow_policy overflow_policy); | ||||||
|     { |     void post_flush(async_logger_ptr &&worker_ptr, async_overflow_policy overflow_policy); | ||||||
|         async_msg async_m(std::move(worker_ptr), async_msg_type::log, msg); |     size_t overrun_counter(); | ||||||
|         post_async_msg_(std::move(async_m), overflow_policy); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     void post_flush(async_logger_ptr &&worker_ptr, async_overflow_policy overflow_policy) |  | ||||||
|     { |  | ||||||
|         post_async_msg_(async_msg(std::move(worker_ptr), async_msg_type::flush), overflow_policy); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     size_t overrun_counter() |  | ||||||
|     { |  | ||||||
|         return q_.overrun_counter(); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
| private: | private: | ||||||
|     q_type q_; |     q_type q_; | ||||||
|  |  | ||||||
|     std::vector<std::thread> threads_; |     std::vector<std::thread> threads_; | ||||||
|  |  | ||||||
|     void post_async_msg_(async_msg &&new_msg, async_overflow_policy overflow_policy) |     void post_async_msg_(async_msg &&new_msg, async_overflow_policy overflow_policy); | ||||||
|     { |     void worker_loop_(); | ||||||
|         if (overflow_policy == async_overflow_policy::block) |  | ||||||
|         { |  | ||||||
|             q_.enqueue(std::move(new_msg)); |  | ||||||
|         } |  | ||||||
|         else |  | ||||||
|         { |  | ||||||
|             q_.enqueue_nowait(std::move(new_msg)); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     void worker_loop_() |  | ||||||
|     { |  | ||||||
|         while (process_next_msg_()) {}; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     // process next message in the queue |     // process next message in the queue | ||||||
|     // return true if this thread should still be active (while no terminate msg |     // return true if this thread should still be active (while no terminate msg | ||||||
|     // was received) |     // was received) | ||||||
|     bool process_next_msg_() |     bool process_next_msg_(); | ||||||
|     { |  | ||||||
|         async_msg incoming_async_msg; |  | ||||||
|         bool dequeued = q_.dequeue_for(incoming_async_msg, std::chrono::seconds(10)); |  | ||||||
|         if (!dequeued) |  | ||||||
|         { |  | ||||||
|             return true; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         switch (incoming_async_msg.msg_type) |  | ||||||
|         { |  | ||||||
|         case async_msg_type::log: |  | ||||||
|         { |  | ||||||
|             auto msg = incoming_async_msg.to_log_msg(); |  | ||||||
|             incoming_async_msg.worker_ptr->backend_log_(msg); |  | ||||||
|             return true; |  | ||||||
|         } |  | ||||||
|         case async_msg_type::flush: |  | ||||||
|         { |  | ||||||
|             incoming_async_msg.worker_ptr->backend_flush_(); |  | ||||||
|             return true; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         case async_msg_type::terminate: |  | ||||||
|         { |  | ||||||
|             return false; |  | ||||||
|         } |  | ||||||
|         } |  | ||||||
|         assert(false && "Unexpected async_msg_type"); |  | ||||||
|         return true; |  | ||||||
|     } |  | ||||||
| }; | }; | ||||||
|  |  | ||||||
| } // namespace details | } // namespace details | ||||||
| } // namespace spdlog | } // namespace spdlog | ||||||
|  |  | ||||||
|  | #ifdef SPDLOG_HEADER_ONLY | ||||||
|  | #include "thread_pool-inl.h" | ||||||
|  | #endif | ||||||
|   | |||||||
| @@ -31,8 +31,7 @@ public: | |||||||
|     bytes_range(It range_begin, It range_end) |     bytes_range(It range_begin, It range_end) | ||||||
|         : begin_(range_begin) |         : begin_(range_begin) | ||||||
|         , end_(range_end) |         , end_(range_end) | ||||||
|     { |     {} | ||||||
|     } |  | ||||||
|  |  | ||||||
|     It begin() const |     It begin() const | ||||||
|     { |     { | ||||||
| @@ -117,7 +116,11 @@ struct formatter<spdlog::details::bytes_range<T>> | |||||||
|  |  | ||||||
|         std::size_t pos = 0; |         std::size_t pos = 0; | ||||||
|         std::size_t column = line_size; |         std::size_t column = line_size; | ||||||
|  | #if FMT_VERSION < 60000 | ||||||
|         auto inserter = ctx.begin(); |         auto inserter = ctx.begin(); | ||||||
|  | #else | ||||||
|  |         auto inserter = ctx.out(); | ||||||
|  | #endif | ||||||
|  |  | ||||||
|         for (auto &item : the_range) |         for (auto &item : the_range) | ||||||
|         { |         { | ||||||
|   | |||||||
| @@ -1,23 +1,27 @@ | |||||||
| Copyright (c) 2012 - 2016, Victor Zverovich | Copyright (c) 2012 - present, Victor Zverovich | ||||||
|  |  | ||||||
| All rights reserved. | Permission is hereby granted, free of charge, to any person obtaining | ||||||
|  | a copy of this software and associated documentation files (the | ||||||
|  | "Software"), to deal in the Software without restriction, including | ||||||
|  | without limitation the rights to use, copy, modify, merge, publish, | ||||||
|  | distribute, sublicense, and/or sell copies of the Software, and to | ||||||
|  | permit persons to whom the Software is furnished to do so, subject to | ||||||
|  | the following conditions: | ||||||
|  |  | ||||||
| Redistribution and use in source and binary forms, with or without | The above copyright notice and this permission notice shall be | ||||||
| modification, are permitted provided that the following conditions are met: | included in all copies or substantial portions of the Software. | ||||||
|  |  | ||||||
| 1. Redistributions of source code must retain the above copyright notice, this | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||||||
|    list of conditions and the following disclaimer. | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||||||
| 2. Redistributions in binary form must reproduce the above copyright notice, | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||||||
|    this list of conditions and the following disclaimer in the documentation | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE | ||||||
|    and/or other materials provided with the distribution. | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION | ||||||
|  | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION | ||||||
|  | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||||||
|  |  | ||||||
| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND | --- Optional exception to the license --- | ||||||
| ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |  | ||||||
| WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | As an exception, if, as a result of your compiling your source code, portions | ||||||
| DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR | of this Software are embedded into a machine-executable object form of such | ||||||
| ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | source code, you may redistribute such embedded portions in such object form | ||||||
| (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | without including the above copyright and permission notices. | ||||||
| LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |  | ||||||
| ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |  | ||||||
| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |  | ||||||
| SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |  | ||||||
|   | |||||||
| @@ -16,9 +16,181 @@ | |||||||
| #include <locale> | #include <locale> | ||||||
| #include <sstream> | #include <sstream> | ||||||
|  |  | ||||||
|  | // enable safe chrono durations, unless explicitly disabled | ||||||
|  | #ifndef FMT_SAFE_DURATION_CAST | ||||||
|  | #  define FMT_SAFE_DURATION_CAST 1 | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #if FMT_SAFE_DURATION_CAST | ||||||
|  | #  include "safe-duration-cast.h" | ||||||
|  | #endif | ||||||
|  |  | ||||||
| FMT_BEGIN_NAMESPACE | FMT_BEGIN_NAMESPACE | ||||||
|  |  | ||||||
| namespace internal{ | // Prevents expansion of a preceding token as a function-style macro. | ||||||
|  | // Usage: f FMT_NOMACRO() | ||||||
|  | #define FMT_NOMACRO | ||||||
|  |  | ||||||
|  | namespace internal { | ||||||
|  | inline null<> localtime_r FMT_NOMACRO(...) { return null<>(); } | ||||||
|  | inline null<> localtime_s(...) { return null<>(); } | ||||||
|  | inline null<> gmtime_r(...) { return null<>(); } | ||||||
|  | inline null<> gmtime_s(...) { return null<>(); } | ||||||
|  | }  // namespace internal | ||||||
|  |  | ||||||
|  | // Thread-safe replacement for std::localtime | ||||||
|  | inline std::tm localtime(std::time_t time) { | ||||||
|  |   struct dispatcher { | ||||||
|  |     std::time_t time_; | ||||||
|  |     std::tm tm_; | ||||||
|  |  | ||||||
|  |     dispatcher(std::time_t t) : time_(t) {} | ||||||
|  |  | ||||||
|  |     bool run() { | ||||||
|  |       using namespace fmt::internal; | ||||||
|  |       return handle(localtime_r(&time_, &tm_)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     bool handle(std::tm* tm) { return tm != nullptr; } | ||||||
|  |  | ||||||
|  |     bool handle(internal::null<>) { | ||||||
|  |       using namespace fmt::internal; | ||||||
|  |       return fallback(localtime_s(&tm_, &time_)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     bool fallback(int res) { return res == 0; } | ||||||
|  |  | ||||||
|  | #if !FMT_MSC_VER | ||||||
|  |     bool fallback(internal::null<>) { | ||||||
|  |       using namespace fmt::internal; | ||||||
|  |       std::tm* tm = std::localtime(&time_); | ||||||
|  |       if (tm) tm_ = *tm; | ||||||
|  |       return tm != nullptr; | ||||||
|  |     } | ||||||
|  | #endif | ||||||
|  |   }; | ||||||
|  |   dispatcher lt(time); | ||||||
|  |   // Too big time values may be unsupported. | ||||||
|  |   if (!lt.run()) FMT_THROW(format_error("time_t value out of range")); | ||||||
|  |   return lt.tm_; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Thread-safe replacement for std::gmtime | ||||||
|  | inline std::tm gmtime(std::time_t time) { | ||||||
|  |   struct dispatcher { | ||||||
|  |     std::time_t time_; | ||||||
|  |     std::tm tm_; | ||||||
|  |  | ||||||
|  |     dispatcher(std::time_t t) : time_(t) {} | ||||||
|  |  | ||||||
|  |     bool run() { | ||||||
|  |       using namespace fmt::internal; | ||||||
|  |       return handle(gmtime_r(&time_, &tm_)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     bool handle(std::tm* tm) { return tm != nullptr; } | ||||||
|  |  | ||||||
|  |     bool handle(internal::null<>) { | ||||||
|  |       using namespace fmt::internal; | ||||||
|  |       return fallback(gmtime_s(&tm_, &time_)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     bool fallback(int res) { return res == 0; } | ||||||
|  |  | ||||||
|  | #if !FMT_MSC_VER | ||||||
|  |     bool fallback(internal::null<>) { | ||||||
|  |       std::tm* tm = std::gmtime(&time_); | ||||||
|  |       if (tm) tm_ = *tm; | ||||||
|  |       return tm != nullptr; | ||||||
|  |     } | ||||||
|  | #endif | ||||||
|  |   }; | ||||||
|  |   dispatcher gt(time); | ||||||
|  |   // Too big time values may be unsupported. | ||||||
|  |   if (!gt.run()) FMT_THROW(format_error("time_t value out of range")); | ||||||
|  |   return gt.tm_; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | namespace internal { | ||||||
|  | inline std::size_t strftime(char* str, std::size_t count, const char* format, | ||||||
|  |                             const std::tm* time) { | ||||||
|  |   return std::strftime(str, count, format, time); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | inline std::size_t strftime(wchar_t* str, std::size_t count, | ||||||
|  |                             const wchar_t* format, const std::tm* time) { | ||||||
|  |   return std::wcsftime(str, count, format, time); | ||||||
|  | } | ||||||
|  | }  // namespace internal | ||||||
|  |  | ||||||
|  | template <typename Char> struct formatter<std::tm, Char> { | ||||||
|  |   template <typename ParseContext> | ||||||
|  |   auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { | ||||||
|  |     auto it = ctx.begin(); | ||||||
|  |     if (it != ctx.end() && *it == ':') ++it; | ||||||
|  |     auto end = it; | ||||||
|  |     while (end != ctx.end() && *end != '}') ++end; | ||||||
|  |     tm_format.reserve(internal::to_unsigned(end - it + 1)); | ||||||
|  |     tm_format.append(it, end); | ||||||
|  |     tm_format.push_back('\0'); | ||||||
|  |     return end; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   template <typename FormatContext> | ||||||
|  |   auto format(const std::tm& tm, FormatContext& ctx) -> decltype(ctx.out()) { | ||||||
|  |     basic_memory_buffer<Char> buf; | ||||||
|  |     std::size_t start = buf.size(); | ||||||
|  |     for (;;) { | ||||||
|  |       std::size_t size = buf.capacity() - start; | ||||||
|  |       std::size_t count = | ||||||
|  |           internal::strftime(&buf[start], size, &tm_format[0], &tm); | ||||||
|  |       if (count != 0) { | ||||||
|  |         buf.resize(start + count); | ||||||
|  |         break; | ||||||
|  |       } | ||||||
|  |       if (size >= tm_format.size() * 256) { | ||||||
|  |         // If the buffer is 256 times larger than the format string, assume | ||||||
|  |         // that `strftime` gives an empty result. There doesn't seem to be a | ||||||
|  |         // better way to distinguish the two cases: | ||||||
|  |         // https://github.com/fmtlib/fmt/issues/367 | ||||||
|  |         break; | ||||||
|  |       } | ||||||
|  |       const std::size_t MIN_GROWTH = 10; | ||||||
|  |       buf.reserve(buf.capacity() + (size > MIN_GROWTH ? size : MIN_GROWTH)); | ||||||
|  |     } | ||||||
|  |     return std::copy(buf.begin(), buf.end(), ctx.out()); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   basic_memory_buffer<Char> tm_format; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | namespace internal { | ||||||
|  | template <typename Period> FMT_CONSTEXPR const char* get_units() { | ||||||
|  |   return nullptr; | ||||||
|  | } | ||||||
|  | template <> FMT_CONSTEXPR const char* get_units<std::atto>() { return "as"; } | ||||||
|  | template <> FMT_CONSTEXPR const char* get_units<std::femto>() { return "fs"; } | ||||||
|  | template <> FMT_CONSTEXPR const char* get_units<std::pico>() { return "ps"; } | ||||||
|  | template <> FMT_CONSTEXPR const char* get_units<std::nano>() { return "ns"; } | ||||||
|  | template <> FMT_CONSTEXPR const char* get_units<std::micro>() { return "µs"; } | ||||||
|  | template <> FMT_CONSTEXPR const char* get_units<std::milli>() { return "ms"; } | ||||||
|  | template <> FMT_CONSTEXPR const char* get_units<std::centi>() { return "cs"; } | ||||||
|  | template <> FMT_CONSTEXPR const char* get_units<std::deci>() { return "ds"; } | ||||||
|  | template <> FMT_CONSTEXPR const char* get_units<std::ratio<1>>() { return "s"; } | ||||||
|  | template <> FMT_CONSTEXPR const char* get_units<std::deca>() { return "das"; } | ||||||
|  | template <> FMT_CONSTEXPR const char* get_units<std::hecto>() { return "hs"; } | ||||||
|  | template <> FMT_CONSTEXPR const char* get_units<std::kilo>() { return "ks"; } | ||||||
|  | template <> FMT_CONSTEXPR const char* get_units<std::mega>() { return "Ms"; } | ||||||
|  | template <> FMT_CONSTEXPR const char* get_units<std::giga>() { return "Gs"; } | ||||||
|  | template <> FMT_CONSTEXPR const char* get_units<std::tera>() { return "Ts"; } | ||||||
|  | template <> FMT_CONSTEXPR const char* get_units<std::peta>() { return "Ps"; } | ||||||
|  | template <> FMT_CONSTEXPR const char* get_units<std::exa>() { return "Es"; } | ||||||
|  | template <> FMT_CONSTEXPR const char* get_units<std::ratio<60>>() { | ||||||
|  |   return "m"; | ||||||
|  | } | ||||||
|  | template <> FMT_CONSTEXPR const char* get_units<std::ratio<3600>>() { | ||||||
|  |   return "h"; | ||||||
|  | } | ||||||
|  |  | ||||||
| enum class numeric_system { | enum class numeric_system { | ||||||
|   standard, |   standard, | ||||||
| @@ -28,8 +200,9 @@ enum class numeric_system { | |||||||
|  |  | ||||||
| // Parses a put_time-like format string and invokes handler actions. | // Parses a put_time-like format string and invokes handler actions. | ||||||
| template <typename Char, typename Handler> | template <typename Char, typename Handler> | ||||||
| FMT_CONSTEXPR const Char *parse_chrono_format( | FMT_CONSTEXPR const Char* parse_chrono_format(const Char* begin, | ||||||
|     const Char *begin, const Char *end, Handler &&handler) { |                                               const Char* end, | ||||||
|  |                                               Handler&& handler) { | ||||||
|   auto ptr = begin; |   auto ptr = begin; | ||||||
|   while (ptr != end) { |   while (ptr != end) { | ||||||
|     auto c = *ptr; |     auto c = *ptr; | ||||||
| @@ -38,11 +211,9 @@ FMT_CONSTEXPR const Char *parse_chrono_format( | |||||||
|       ++ptr; |       ++ptr; | ||||||
|       continue; |       continue; | ||||||
|     } |     } | ||||||
|     if (begin != ptr) |     if (begin != ptr) handler.on_text(begin, ptr); | ||||||
|       handler.on_text(begin, ptr); |     ++ptr;  // consume '%' | ||||||
|     ++ptr; // consume '%' |     if (ptr == end) FMT_THROW(format_error("invalid format")); | ||||||
|     if (ptr == end) |  | ||||||
|       throw format_error("invalid format"); |  | ||||||
|     c = *ptr++; |     c = *ptr++; | ||||||
|     switch (c) { |     switch (c) { | ||||||
|     case '%': |     case '%': | ||||||
| @@ -119,6 +290,12 @@ FMT_CONSTEXPR const Char *parse_chrono_format( | |||||||
|     case 'p': |     case 'p': | ||||||
|       handler.on_am_pm(); |       handler.on_am_pm(); | ||||||
|       break; |       break; | ||||||
|  |     case 'Q': | ||||||
|  |       handler.on_duration_value(); | ||||||
|  |       break; | ||||||
|  |     case 'q': | ||||||
|  |       handler.on_duration_unit(); | ||||||
|  |       break; | ||||||
|     case 'z': |     case 'z': | ||||||
|       handler.on_utc_offset(); |       handler.on_utc_offset(); | ||||||
|       break; |       break; | ||||||
| @@ -127,8 +304,7 @@ FMT_CONSTEXPR const Char *parse_chrono_format( | |||||||
|       break; |       break; | ||||||
|     // Alternative representation: |     // Alternative representation: | ||||||
|     case 'E': { |     case 'E': { | ||||||
|       if (ptr == end) |       if (ptr == end) FMT_THROW(format_error("invalid format")); | ||||||
|         throw format_error("invalid format"); |  | ||||||
|       c = *ptr++; |       c = *ptr++; | ||||||
|       switch (c) { |       switch (c) { | ||||||
|       case 'c': |       case 'c': | ||||||
| @@ -141,13 +317,12 @@ FMT_CONSTEXPR const Char *parse_chrono_format( | |||||||
|         handler.on_loc_time(numeric_system::alternative); |         handler.on_loc_time(numeric_system::alternative); | ||||||
|         break; |         break; | ||||||
|       default: |       default: | ||||||
|         throw format_error("invalid format"); |         FMT_THROW(format_error("invalid format")); | ||||||
|       } |       } | ||||||
|       break; |       break; | ||||||
|     } |     } | ||||||
|     case 'O': |     case 'O': | ||||||
|       if (ptr == end) |       if (ptr == end) FMT_THROW(format_error("invalid format")); | ||||||
|         throw format_error("invalid format"); |  | ||||||
|       c = *ptr++; |       c = *ptr++; | ||||||
|       switch (c) { |       switch (c) { | ||||||
|       case 'w': |       case 'w': | ||||||
| @@ -169,96 +344,259 @@ FMT_CONSTEXPR const Char *parse_chrono_format( | |||||||
|         handler.on_second(numeric_system::alternative); |         handler.on_second(numeric_system::alternative); | ||||||
|         break; |         break; | ||||||
|       default: |       default: | ||||||
|         throw format_error("invalid format"); |         FMT_THROW(format_error("invalid format")); | ||||||
|       } |       } | ||||||
|       break; |       break; | ||||||
|     default: |     default: | ||||||
|       throw format_error("invalid format"); |       FMT_THROW(format_error("invalid format")); | ||||||
|     } |     } | ||||||
|     begin = ptr; |     begin = ptr; | ||||||
|   } |   } | ||||||
|   if (begin != ptr) |   if (begin != ptr) handler.on_text(begin, ptr); | ||||||
|     handler.on_text(begin, ptr); |  | ||||||
|   return ptr; |   return ptr; | ||||||
| } | } | ||||||
|  |  | ||||||
| struct chrono_format_checker { | struct chrono_format_checker { | ||||||
|   void report_no_date() { throw format_error("no date"); } |   FMT_NORETURN void report_no_date() { FMT_THROW(format_error("no date")); } | ||||||
|  |  | ||||||
|   template <typename Char> |   template <typename Char> void on_text(const Char*, const Char*) {} | ||||||
|   void on_text(const Char *, const Char *) {} |   FMT_NORETURN void on_abbr_weekday() { report_no_date(); } | ||||||
|   void on_abbr_weekday() { report_no_date(); } |   FMT_NORETURN void on_full_weekday() { report_no_date(); } | ||||||
|   void on_full_weekday() { report_no_date(); } |   FMT_NORETURN void on_dec0_weekday(numeric_system) { report_no_date(); } | ||||||
|   void on_dec0_weekday(numeric_system) { report_no_date(); } |   FMT_NORETURN void on_dec1_weekday(numeric_system) { report_no_date(); } | ||||||
|   void on_dec1_weekday(numeric_system) { report_no_date(); } |   FMT_NORETURN void on_abbr_month() { report_no_date(); } | ||||||
|   void on_abbr_month() { report_no_date(); } |   FMT_NORETURN void on_full_month() { report_no_date(); } | ||||||
|   void on_full_month() { report_no_date(); } |  | ||||||
|   void on_24_hour(numeric_system) {} |   void on_24_hour(numeric_system) {} | ||||||
|   void on_12_hour(numeric_system) {} |   void on_12_hour(numeric_system) {} | ||||||
|   void on_minute(numeric_system) {} |   void on_minute(numeric_system) {} | ||||||
|   void on_second(numeric_system) {} |   void on_second(numeric_system) {} | ||||||
|   void on_datetime(numeric_system) { report_no_date(); } |   FMT_NORETURN void on_datetime(numeric_system) { report_no_date(); } | ||||||
|   void on_loc_date(numeric_system) { report_no_date(); } |   FMT_NORETURN void on_loc_date(numeric_system) { report_no_date(); } | ||||||
|   void on_loc_time(numeric_system) { report_no_date(); } |   FMT_NORETURN void on_loc_time(numeric_system) { report_no_date(); } | ||||||
|   void on_us_date() { report_no_date(); } |   FMT_NORETURN void on_us_date() { report_no_date(); } | ||||||
|   void on_iso_date() { report_no_date(); } |   FMT_NORETURN void on_iso_date() { report_no_date(); } | ||||||
|   void on_12_hour_time() {} |   void on_12_hour_time() {} | ||||||
|   void on_24_hour_time() {} |   void on_24_hour_time() {} | ||||||
|   void on_iso_time() {} |   void on_iso_time() {} | ||||||
|   void on_am_pm() {} |   void on_am_pm() {} | ||||||
|   void on_utc_offset() { report_no_date(); } |   void on_duration_value() {} | ||||||
|   void on_tz_name() { report_no_date(); } |   void on_duration_unit() {} | ||||||
|  |   FMT_NORETURN void on_utc_offset() { report_no_date(); } | ||||||
|  |   FMT_NORETURN void on_tz_name() { report_no_date(); } | ||||||
| }; | }; | ||||||
|  |  | ||||||
| template <typename Int> | template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)> | ||||||
| inline int to_int(Int value) { | inline bool isnan(T) { | ||||||
|   FMT_ASSERT(value >= (std::numeric_limits<int>::min)() && |   return false; | ||||||
|              value <= (std::numeric_limits<int>::max)(), "invalid value"); | } | ||||||
|  | template <typename T, FMT_ENABLE_IF(std::is_floating_point<T>::value)> | ||||||
|  | inline bool isnan(T value) { | ||||||
|  |   return std::isnan(value); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)> | ||||||
|  | inline bool isfinite(T) { | ||||||
|  |   return true; | ||||||
|  | } | ||||||
|  | template <typename T, FMT_ENABLE_IF(std::is_floating_point<T>::value)> | ||||||
|  | inline bool isfinite(T value) { | ||||||
|  |   return std::isfinite(value); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Convers value to int and checks that it's in the range [0, upper). | ||||||
|  | template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)> | ||||||
|  | inline int to_nonnegative_int(T value, int upper) { | ||||||
|  |   FMT_ASSERT(value >= 0 && value <= upper, "invalid value"); | ||||||
|  |   (void)upper; | ||||||
|  |   return static_cast<int>(value); | ||||||
|  | } | ||||||
|  | template <typename T, FMT_ENABLE_IF(!std::is_integral<T>::value)> | ||||||
|  | inline int to_nonnegative_int(T value, int upper) { | ||||||
|  |   FMT_ASSERT( | ||||||
|  |       std::isnan(value) || (value >= 0 && value <= static_cast<T>(upper)), | ||||||
|  |       "invalid value"); | ||||||
|  |   (void)upper; | ||||||
|   return static_cast<int>(value); |   return static_cast<int>(value); | ||||||
| } | } | ||||||
|  |  | ||||||
| template <typename FormatContext, typename OutputIt> | template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)> | ||||||
|  | inline T mod(T x, int y) { | ||||||
|  |   return x % y; | ||||||
|  | } | ||||||
|  | template <typename T, FMT_ENABLE_IF(std::is_floating_point<T>::value)> | ||||||
|  | inline T mod(T x, int y) { | ||||||
|  |   return std::fmod(x, static_cast<T>(y)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // If T is an integral type, maps T to its unsigned counterpart, otherwise | ||||||
|  | // leaves it unchanged (unlike std::make_unsigned). | ||||||
|  | template <typename T, bool INTEGRAL = std::is_integral<T>::value> | ||||||
|  | struct make_unsigned_or_unchanged { | ||||||
|  |   using type = T; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | template <typename T> struct make_unsigned_or_unchanged<T, true> { | ||||||
|  |   using type = typename std::make_unsigned<T>::type; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | #if FMT_SAFE_DURATION_CAST | ||||||
|  | // throwing version of safe_duration_cast | ||||||
|  | template <typename To, typename FromRep, typename FromPeriod> | ||||||
|  | To fmt_safe_duration_cast(std::chrono::duration<FromRep, FromPeriod> from) { | ||||||
|  |   int ec; | ||||||
|  |   To to = safe_duration_cast::safe_duration_cast<To>(from, ec); | ||||||
|  |   if (ec) FMT_THROW(format_error("cannot format duration")); | ||||||
|  |   return to; | ||||||
|  | } | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | template <typename Rep, typename Period, | ||||||
|  |           FMT_ENABLE_IF(std::is_integral<Rep>::value)> | ||||||
|  | inline std::chrono::duration<Rep, std::milli> get_milliseconds( | ||||||
|  |     std::chrono::duration<Rep, Period> d) { | ||||||
|  |   // this may overflow and/or the result may not fit in the | ||||||
|  |   // target type. | ||||||
|  | #if FMT_SAFE_DURATION_CAST | ||||||
|  |   using CommonSecondsType = | ||||||
|  |       typename std::common_type<decltype(d), std::chrono::seconds>::type; | ||||||
|  |   const auto d_as_common = fmt_safe_duration_cast<CommonSecondsType>(d); | ||||||
|  |   const auto d_as_whole_seconds = | ||||||
|  |       fmt_safe_duration_cast<std::chrono::seconds>(d_as_common); | ||||||
|  |   // this conversion should be nonproblematic | ||||||
|  |   const auto diff = d_as_common - d_as_whole_seconds; | ||||||
|  |   const auto ms = | ||||||
|  |       fmt_safe_duration_cast<std::chrono::duration<Rep, std::milli>>(diff); | ||||||
|  |   return ms; | ||||||
|  | #else | ||||||
|  |   auto s = std::chrono::duration_cast<std::chrono::seconds>(d); | ||||||
|  |   return std::chrono::duration_cast<std::chrono::milliseconds>(d - s); | ||||||
|  | #endif | ||||||
|  | } | ||||||
|  |  | ||||||
|  | template <typename Rep, typename Period, | ||||||
|  |           FMT_ENABLE_IF(std::is_floating_point<Rep>::value)> | ||||||
|  | inline std::chrono::duration<Rep, std::milli> get_milliseconds( | ||||||
|  |     std::chrono::duration<Rep, Period> d) { | ||||||
|  |   using common_type = typename std::common_type<Rep, std::intmax_t>::type; | ||||||
|  |   auto ms = mod(d.count() * static_cast<common_type>(Period::num) / | ||||||
|  |                     static_cast<common_type>(Period::den) * 1000, | ||||||
|  |                 1000); | ||||||
|  |   return std::chrono::duration<Rep, std::milli>(static_cast<Rep>(ms)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | template <typename Rep, typename OutputIt> | ||||||
|  | OutputIt format_chrono_duration_value(OutputIt out, Rep val, int precision) { | ||||||
|  |   if (precision >= 0) return format_to(out, "{:.{}f}", val, precision); | ||||||
|  |   return format_to(out, std::is_floating_point<Rep>::value ? "{:g}" : "{}", | ||||||
|  |                    val); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | template <typename Period, typename OutputIt> | ||||||
|  | static OutputIt format_chrono_duration_unit(OutputIt out) { | ||||||
|  |   if (const char* unit = get_units<Period>()) return format_to(out, "{}", unit); | ||||||
|  |   if (Period::den == 1) return format_to(out, "[{}]s", Period::num); | ||||||
|  |   return format_to(out, "[{}/{}]s", Period::num, Period::den); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | template <typename FormatContext, typename OutputIt, typename Rep, | ||||||
|  |           typename Period> | ||||||
| struct chrono_formatter { | struct chrono_formatter { | ||||||
|   FormatContext &context; |   FormatContext& context; | ||||||
|   OutputIt out; |   OutputIt out; | ||||||
|   std::chrono::seconds s; |   int precision; | ||||||
|   std::chrono::milliseconds ms; |   // rep is unsigned to avoid overflow. | ||||||
|  |   using rep = | ||||||
|  |       conditional_t<std::is_integral<Rep>::value && sizeof(Rep) < sizeof(int), | ||||||
|  |                     unsigned, typename make_unsigned_or_unchanged<Rep>::type>; | ||||||
|  |   rep val; | ||||||
|  |   using seconds = std::chrono::duration<rep>; | ||||||
|  |   seconds s; | ||||||
|  |   using milliseconds = std::chrono::duration<rep, std::milli>; | ||||||
|  |   bool negative; | ||||||
|  |  | ||||||
|   typedef typename FormatContext::char_type char_type; |   using char_type = typename FormatContext::char_type; | ||||||
|  |  | ||||||
|   explicit chrono_formatter(FormatContext &ctx, OutputIt o) |   explicit chrono_formatter(FormatContext& ctx, OutputIt o, | ||||||
|     : context(ctx), out(o) {} |                             std::chrono::duration<Rep, Period> d) | ||||||
|  |       : context(ctx), out(o), val(d.count()), negative(false) { | ||||||
|  |     if (d.count() < 0) { | ||||||
|  |       val = 0 - val; | ||||||
|  |       negative = true; | ||||||
|  |     } | ||||||
|  |  | ||||||
|   int hour() const { return to_int((s.count() / 3600) % 24); } |     // this may overflow and/or the result may not fit in the | ||||||
|  |     // target type. | ||||||
|   int hour12() const { | #if FMT_SAFE_DURATION_CAST | ||||||
|     auto hour = to_int((s.count() / 3600) % 12); |     // might need checked conversion (rep!=Rep) | ||||||
|     return hour > 0 ? hour : 12; |     auto tmpval = std::chrono::duration<rep, Period>(val); | ||||||
|  |     s = fmt_safe_duration_cast<seconds>(tmpval); | ||||||
|  | #else | ||||||
|  |     s = std::chrono::duration_cast<seconds>( | ||||||
|  |         std::chrono::duration<rep, Period>(val)); | ||||||
|  | #endif | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   int minute() const { return to_int((s.count() / 60) % 60); } |   // returns true if nan or inf, writes to out. | ||||||
|   int second() const { return to_int(s.count() % 60); } |   bool handle_nan_inf() { | ||||||
|  |     if (isfinite(val)) { | ||||||
|  |       return false; | ||||||
|  |     } | ||||||
|  |     if (isnan(val)) { | ||||||
|  |       write_nan(); | ||||||
|  |       return true; | ||||||
|  |     } | ||||||
|  |     // must be +-inf | ||||||
|  |     if (val > 0) { | ||||||
|  |       write_pinf(); | ||||||
|  |     } else { | ||||||
|  |       write_ninf(); | ||||||
|  |     } | ||||||
|  |     return true; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   Rep hour() const { return static_cast<Rep>(mod((s.count() / 3600), 24)); } | ||||||
|  |  | ||||||
|  |   Rep hour12() const { | ||||||
|  |     Rep hour = static_cast<Rep>(mod((s.count() / 3600), 12)); | ||||||
|  |     return hour <= 0 ? 12 : hour; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   Rep minute() const { return static_cast<Rep>(mod((s.count() / 60), 60)); } | ||||||
|  |   Rep second() const { return static_cast<Rep>(mod(s.count(), 60)); } | ||||||
|  |  | ||||||
|   std::tm time() const { |   std::tm time() const { | ||||||
|     auto time = std::tm(); |     auto time = std::tm(); | ||||||
|     time.tm_hour = hour(); |     time.tm_hour = to_nonnegative_int(hour(), 24); | ||||||
|     time.tm_min = minute(); |     time.tm_min = to_nonnegative_int(minute(), 60); | ||||||
|     time.tm_sec = second(); |     time.tm_sec = to_nonnegative_int(second(), 60); | ||||||
|     return time; |     return time; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   void write(int value, int width) { |   void write_sign() { | ||||||
|     typedef typename int_traits<int>::main_type main_type; |     if (negative) { | ||||||
|     main_type n = to_unsigned(value); |       *out++ = '-'; | ||||||
|  |       negative = false; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   void write(Rep value, int width) { | ||||||
|  |     write_sign(); | ||||||
|  |     if (isnan(value)) return write_nan(); | ||||||
|  |     uint32_or_64_t<int> n = to_unsigned( | ||||||
|  |         to_nonnegative_int(value, (std::numeric_limits<int>::max)())); | ||||||
|     int num_digits = internal::count_digits(n); |     int num_digits = internal::count_digits(n); | ||||||
|     if (width > num_digits) |     if (width > num_digits) out = std::fill_n(out, width - num_digits, '0'); | ||||||
|       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); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   void format_localized(const tm &time, const char *format) { |   void write_nan() { std::copy_n("nan", 3, out); } | ||||||
|  |   void write_pinf() { std::copy_n("inf", 3, out); } | ||||||
|  |   void write_ninf() { std::copy_n("-inf", 4, out); } | ||||||
|  |  | ||||||
|  |   void format_localized(const tm& time, const char* format) { | ||||||
|  |     if (isnan(val)) return write_nan(); | ||||||
|     auto locale = context.locale().template get<std::locale>(); |     auto locale = context.locale().template get<std::locale>(); | ||||||
|     auto &facet = std::use_facet<std::time_put<char_type>>(locale); |     auto& facet = std::use_facet<std::time_put<char_type>>(locale); | ||||||
|     std::basic_ostringstream<char_type> os; |     std::basic_ostringstream<char_type> os; | ||||||
|     os.imbue(locale); |     os.imbue(locale); | ||||||
|     facet.put(os, os, ' ', &time, format, format + std::strlen(format)); |     facet.put(os, os, ' ', &time, format, format + std::strlen(format)); | ||||||
| @@ -266,7 +604,7 @@ struct chrono_formatter { | |||||||
|     std::copy(str.begin(), str.end(), out); |     std::copy(str.begin(), str.end(), out); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   void on_text(const char_type *begin, const char_type *end) { |   void on_text(const char_type* begin, const char_type* end) { | ||||||
|     std::copy(begin, end, out); |     std::copy(begin, end, out); | ||||||
|   } |   } | ||||||
|  |  | ||||||
| @@ -286,46 +624,70 @@ struct chrono_formatter { | |||||||
|   void on_tz_name() {} |   void on_tz_name() {} | ||||||
|  |  | ||||||
|   void on_24_hour(numeric_system ns) { |   void on_24_hour(numeric_system ns) { | ||||||
|     if (ns == numeric_system::standard) |     if (handle_nan_inf()) return; | ||||||
|       return write(hour(), 2); |  | ||||||
|  |     if (ns == numeric_system::standard) return write(hour(), 2); | ||||||
|     auto time = tm(); |     auto time = tm(); | ||||||
|     time.tm_hour = hour(); |     time.tm_hour = to_nonnegative_int(hour(), 24); | ||||||
|     format_localized(time, "%OH"); |     format_localized(time, "%OH"); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   void on_12_hour(numeric_system ns) { |   void on_12_hour(numeric_system ns) { | ||||||
|     if (ns == numeric_system::standard) |     if (handle_nan_inf()) return; | ||||||
|       return write(hour12(), 2); |  | ||||||
|  |     if (ns == numeric_system::standard) return write(hour12(), 2); | ||||||
|     auto time = tm(); |     auto time = tm(); | ||||||
|     time.tm_hour = hour(); |     time.tm_hour = to_nonnegative_int(hour12(), 12); | ||||||
|     format_localized(time, "%OI"); |     format_localized(time, "%OI"); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   void on_minute(numeric_system ns) { |   void on_minute(numeric_system ns) { | ||||||
|     if (ns == numeric_system::standard) |     if (handle_nan_inf()) return; | ||||||
|       return write(minute(), 2); |  | ||||||
|  |     if (ns == numeric_system::standard) return write(minute(), 2); | ||||||
|     auto time = tm(); |     auto time = tm(); | ||||||
|     time.tm_min = minute(); |     time.tm_min = to_nonnegative_int(minute(), 60); | ||||||
|     format_localized(time, "%OM"); |     format_localized(time, "%OM"); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   void on_second(numeric_system ns) { |   void on_second(numeric_system ns) { | ||||||
|  |     if (handle_nan_inf()) return; | ||||||
|  |  | ||||||
|     if (ns == numeric_system::standard) { |     if (ns == numeric_system::standard) { | ||||||
|       write(second(), 2); |       write(second(), 2); | ||||||
|  | #if FMT_SAFE_DURATION_CAST | ||||||
|  |       // convert rep->Rep | ||||||
|  |       using duration_rep = std::chrono::duration<rep, Period>; | ||||||
|  |       using duration_Rep = std::chrono::duration<Rep, Period>; | ||||||
|  |       auto tmpval = fmt_safe_duration_cast<duration_Rep>(duration_rep{val}); | ||||||
|  | #else | ||||||
|  |       auto tmpval = std::chrono::duration<Rep, Period>(val); | ||||||
|  | #endif | ||||||
|  |       auto ms = get_milliseconds(tmpval); | ||||||
|       if (ms != std::chrono::milliseconds(0)) { |       if (ms != std::chrono::milliseconds(0)) { | ||||||
|         *out++ = '.'; |         *out++ = '.'; | ||||||
|         write(to_int(ms.count()), 3); |         write(ms.count(), 3); | ||||||
|       } |       } | ||||||
|       return; |       return; | ||||||
|     } |     } | ||||||
|     auto time = tm(); |     auto time = tm(); | ||||||
|     time.tm_sec = second(); |     time.tm_sec = to_nonnegative_int(second(), 60); | ||||||
|     format_localized(time, "%OS"); |     format_localized(time, "%OS"); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   void on_12_hour_time() { format_localized(time(), "%r"); } |   void on_12_hour_time() { | ||||||
|  |     if (handle_nan_inf()) return; | ||||||
|  |  | ||||||
|  |     format_localized(time(), "%r"); | ||||||
|  |   } | ||||||
|  |  | ||||||
|   void on_24_hour_time() { |   void on_24_hour_time() { | ||||||
|  |     if (handle_nan_inf()) { | ||||||
|  |       *out++ = ':'; | ||||||
|  |       handle_nan_inf(); | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     write(hour(), 2); |     write(hour(), 2); | ||||||
|     *out++ = ':'; |     *out++ = ':'; | ||||||
|     write(minute(), 2); |     write(minute(), 2); | ||||||
| @@ -334,115 +696,130 @@ struct chrono_formatter { | |||||||
|   void on_iso_time() { |   void on_iso_time() { | ||||||
|     on_24_hour_time(); |     on_24_hour_time(); | ||||||
|     *out++ = ':'; |     *out++ = ':'; | ||||||
|  |     if (handle_nan_inf()) return; | ||||||
|     write(second(), 2); |     write(second(), 2); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   void on_am_pm() { format_localized(time(), "%p"); } |   void on_am_pm() { | ||||||
|  |     if (handle_nan_inf()) return; | ||||||
|  |     format_localized(time(), "%p"); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   void on_duration_value() { | ||||||
|  |     if (handle_nan_inf()) return; | ||||||
|  |     write_sign(); | ||||||
|  |     out = format_chrono_duration_value(out, val, precision); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   void on_duration_unit() { out = format_chrono_duration_unit<Period>(out); } | ||||||
| }; | }; | ||||||
| }  // namespace internal | }  // namespace internal | ||||||
|  |  | ||||||
| template <typename Period> FMT_CONSTEXPR const char *get_units() { |  | ||||||
|   return FMT_NULL; |  | ||||||
| } |  | ||||||
| template <> FMT_CONSTEXPR const char *get_units<std::atto>() { return "as"; } |  | ||||||
| template <> FMT_CONSTEXPR const char *get_units<std::femto>() { return "fs"; } |  | ||||||
| template <> FMT_CONSTEXPR const char *get_units<std::pico>() { return "ps"; } |  | ||||||
| template <> FMT_CONSTEXPR const char *get_units<std::nano>() { return "ns"; } |  | ||||||
| template <> FMT_CONSTEXPR const char *get_units<std::micro>() { return "µs"; } |  | ||||||
| template <> FMT_CONSTEXPR const char *get_units<std::milli>() { return "ms"; } |  | ||||||
| template <> FMT_CONSTEXPR const char *get_units<std::centi>() { return "cs"; } |  | ||||||
| template <> FMT_CONSTEXPR const char *get_units<std::deci>() { return "ds"; } |  | ||||||
| template <> FMT_CONSTEXPR const char *get_units<std::ratio<1>>() { return "s"; } |  | ||||||
| template <> FMT_CONSTEXPR const char *get_units<std::deca>() { return "das"; } |  | ||||||
| template <> FMT_CONSTEXPR const char *get_units<std::hecto>() { return "hs"; } |  | ||||||
| template <> FMT_CONSTEXPR const char *get_units<std::kilo>() { return "ks"; } |  | ||||||
| template <> FMT_CONSTEXPR const char *get_units<std::mega>() { return "Ms"; } |  | ||||||
| template <> FMT_CONSTEXPR const char *get_units<std::giga>() { return "Gs"; } |  | ||||||
| template <> FMT_CONSTEXPR const char *get_units<std::tera>() { return "Ts"; } |  | ||||||
| template <> FMT_CONSTEXPR const char *get_units<std::peta>() { return "Ps"; } |  | ||||||
| template <> FMT_CONSTEXPR const char *get_units<std::exa>() { return "Es"; } |  | ||||||
| template <> FMT_CONSTEXPR const char *get_units<std::ratio<60>>() { |  | ||||||
|   return "m"; |  | ||||||
| } |  | ||||||
| template <> FMT_CONSTEXPR const char *get_units<std::ratio<3600>>() { |  | ||||||
|   return "h"; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| template <typename Rep, typename Period, typename Char> | template <typename Rep, typename Period, typename Char> | ||||||
| struct formatter<std::chrono::duration<Rep, Period>, Char> { | struct formatter<std::chrono::duration<Rep, Period>, Char> { | ||||||
|  private: |  private: | ||||||
|   align_spec spec; |   basic_format_specs<Char> specs; | ||||||
|   internal::arg_ref<Char> width_ref; |   int precision; | ||||||
|  |   using arg_ref_type = internal::arg_ref<Char>; | ||||||
|  |   arg_ref_type width_ref; | ||||||
|  |   arg_ref_type precision_ref; | ||||||
|   mutable basic_string_view<Char> format_str; |   mutable basic_string_view<Char> format_str; | ||||||
|   typedef std::chrono::duration<Rep, Period> duration; |   using duration = std::chrono::duration<Rep, Period>; | ||||||
|  |  | ||||||
|   struct spec_handler { |   struct spec_handler { | ||||||
|     formatter &f; |     formatter& f; | ||||||
|     basic_parse_context<Char> &context; |     basic_parse_context<Char>& context; | ||||||
|  |     basic_string_view<Char> format_str; | ||||||
|  |  | ||||||
|     typedef internal::arg_ref<Char> arg_ref_type; |     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) { |  | ||||||
|       context.check_arg_id(arg_id); |       context.check_arg_id(arg_id); | ||||||
|       return arg_ref_type(arg_id); |       return arg_ref_type(arg_id); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     FMT_CONSTEXPR arg_ref_type make_arg_ref(basic_string_view<Char> arg_id) { | ||||||
|  |       context.check_arg_id(arg_id); | ||||||
|  |       const auto str_val = internal::string_view_metadata(format_str, 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) { | ||||||
|       return arg_ref_type(context.next_arg_id()); |       return arg_ref_type(context.next_arg_id()); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     void on_error(const char *msg) { throw format_error(msg); } |     void on_error(const char* msg) { FMT_THROW(format_error(msg)); } | ||||||
|     void on_fill(Char fill) { f.spec.fill_ = fill; } |     void on_fill(Char fill) { f.specs.fill[0] = fill; } | ||||||
|     void on_align(alignment align) { f.spec.align_ = align; } |     void on_align(align_t align) { f.specs.align = align; } | ||||||
|     void on_width(unsigned width) { f.spec.width_ = width; } |     void on_width(unsigned width) { f.specs.width = width; } | ||||||
|  |     void on_precision(unsigned precision) { f.precision = precision; } | ||||||
|  |     void end_precision() {} | ||||||
|  |  | ||||||
|     template <typename Id> |     template <typename Id> void on_dynamic_width(Id arg_id) { | ||||||
|     void on_dynamic_width(Id arg_id) { |  | ||||||
|       f.width_ref = make_arg_ref(arg_id); |       f.width_ref = make_arg_ref(arg_id); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     template <typename Id> void on_dynamic_precision(Id arg_id) { | ||||||
|  |       f.precision_ref = make_arg_ref(arg_id); | ||||||
|  |     } | ||||||
|   }; |   }; | ||||||
|  |  | ||||||
|  public: |   using iterator = typename basic_parse_context<Char>::iterator; | ||||||
|   formatter() : spec() {} |   struct parse_range { | ||||||
|  |     iterator begin; | ||||||
|  |     iterator end; | ||||||
|  |   }; | ||||||
|  |  | ||||||
|   FMT_CONSTEXPR auto parse(basic_parse_context<Char> &ctx) |   FMT_CONSTEXPR parse_range do_parse(basic_parse_context<Char>& ctx) { | ||||||
|       -> decltype(ctx.begin()) { |  | ||||||
|     auto begin = ctx.begin(), end = ctx.end(); |     auto begin = ctx.begin(), end = ctx.end(); | ||||||
|     if (begin == end) return begin; |     if (begin == end || *begin == '}') return {begin, begin}; | ||||||
|     spec_handler handler{*this, ctx}; |     spec_handler handler{*this, ctx, format_str}; | ||||||
|     begin = internal::parse_align(begin, end, handler); |     begin = internal::parse_align(begin, end, handler); | ||||||
|     if (begin == end) return begin; |     if (begin == end) return {begin, begin}; | ||||||
|     begin = internal::parse_width(begin, end, handler); |     begin = internal::parse_width(begin, end, handler); | ||||||
|  |     if (begin == end) return {begin, begin}; | ||||||
|  |     if (*begin == '.') { | ||||||
|  |       if (std::is_floating_point<Rep>::value) | ||||||
|  |         begin = internal::parse_precision(begin, end, handler); | ||||||
|  |       else | ||||||
|  |         handler.on_error("precision not allowed for this argument type"); | ||||||
|  |     } | ||||||
|     end = parse_chrono_format(begin, end, internal::chrono_format_checker()); |     end = parse_chrono_format(begin, end, internal::chrono_format_checker()); | ||||||
|     format_str = basic_string_view<Char>(&*begin, internal::to_unsigned(end - begin)); |     return {begin, end}; | ||||||
|     return end; |   } | ||||||
|  |  | ||||||
|  |  public: | ||||||
|  |   formatter() : precision(-1) {} | ||||||
|  |  | ||||||
|  |   FMT_CONSTEXPR auto parse(basic_parse_context<Char>& ctx) | ||||||
|  |       -> decltype(ctx.begin()) { | ||||||
|  |     auto range = do_parse(ctx); | ||||||
|  |     format_str = basic_string_view<Char>( | ||||||
|  |         &*range.begin, internal::to_unsigned(range.end - range.begin)); | ||||||
|  |     return range.end; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   template <typename FormatContext> |   template <typename FormatContext> | ||||||
|   auto format(const duration &d, FormatContext &ctx) |   auto format(const duration& d, FormatContext& ctx) -> decltype(ctx.out()) { | ||||||
|       -> decltype(ctx.out()) { |  | ||||||
|     auto begin = format_str.begin(), end = format_str.end(); |     auto begin = format_str.begin(), end = format_str.end(); | ||||||
|     memory_buffer buf; |     // As a possible future optimization, we could avoid extra copying if width | ||||||
|     typedef output_range<decltype(ctx.out()), Char> range; |     // is not specified. | ||||||
|     basic_writer<range> w(range(ctx.out())); |     basic_memory_buffer<Char> buf; | ||||||
|  |     auto out = std::back_inserter(buf); | ||||||
|  |     using range = internal::output_range<decltype(ctx.out()), Char>; | ||||||
|  |     internal::basic_writer<range> w(range(ctx.out())); | ||||||
|  |     internal::handle_dynamic_spec<internal::width_checker>( | ||||||
|  |         specs.width, width_ref, ctx, format_str.begin()); | ||||||
|  |     internal::handle_dynamic_spec<internal::precision_checker>( | ||||||
|  |         precision, precision_ref, ctx, format_str.begin()); | ||||||
|     if (begin == end || *begin == '}') { |     if (begin == end || *begin == '}') { | ||||||
|       if (const char *unit = get_units<Period>()) |       out = internal::format_chrono_duration_value(out, d.count(), precision); | ||||||
|         format_to(buf, "{}{}", d.count(), unit); |       internal::format_chrono_duration_unit<Period>(out); | ||||||
|       else if (Period::den == 1) |  | ||||||
|         format_to(buf, "{}[{}]s", d.count(), Period::num); |  | ||||||
|       else |  | ||||||
|         format_to(buf, "{}[{}/{}]s", d.count(), Period::num, Period::den); |  | ||||||
|       internal::handle_dynamic_spec<internal::width_checker>( |  | ||||||
|         spec.width_, width_ref, ctx); |  | ||||||
|     } else { |     } else { | ||||||
|       auto out = std::back_inserter(buf); |       internal::chrono_formatter<FormatContext, decltype(out), Rep, Period> f( | ||||||
|       internal::chrono_formatter<FormatContext, decltype(out)> f(ctx, out); |           ctx, out, d); | ||||||
|       f.s = std::chrono::duration_cast<std::chrono::seconds>(d); |       f.precision = precision; | ||||||
|       f.ms = std::chrono::duration_cast<std::chrono::milliseconds>(d - f.s); |  | ||||||
|       parse_chrono_format(begin, end, f); |       parse_chrono_format(begin, end, f); | ||||||
|     } |     } | ||||||
|     w.write(buf.data(), buf.size(), spec); |     w.write(buf.data(), buf.size(), specs); | ||||||
|     return w.out(); |     return w.out(); | ||||||
|   } |   } | ||||||
| }; | }; | ||||||
|   | |||||||
| @@ -12,184 +12,149 @@ | |||||||
|  |  | ||||||
| FMT_BEGIN_NAMESPACE | FMT_BEGIN_NAMESPACE | ||||||
|  |  | ||||||
| #ifdef FMT_DEPRECATED_COLORS |  | ||||||
|  |  | ||||||
| // color and (v)print_colored are deprecated. |  | ||||||
| enum color { black, red, green, yellow, blue, magenta, cyan, white }; |  | ||||||
| FMT_API void vprint_colored(color c, string_view format, format_args args); |  | ||||||
| FMT_API void vprint_colored(color c, wstring_view format, wformat_args args); |  | ||||||
| template <typename... Args> |  | ||||||
| inline void print_colored(color c, string_view format_str, |  | ||||||
|                           const Args & ... args) { |  | ||||||
|   vprint_colored(c, format_str, make_format_args(args...)); |  | ||||||
| } |  | ||||||
| template <typename... Args> |  | ||||||
| inline void print_colored(color c, wstring_view format_str, |  | ||||||
|                           const Args & ... args) { |  | ||||||
|   vprint_colored(c, format_str, make_format_args<wformat_context>(args...)); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| inline void vprint_colored(color c, string_view format, format_args args) { |  | ||||||
|   char escape[] = "\x1b[30m"; |  | ||||||
|   escape[3] = static_cast<char>('0' + c); |  | ||||||
|   std::fputs(escape, stdout); |  | ||||||
|   vprint(format, args); |  | ||||||
|   std::fputs(internal::data::RESET_COLOR, stdout); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| inline void vprint_colored(color c, wstring_view format, wformat_args args) { |  | ||||||
|   wchar_t escape[] = L"\x1b[30m"; |  | ||||||
|   escape[3] = static_cast<wchar_t>('0' + c); |  | ||||||
|   std::fputws(escape, stdout); |  | ||||||
|   vprint(format, args); |  | ||||||
|   std::fputws(internal::data::WRESET_COLOR, stdout); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| #else |  | ||||||
|  |  | ||||||
| enum class color : uint32_t { | enum class color : uint32_t { | ||||||
|   alice_blue              = 0xF0F8FF, // rgb(240,248,255) |   alice_blue = 0xF0F8FF,               // rgb(240,248,255) | ||||||
|   antique_white           = 0xFAEBD7, // rgb(250,235,215) |   antique_white = 0xFAEBD7,            // rgb(250,235,215) | ||||||
|   aqua                    = 0x00FFFF, // rgb(0,255,255) |   aqua = 0x00FFFF,                     // rgb(0,255,255) | ||||||
|   aquamarine              = 0x7FFFD4, // rgb(127,255,212) |   aquamarine = 0x7FFFD4,               // rgb(127,255,212) | ||||||
|   azure                   = 0xF0FFFF, // rgb(240,255,255) |   azure = 0xF0FFFF,                    // rgb(240,255,255) | ||||||
|   beige                   = 0xF5F5DC, // rgb(245,245,220) |   beige = 0xF5F5DC,                    // rgb(245,245,220) | ||||||
|   bisque                  = 0xFFE4C4, // rgb(255,228,196) |   bisque = 0xFFE4C4,                   // rgb(255,228,196) | ||||||
|   black                   = 0x000000, // rgb(0,0,0) |   black = 0x000000,                    // rgb(0,0,0) | ||||||
|   blanched_almond         = 0xFFEBCD, // rgb(255,235,205) |   blanched_almond = 0xFFEBCD,          // rgb(255,235,205) | ||||||
|   blue                    = 0x0000FF, // rgb(0,0,255) |   blue = 0x0000FF,                     // rgb(0,0,255) | ||||||
|   blue_violet             = 0x8A2BE2, // rgb(138,43,226) |   blue_violet = 0x8A2BE2,              // rgb(138,43,226) | ||||||
|   brown                   = 0xA52A2A, // rgb(165,42,42) |   brown = 0xA52A2A,                    // rgb(165,42,42) | ||||||
|   burly_wood              = 0xDEB887, // rgb(222,184,135) |   burly_wood = 0xDEB887,               // rgb(222,184,135) | ||||||
|   cadet_blue              = 0x5F9EA0, // rgb(95,158,160) |   cadet_blue = 0x5F9EA0,               // rgb(95,158,160) | ||||||
|   chartreuse              = 0x7FFF00, // rgb(127,255,0) |   chartreuse = 0x7FFF00,               // rgb(127,255,0) | ||||||
|   chocolate               = 0xD2691E, // rgb(210,105,30) |   chocolate = 0xD2691E,                // rgb(210,105,30) | ||||||
|   coral                   = 0xFF7F50, // rgb(255,127,80) |   coral = 0xFF7F50,                    // rgb(255,127,80) | ||||||
|   cornflower_blue         = 0x6495ED, // rgb(100,149,237) |   cornflower_blue = 0x6495ED,          // rgb(100,149,237) | ||||||
|   cornsilk                = 0xFFF8DC, // rgb(255,248,220) |   cornsilk = 0xFFF8DC,                 // rgb(255,248,220) | ||||||
|   crimson                 = 0xDC143C, // rgb(220,20,60) |   crimson = 0xDC143C,                  // rgb(220,20,60) | ||||||
|   cyan                    = 0x00FFFF, // rgb(0,255,255) |   cyan = 0x00FFFF,                     // rgb(0,255,255) | ||||||
|   dark_blue               = 0x00008B, // rgb(0,0,139) |   dark_blue = 0x00008B,                // rgb(0,0,139) | ||||||
|   dark_cyan               = 0x008B8B, // rgb(0,139,139) |   dark_cyan = 0x008B8B,                // rgb(0,139,139) | ||||||
|   dark_golden_rod         = 0xB8860B, // rgb(184,134,11) |   dark_golden_rod = 0xB8860B,          // rgb(184,134,11) | ||||||
|   dark_gray               = 0xA9A9A9, // rgb(169,169,169) |   dark_gray = 0xA9A9A9,                // rgb(169,169,169) | ||||||
|   dark_green              = 0x006400, // rgb(0,100,0) |   dark_green = 0x006400,               // rgb(0,100,0) | ||||||
|   dark_khaki              = 0xBDB76B, // rgb(189,183,107) |   dark_khaki = 0xBDB76B,               // rgb(189,183,107) | ||||||
|   dark_magenta            = 0x8B008B, // rgb(139,0,139) |   dark_magenta = 0x8B008B,             // rgb(139,0,139) | ||||||
|   dark_olive_green        = 0x556B2F, // rgb(85,107,47) |   dark_olive_green = 0x556B2F,         // rgb(85,107,47) | ||||||
|   dark_orange             = 0xFF8C00, // rgb(255,140,0) |   dark_orange = 0xFF8C00,              // rgb(255,140,0) | ||||||
|   dark_orchid             = 0x9932CC, // rgb(153,50,204) |   dark_orchid = 0x9932CC,              // rgb(153,50,204) | ||||||
|   dark_red                = 0x8B0000, // rgb(139,0,0) |   dark_red = 0x8B0000,                 // rgb(139,0,0) | ||||||
|   dark_salmon             = 0xE9967A, // rgb(233,150,122) |   dark_salmon = 0xE9967A,              // rgb(233,150,122) | ||||||
|   dark_sea_green          = 0x8FBC8F, // rgb(143,188,143) |   dark_sea_green = 0x8FBC8F,           // rgb(143,188,143) | ||||||
|   dark_slate_blue         = 0x483D8B, // rgb(72,61,139) |   dark_slate_blue = 0x483D8B,          // rgb(72,61,139) | ||||||
|   dark_slate_gray         = 0x2F4F4F, // rgb(47,79,79) |   dark_slate_gray = 0x2F4F4F,          // rgb(47,79,79) | ||||||
|   dark_turquoise          = 0x00CED1, // rgb(0,206,209) |   dark_turquoise = 0x00CED1,           // rgb(0,206,209) | ||||||
|   dark_violet             = 0x9400D3, // rgb(148,0,211) |   dark_violet = 0x9400D3,              // rgb(148,0,211) | ||||||
|   deep_pink               = 0xFF1493, // rgb(255,20,147) |   deep_pink = 0xFF1493,                // rgb(255,20,147) | ||||||
|   deep_sky_blue           = 0x00BFFF, // rgb(0,191,255) |   deep_sky_blue = 0x00BFFF,            // rgb(0,191,255) | ||||||
|   dim_gray                = 0x696969, // rgb(105,105,105) |   dim_gray = 0x696969,                 // rgb(105,105,105) | ||||||
|   dodger_blue             = 0x1E90FF, // rgb(30,144,255) |   dodger_blue = 0x1E90FF,              // rgb(30,144,255) | ||||||
|   fire_brick              = 0xB22222, // rgb(178,34,34) |   fire_brick = 0xB22222,               // rgb(178,34,34) | ||||||
|   floral_white            = 0xFFFAF0, // rgb(255,250,240) |   floral_white = 0xFFFAF0,             // rgb(255,250,240) | ||||||
|   forest_green            = 0x228B22, // rgb(34,139,34) |   forest_green = 0x228B22,             // rgb(34,139,34) | ||||||
|   fuchsia                 = 0xFF00FF, // rgb(255,0,255) |   fuchsia = 0xFF00FF,                  // rgb(255,0,255) | ||||||
|   gainsboro               = 0xDCDCDC, // rgb(220,220,220) |   gainsboro = 0xDCDCDC,                // rgb(220,220,220) | ||||||
|   ghost_white             = 0xF8F8FF, // rgb(248,248,255) |   ghost_white = 0xF8F8FF,              // rgb(248,248,255) | ||||||
|   gold                    = 0xFFD700, // rgb(255,215,0) |   gold = 0xFFD700,                     // rgb(255,215,0) | ||||||
|   golden_rod              = 0xDAA520, // rgb(218,165,32) |   golden_rod = 0xDAA520,               // rgb(218,165,32) | ||||||
|   gray                    = 0x808080, // rgb(128,128,128) |   gray = 0x808080,                     // rgb(128,128,128) | ||||||
|   green                   = 0x008000, // rgb(0,128,0) |   green = 0x008000,                    // rgb(0,128,0) | ||||||
|   green_yellow            = 0xADFF2F, // rgb(173,255,47) |   green_yellow = 0xADFF2F,             // rgb(173,255,47) | ||||||
|   honey_dew               = 0xF0FFF0, // rgb(240,255,240) |   honey_dew = 0xF0FFF0,                // rgb(240,255,240) | ||||||
|   hot_pink                = 0xFF69B4, // rgb(255,105,180) |   hot_pink = 0xFF69B4,                 // rgb(255,105,180) | ||||||
|   indian_red              = 0xCD5C5C, // rgb(205,92,92) |   indian_red = 0xCD5C5C,               // rgb(205,92,92) | ||||||
|   indigo                  = 0x4B0082, // rgb(75,0,130) |   indigo = 0x4B0082,                   // rgb(75,0,130) | ||||||
|   ivory                   = 0xFFFFF0, // rgb(255,255,240) |   ivory = 0xFFFFF0,                    // rgb(255,255,240) | ||||||
|   khaki                   = 0xF0E68C, // rgb(240,230,140) |   khaki = 0xF0E68C,                    // rgb(240,230,140) | ||||||
|   lavender                = 0xE6E6FA, // rgb(230,230,250) |   lavender = 0xE6E6FA,                 // rgb(230,230,250) | ||||||
|   lavender_blush          = 0xFFF0F5, // rgb(255,240,245) |   lavender_blush = 0xFFF0F5,           // rgb(255,240,245) | ||||||
|   lawn_green              = 0x7CFC00, // rgb(124,252,0) |   lawn_green = 0x7CFC00,               // rgb(124,252,0) | ||||||
|   lemon_chiffon           = 0xFFFACD, // rgb(255,250,205) |   lemon_chiffon = 0xFFFACD,            // rgb(255,250,205) | ||||||
|   light_blue              = 0xADD8E6, // rgb(173,216,230) |   light_blue = 0xADD8E6,               // rgb(173,216,230) | ||||||
|   light_coral             = 0xF08080, // rgb(240,128,128) |   light_coral = 0xF08080,              // rgb(240,128,128) | ||||||
|   light_cyan              = 0xE0FFFF, // rgb(224,255,255) |   light_cyan = 0xE0FFFF,               // rgb(224,255,255) | ||||||
|   light_golden_rod_yellow = 0xFAFAD2, // rgb(250,250,210) |   light_golden_rod_yellow = 0xFAFAD2,  // rgb(250,250,210) | ||||||
|   light_gray              = 0xD3D3D3, // rgb(211,211,211) |   light_gray = 0xD3D3D3,               // rgb(211,211,211) | ||||||
|   light_green             = 0x90EE90, // rgb(144,238,144) |   light_green = 0x90EE90,              // rgb(144,238,144) | ||||||
|   light_pink              = 0xFFB6C1, // rgb(255,182,193) |   light_pink = 0xFFB6C1,               // rgb(255,182,193) | ||||||
|   light_salmon            = 0xFFA07A, // rgb(255,160,122) |   light_salmon = 0xFFA07A,             // rgb(255,160,122) | ||||||
|   light_sea_green         = 0x20B2AA, // rgb(32,178,170) |   light_sea_green = 0x20B2AA,          // rgb(32,178,170) | ||||||
|   light_sky_blue          = 0x87CEFA, // rgb(135,206,250) |   light_sky_blue = 0x87CEFA,           // rgb(135,206,250) | ||||||
|   light_slate_gray        = 0x778899, // rgb(119,136,153) |   light_slate_gray = 0x778899,         // rgb(119,136,153) | ||||||
|   light_steel_blue        = 0xB0C4DE, // rgb(176,196,222) |   light_steel_blue = 0xB0C4DE,         // rgb(176,196,222) | ||||||
|   light_yellow            = 0xFFFFE0, // rgb(255,255,224) |   light_yellow = 0xFFFFE0,             // rgb(255,255,224) | ||||||
|   lime                    = 0x00FF00, // rgb(0,255,0) |   lime = 0x00FF00,                     // rgb(0,255,0) | ||||||
|   lime_green              = 0x32CD32, // rgb(50,205,50) |   lime_green = 0x32CD32,               // rgb(50,205,50) | ||||||
|   linen                   = 0xFAF0E6, // rgb(250,240,230) |   linen = 0xFAF0E6,                    // rgb(250,240,230) | ||||||
|   magenta                 = 0xFF00FF, // rgb(255,0,255) |   magenta = 0xFF00FF,                  // rgb(255,0,255) | ||||||
|   maroon                  = 0x800000, // rgb(128,0,0) |   maroon = 0x800000,                   // rgb(128,0,0) | ||||||
|   medium_aquamarine       = 0x66CDAA, // rgb(102,205,170) |   medium_aquamarine = 0x66CDAA,        // rgb(102,205,170) | ||||||
|   medium_blue             = 0x0000CD, // rgb(0,0,205) |   medium_blue = 0x0000CD,              // rgb(0,0,205) | ||||||
|   medium_orchid           = 0xBA55D3, // rgb(186,85,211) |   medium_orchid = 0xBA55D3,            // rgb(186,85,211) | ||||||
|   medium_purple           = 0x9370DB, // rgb(147,112,219) |   medium_purple = 0x9370DB,            // rgb(147,112,219) | ||||||
|   medium_sea_green        = 0x3CB371, // rgb(60,179,113) |   medium_sea_green = 0x3CB371,         // rgb(60,179,113) | ||||||
|   medium_slate_blue       = 0x7B68EE, // rgb(123,104,238) |   medium_slate_blue = 0x7B68EE,        // rgb(123,104,238) | ||||||
|   medium_spring_green     = 0x00FA9A, // rgb(0,250,154) |   medium_spring_green = 0x00FA9A,      // rgb(0,250,154) | ||||||
|   medium_turquoise        = 0x48D1CC, // rgb(72,209,204) |   medium_turquoise = 0x48D1CC,         // rgb(72,209,204) | ||||||
|   medium_violet_red       = 0xC71585, // rgb(199,21,133) |   medium_violet_red = 0xC71585,        // rgb(199,21,133) | ||||||
|   midnight_blue           = 0x191970, // rgb(25,25,112) |   midnight_blue = 0x191970,            // rgb(25,25,112) | ||||||
|   mint_cream              = 0xF5FFFA, // rgb(245,255,250) |   mint_cream = 0xF5FFFA,               // rgb(245,255,250) | ||||||
|   misty_rose              = 0xFFE4E1, // rgb(255,228,225) |   misty_rose = 0xFFE4E1,               // rgb(255,228,225) | ||||||
|   moccasin                = 0xFFE4B5, // rgb(255,228,181) |   moccasin = 0xFFE4B5,                 // rgb(255,228,181) | ||||||
|   navajo_white            = 0xFFDEAD, // rgb(255,222,173) |   navajo_white = 0xFFDEAD,             // rgb(255,222,173) | ||||||
|   navy                    = 0x000080, // rgb(0,0,128) |   navy = 0x000080,                     // rgb(0,0,128) | ||||||
|   old_lace                = 0xFDF5E6, // rgb(253,245,230) |   old_lace = 0xFDF5E6,                 // rgb(253,245,230) | ||||||
|   olive                   = 0x808000, // rgb(128,128,0) |   olive = 0x808000,                    // rgb(128,128,0) | ||||||
|   olive_drab              = 0x6B8E23, // rgb(107,142,35) |   olive_drab = 0x6B8E23,               // rgb(107,142,35) | ||||||
|   orange                  = 0xFFA500, // rgb(255,165,0) |   orange = 0xFFA500,                   // rgb(255,165,0) | ||||||
|   orange_red              = 0xFF4500, // rgb(255,69,0) |   orange_red = 0xFF4500,               // rgb(255,69,0) | ||||||
|   orchid                  = 0xDA70D6, // rgb(218,112,214) |   orchid = 0xDA70D6,                   // rgb(218,112,214) | ||||||
|   pale_golden_rod         = 0xEEE8AA, // rgb(238,232,170) |   pale_golden_rod = 0xEEE8AA,          // rgb(238,232,170) | ||||||
|   pale_green              = 0x98FB98, // rgb(152,251,152) |   pale_green = 0x98FB98,               // rgb(152,251,152) | ||||||
|   pale_turquoise          = 0xAFEEEE, // rgb(175,238,238) |   pale_turquoise = 0xAFEEEE,           // rgb(175,238,238) | ||||||
|   pale_violet_red         = 0xDB7093, // rgb(219,112,147) |   pale_violet_red = 0xDB7093,          // rgb(219,112,147) | ||||||
|   papaya_whip             = 0xFFEFD5, // rgb(255,239,213) |   papaya_whip = 0xFFEFD5,              // rgb(255,239,213) | ||||||
|   peach_puff              = 0xFFDAB9, // rgb(255,218,185) |   peach_puff = 0xFFDAB9,               // rgb(255,218,185) | ||||||
|   peru                    = 0xCD853F, // rgb(205,133,63) |   peru = 0xCD853F,                     // rgb(205,133,63) | ||||||
|   pink                    = 0xFFC0CB, // rgb(255,192,203) |   pink = 0xFFC0CB,                     // rgb(255,192,203) | ||||||
|   plum                    = 0xDDA0DD, // rgb(221,160,221) |   plum = 0xDDA0DD,                     // rgb(221,160,221) | ||||||
|   powder_blue             = 0xB0E0E6, // rgb(176,224,230) |   powder_blue = 0xB0E0E6,              // rgb(176,224,230) | ||||||
|   purple                  = 0x800080, // rgb(128,0,128) |   purple = 0x800080,                   // rgb(128,0,128) | ||||||
|   rebecca_purple          = 0x663399, // rgb(102,51,153) |   rebecca_purple = 0x663399,           // rgb(102,51,153) | ||||||
|   red                     = 0xFF0000, // rgb(255,0,0) |   red = 0xFF0000,                      // rgb(255,0,0) | ||||||
|   rosy_brown              = 0xBC8F8F, // rgb(188,143,143) |   rosy_brown = 0xBC8F8F,               // rgb(188,143,143) | ||||||
|   royal_blue              = 0x4169E1, // rgb(65,105,225) |   royal_blue = 0x4169E1,               // rgb(65,105,225) | ||||||
|   saddle_brown            = 0x8B4513, // rgb(139,69,19) |   saddle_brown = 0x8B4513,             // rgb(139,69,19) | ||||||
|   salmon                  = 0xFA8072, // rgb(250,128,114) |   salmon = 0xFA8072,                   // rgb(250,128,114) | ||||||
|   sandy_brown             = 0xF4A460, // rgb(244,164,96) |   sandy_brown = 0xF4A460,              // rgb(244,164,96) | ||||||
|   sea_green               = 0x2E8B57, // rgb(46,139,87) |   sea_green = 0x2E8B57,                // rgb(46,139,87) | ||||||
|   sea_shell               = 0xFFF5EE, // rgb(255,245,238) |   sea_shell = 0xFFF5EE,                // rgb(255,245,238) | ||||||
|   sienna                  = 0xA0522D, // rgb(160,82,45) |   sienna = 0xA0522D,                   // rgb(160,82,45) | ||||||
|   silver                  = 0xC0C0C0, // rgb(192,192,192) |   silver = 0xC0C0C0,                   // rgb(192,192,192) | ||||||
|   sky_blue                = 0x87CEEB, // rgb(135,206,235) |   sky_blue = 0x87CEEB,                 // rgb(135,206,235) | ||||||
|   slate_blue              = 0x6A5ACD, // rgb(106,90,205) |   slate_blue = 0x6A5ACD,               // rgb(106,90,205) | ||||||
|   slate_gray              = 0x708090, // rgb(112,128,144) |   slate_gray = 0x708090,               // rgb(112,128,144) | ||||||
|   snow                    = 0xFFFAFA, // rgb(255,250,250) |   snow = 0xFFFAFA,                     // rgb(255,250,250) | ||||||
|   spring_green            = 0x00FF7F, // rgb(0,255,127) |   spring_green = 0x00FF7F,             // rgb(0,255,127) | ||||||
|   steel_blue              = 0x4682B4, // rgb(70,130,180) |   steel_blue = 0x4682B4,               // rgb(70,130,180) | ||||||
|   tan                     = 0xD2B48C, // rgb(210,180,140) |   tan = 0xD2B48C,                      // rgb(210,180,140) | ||||||
|   teal                    = 0x008080, // rgb(0,128,128) |   teal = 0x008080,                     // rgb(0,128,128) | ||||||
|   thistle                 = 0xD8BFD8, // rgb(216,191,216) |   thistle = 0xD8BFD8,                  // rgb(216,191,216) | ||||||
|   tomato                  = 0xFF6347, // rgb(255,99,71) |   tomato = 0xFF6347,                   // rgb(255,99,71) | ||||||
|   turquoise               = 0x40E0D0, // rgb(64,224,208) |   turquoise = 0x40E0D0,                // rgb(64,224,208) | ||||||
|   violet                  = 0xEE82EE, // rgb(238,130,238) |   violet = 0xEE82EE,                   // rgb(238,130,238) | ||||||
|   wheat                   = 0xF5DEB3, // rgb(245,222,179) |   wheat = 0xF5DEB3,                    // rgb(245,222,179) | ||||||
|   white                   = 0xFFFFFF, // rgb(255,255,255) |   white = 0xFFFFFF,                    // rgb(255,255,255) | ||||||
|   white_smoke             = 0xF5F5F5, // rgb(245,245,245) |   white_smoke = 0xF5F5F5,              // rgb(245,245,245) | ||||||
|   yellow                  = 0xFFFF00, // rgb(255,255,0) |   yellow = 0xFFFF00,                   // rgb(255,255,0) | ||||||
|   yellow_green            = 0x9ACD32  // rgb(154,205,50) |   yellow_green = 0x9ACD32              // rgb(154,205,50) | ||||||
| };  // enum class color | };                                     // enum class color | ||||||
|  |  | ||||||
| enum class terminal_color : uint8_t { | enum class terminal_color : uint8_t { | ||||||
|   black = 30, |   black = 30, | ||||||
| @@ -208,27 +173,26 @@ enum class terminal_color : uint8_t { | |||||||
|   bright_magenta, |   bright_magenta, | ||||||
|   bright_cyan, |   bright_cyan, | ||||||
|   bright_white |   bright_white | ||||||
| };  // enum class terminal_color | }; | ||||||
|  |  | ||||||
| enum class emphasis : uint8_t { | enum class emphasis : uint8_t { | ||||||
|   bold = 1, |   bold = 1, | ||||||
|   italic = 1 << 1, |   italic = 1 << 1, | ||||||
|   underline = 1 << 2, |   underline = 1 << 2, | ||||||
|   strikethrough = 1 << 3 |   strikethrough = 1 << 3 | ||||||
| };  // enum class emphasis | }; | ||||||
|  |  | ||||||
| // rgb is a struct for red, green and blue colors. | // rgb is a struct for red, green and blue colors. | ||||||
| // We use rgb as name because some editors will show it as color direct in the | // Using the name "rgb" makes some editors show the color in a tooltip. | ||||||
| // editor. |  | ||||||
| struct rgb { | struct rgb { | ||||||
|   FMT_CONSTEXPR_DECL rgb() : r(0), g(0), b(0) {} |   FMT_CONSTEXPR rgb() : r(0), g(0), b(0) {} | ||||||
|   FMT_CONSTEXPR_DECL rgb(uint8_t r_, uint8_t g_, uint8_t b_) |   FMT_CONSTEXPR rgb(uint8_t r_, uint8_t g_, uint8_t b_) : r(r_), g(g_), b(b_) {} | ||||||
|     : r(r_), g(g_), b(b_) {} |   FMT_CONSTEXPR rgb(uint32_t hex) | ||||||
|   FMT_CONSTEXPR_DECL rgb(uint32_t hex) |       : r((hex >> 16) & 0xFF), g((hex >> 8) & 0xFF), b(hex & 0xFF) {} | ||||||
|     : r((hex >> 16) & 0xFF), g((hex >> 8) & 0xFF), b((hex) & 0xFF) {} |   FMT_CONSTEXPR rgb(color hex) | ||||||
|   FMT_CONSTEXPR_DECL rgb(color hex) |       : r((uint32_t(hex) >> 16) & 0xFF), | ||||||
|     : r((uint32_t(hex) >> 16) & 0xFF), g((uint32_t(hex) >> 8) & 0xFF), |         g((uint32_t(hex) >> 8) & 0xFF), | ||||||
|       b(uint32_t(hex) & 0xFF) {} |         b(uint32_t(hex) & 0xFF) {} | ||||||
|   uint8_t r; |   uint8_t r; | ||||||
|   uint8_t g; |   uint8_t g; | ||||||
|   uint8_t b; |   uint8_t b; | ||||||
| @@ -238,19 +202,17 @@ namespace internal { | |||||||
|  |  | ||||||
| // color is a struct of either a rgb color or a terminal color. | // color is a struct of either a rgb color or a terminal color. | ||||||
| struct color_type { | struct color_type { | ||||||
|   FMT_CONSTEXPR color_type() FMT_NOEXCEPT |   FMT_CONSTEXPR color_type() FMT_NOEXCEPT : is_rgb(), value{} {} | ||||||
|     : is_rgb(), value{} {} |   FMT_CONSTEXPR color_type(color rgb_color) FMT_NOEXCEPT : is_rgb(true), | ||||||
|   FMT_CONSTEXPR color_type(color rgb_color) FMT_NOEXCEPT |                                                            value{} { | ||||||
|     : is_rgb(true), value{} { |  | ||||||
|     value.rgb_color = static_cast<uint32_t>(rgb_color); |     value.rgb_color = static_cast<uint32_t>(rgb_color); | ||||||
|   } |   } | ||||||
|   FMT_CONSTEXPR color_type(rgb rgb_color) FMT_NOEXCEPT |   FMT_CONSTEXPR color_type(rgb rgb_color) FMT_NOEXCEPT : is_rgb(true), value{} { | ||||||
|     : is_rgb(true), value{} { |     value.rgb_color = (static_cast<uint32_t>(rgb_color.r) << 16) | | ||||||
|     value.rgb_color = (static_cast<uint32_t>(rgb_color.r) << 16) |                       (static_cast<uint32_t>(rgb_color.g) << 8) | rgb_color.b; | ||||||
|        | (static_cast<uint32_t>(rgb_color.g) << 8) | rgb_color.b; |  | ||||||
|   } |   } | ||||||
|   FMT_CONSTEXPR color_type(terminal_color term_color) FMT_NOEXCEPT |   FMT_CONSTEXPR color_type(terminal_color term_color) FMT_NOEXCEPT : is_rgb(), | ||||||
|     : is_rgb(), value{} { |                                                                      value{} { | ||||||
|     value.term_color = static_cast<uint8_t>(term_color); |     value.term_color = static_cast<uint8_t>(term_color); | ||||||
|   } |   } | ||||||
|   bool is_rgb; |   bool is_rgb; | ||||||
| @@ -259,21 +221,23 @@ struct color_type { | |||||||
|     uint32_t rgb_color; |     uint32_t rgb_color; | ||||||
|   } value; |   } value; | ||||||
| }; | }; | ||||||
| } // namespace internal | }  // namespace internal | ||||||
|  |  | ||||||
| // Experimental text formatting support. | // Experimental text formatting support. | ||||||
| class text_style { | class text_style { | ||||||
|  public: |  public: | ||||||
|   FMT_CONSTEXPR text_style(emphasis em = emphasis()) FMT_NOEXCEPT |   FMT_CONSTEXPR text_style(emphasis em = emphasis()) FMT_NOEXCEPT | ||||||
|       : set_foreground_color(), set_background_color(), ems(em) {} |       : set_foreground_color(), | ||||||
|  |         set_background_color(), | ||||||
|  |         ems(em) {} | ||||||
|  |  | ||||||
|   FMT_CONSTEXPR text_style &operator|=(const text_style &rhs) { |   FMT_CONSTEXPR text_style& operator|=(const text_style& rhs) { | ||||||
|     if (!set_foreground_color) { |     if (!set_foreground_color) { | ||||||
|       set_foreground_color = rhs.set_foreground_color; |       set_foreground_color = rhs.set_foreground_color; | ||||||
|       foreground_color = rhs.foreground_color; |       foreground_color = rhs.foreground_color; | ||||||
|     } else if (rhs.set_foreground_color) { |     } else if (rhs.set_foreground_color) { | ||||||
|       if (!foreground_color.is_rgb || !rhs.foreground_color.is_rgb) |       if (!foreground_color.is_rgb || !rhs.foreground_color.is_rgb) | ||||||
|         throw format_error("can't OR a terminal color"); |         FMT_THROW(format_error("can't OR a terminal color")); | ||||||
|       foreground_color.value.rgb_color |= rhs.foreground_color.value.rgb_color; |       foreground_color.value.rgb_color |= rhs.foreground_color.value.rgb_color; | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -282,7 +246,7 @@ class text_style { | |||||||
|       background_color = rhs.background_color; |       background_color = rhs.background_color; | ||||||
|     } else if (rhs.set_background_color) { |     } else if (rhs.set_background_color) { | ||||||
|       if (!background_color.is_rgb || !rhs.background_color.is_rgb) |       if (!background_color.is_rgb || !rhs.background_color.is_rgb) | ||||||
|         throw format_error("can't OR a terminal color"); |         FMT_THROW(format_error("can't OR a terminal color")); | ||||||
|       background_color.value.rgb_color |= rhs.background_color.value.rgb_color; |       background_color.value.rgb_color |= rhs.background_color.value.rgb_color; | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -291,18 +255,18 @@ class text_style { | |||||||
|     return *this; |     return *this; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   friend FMT_CONSTEXPR |   friend FMT_CONSTEXPR text_style operator|(text_style lhs, | ||||||
|   text_style operator|(text_style lhs, const text_style &rhs) { |                                             const text_style& rhs) { | ||||||
|     return lhs |= rhs; |     return lhs |= rhs; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   FMT_CONSTEXPR text_style &operator&=(const text_style &rhs) { |   FMT_CONSTEXPR text_style& operator&=(const text_style& rhs) { | ||||||
|     if (!set_foreground_color) { |     if (!set_foreground_color) { | ||||||
|       set_foreground_color = rhs.set_foreground_color; |       set_foreground_color = rhs.set_foreground_color; | ||||||
|       foreground_color = rhs.foreground_color; |       foreground_color = rhs.foreground_color; | ||||||
|     } else if (rhs.set_foreground_color) { |     } else if (rhs.set_foreground_color) { | ||||||
|       if (!foreground_color.is_rgb || !rhs.foreground_color.is_rgb) |       if (!foreground_color.is_rgb || !rhs.foreground_color.is_rgb) | ||||||
|         throw format_error("can't AND a terminal color"); |         FMT_THROW(format_error("can't AND a terminal color")); | ||||||
|       foreground_color.value.rgb_color &= rhs.foreground_color.value.rgb_color; |       foreground_color.value.rgb_color &= rhs.foreground_color.value.rgb_color; | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -311,7 +275,7 @@ class text_style { | |||||||
|       background_color = rhs.background_color; |       background_color = rhs.background_color; | ||||||
|     } else if (rhs.set_background_color) { |     } else if (rhs.set_background_color) { | ||||||
|       if (!background_color.is_rgb || !rhs.background_color.is_rgb) |       if (!background_color.is_rgb || !rhs.background_color.is_rgb) | ||||||
|         throw format_error("can't AND a terminal color"); |         FMT_THROW(format_error("can't AND a terminal color")); | ||||||
|       background_color.value.rgb_color &= rhs.background_color.value.rgb_color; |       background_color.value.rgb_color &= rhs.background_color.value.rgb_color; | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -320,8 +284,8 @@ class text_style { | |||||||
|     return *this; |     return *this; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   friend FMT_CONSTEXPR |   friend FMT_CONSTEXPR text_style operator&(text_style lhs, | ||||||
|   text_style operator&(text_style lhs, const text_style &rhs) { |                                             const text_style& rhs) { | ||||||
|     return lhs &= rhs; |     return lhs &= rhs; | ||||||
|   } |   } | ||||||
|  |  | ||||||
| @@ -347,20 +311,20 @@ class text_style { | |||||||
|     return ems; |     return ems; | ||||||
|   } |   } | ||||||
|  |  | ||||||
| private: |  private: | ||||||
|  FMT_CONSTEXPR text_style(bool is_foreground, |   FMT_CONSTEXPR text_style(bool is_foreground, | ||||||
|                           internal::color_type text_color) FMT_NOEXCEPT |                            internal::color_type text_color) FMT_NOEXCEPT | ||||||
|      : set_foreground_color(), |       : set_foreground_color(), | ||||||
|        set_background_color(), |         set_background_color(), | ||||||
|        ems() { |         ems() { | ||||||
|    if (is_foreground) { |     if (is_foreground) { | ||||||
|      foreground_color = text_color; |       foreground_color = text_color; | ||||||
|      set_foreground_color = true; |       set_foreground_color = true; | ||||||
|    } else { |     } else { | ||||||
|      background_color = text_color; |       background_color = text_color; | ||||||
|      set_background_color = true; |       set_background_color = true; | ||||||
|    } |     } | ||||||
|  } |   } | ||||||
|  |  | ||||||
|   friend FMT_CONSTEXPR_DECL text_style fg(internal::color_type foreground) |   friend FMT_CONSTEXPR_DECL text_style fg(internal::color_type foreground) | ||||||
|       FMT_NOEXCEPT; |       FMT_NOEXCEPT; | ||||||
| @@ -388,19 +352,17 @@ FMT_CONSTEXPR text_style operator|(emphasis lhs, emphasis rhs) FMT_NOEXCEPT { | |||||||
|  |  | ||||||
| namespace internal { | namespace internal { | ||||||
|  |  | ||||||
| template <typename Char> | template <typename Char> struct ansi_color_escape { | ||||||
| struct ansi_color_escape { |  | ||||||
|   FMT_CONSTEXPR ansi_color_escape(internal::color_type text_color, |   FMT_CONSTEXPR ansi_color_escape(internal::color_type text_color, | ||||||
|                                   const char * esc) FMT_NOEXCEPT { |                                   const char* esc) FMT_NOEXCEPT { | ||||||
|     // If we have a terminal color, we need to output another escape code |     // If we have a terminal color, we need to output another escape code | ||||||
|     // sequence. |     // sequence. | ||||||
|     if (!text_color.is_rgb) { |     if (!text_color.is_rgb) { | ||||||
|       bool is_background = esc == internal::data::BACKGROUND_COLOR; |       bool is_background = esc == internal::data::background_color; | ||||||
|       uint32_t value = text_color.value.term_color; |       uint32_t value = text_color.value.term_color; | ||||||
|       // Background ASCII codes are the same as the foreground ones but with |       // Background ASCII codes are the same as the foreground ones but with | ||||||
|       // 10 more. |       // 10 more. | ||||||
|       if (is_background) |       if (is_background) value += 10u; | ||||||
|         value += 10u; |  | ||||||
|  |  | ||||||
|       std::size_t index = 0; |       std::size_t index = 0; | ||||||
|       buffer[index++] = static_cast<Char>('\x1b'); |       buffer[index++] = static_cast<Char>('\x1b'); | ||||||
| @@ -422,7 +384,7 @@ struct ansi_color_escape { | |||||||
|       buffer[i] = static_cast<Char>(esc[i]); |       buffer[i] = static_cast<Char>(esc[i]); | ||||||
|     } |     } | ||||||
|     rgb color(text_color.value.rgb_color); |     rgb color(text_color.value.rgb_color); | ||||||
|     to_esc(color.r, buffer +  7, ';'); |     to_esc(color.r, buffer + 7, ';'); | ||||||
|     to_esc(color.g, buffer + 11, ';'); |     to_esc(color.g, buffer + 11, ';'); | ||||||
|     to_esc(color.b, buffer + 15, 'm'); |     to_esc(color.b, buffer + 15, 'm'); | ||||||
|     buffer[19] = static_cast<Char>(0); |     buffer[19] = static_cast<Char>(0); | ||||||
| @@ -430,19 +392,15 @@ struct ansi_color_escape { | |||||||
|   FMT_CONSTEXPR ansi_color_escape(emphasis em) FMT_NOEXCEPT { |   FMT_CONSTEXPR ansi_color_escape(emphasis em) FMT_NOEXCEPT { | ||||||
|     uint8_t em_codes[4] = {}; |     uint8_t em_codes[4] = {}; | ||||||
|     uint8_t em_bits = static_cast<uint8_t>(em); |     uint8_t em_bits = static_cast<uint8_t>(em); | ||||||
|     if (em_bits & static_cast<uint8_t>(emphasis::bold)) |     if (em_bits & static_cast<uint8_t>(emphasis::bold)) em_codes[0] = 1; | ||||||
|       em_codes[0] = 1; |     if (em_bits & static_cast<uint8_t>(emphasis::italic)) em_codes[1] = 3; | ||||||
|     if (em_bits & static_cast<uint8_t>(emphasis::italic)) |     if (em_bits & static_cast<uint8_t>(emphasis::underline)) em_codes[2] = 4; | ||||||
|       em_codes[1] = 3; |  | ||||||
|     if (em_bits & static_cast<uint8_t>(emphasis::underline)) |  | ||||||
|       em_codes[2] = 4; |  | ||||||
|     if (em_bits & static_cast<uint8_t>(emphasis::strikethrough)) |     if (em_bits & static_cast<uint8_t>(emphasis::strikethrough)) | ||||||
|       em_codes[3] = 9; |       em_codes[3] = 9; | ||||||
|  |  | ||||||
|     std::size_t index = 0; |     std::size_t index = 0; | ||||||
|     for (int i = 0; i < 4; ++i) { |     for (int i = 0; i < 4; ++i) { | ||||||
|       if (!em_codes[i]) |       if (!em_codes[i]) continue; | ||||||
|         continue; |  | ||||||
|       buffer[index++] = static_cast<Char>('\x1b'); |       buffer[index++] = static_cast<Char>('\x1b'); | ||||||
|       buffer[index++] = static_cast<Char>('['); |       buffer[index++] = static_cast<Char>('['); | ||||||
|       buffer[index++] = static_cast<Char>('0' + em_codes[i]); |       buffer[index++] = static_cast<Char>('0' + em_codes[i]); | ||||||
| @@ -450,12 +408,17 @@ struct ansi_color_escape { | |||||||
|     } |     } | ||||||
|     buffer[index++] = static_cast<Char>(0); |     buffer[index++] = static_cast<Char>(0); | ||||||
|   } |   } | ||||||
|   FMT_CONSTEXPR operator const Char *() const FMT_NOEXCEPT { return buffer; } |   FMT_CONSTEXPR operator const Char*() const FMT_NOEXCEPT { return buffer; } | ||||||
|  |  | ||||||
| private: |   FMT_CONSTEXPR const Char* begin() const FMT_NOEXCEPT { return buffer; } | ||||||
|  |   FMT_CONSTEXPR const Char* end() const FMT_NOEXCEPT { | ||||||
|  |     return buffer + std::strlen(buffer); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |  private: | ||||||
|   Char buffer[7u + 3u * 4u + 1u]; |   Char buffer[7u + 3u * 4u + 1u]; | ||||||
|  |  | ||||||
|   static FMT_CONSTEXPR void to_esc(uint8_t c, Char *out, |   static FMT_CONSTEXPR void to_esc(uint8_t c, Char* out, | ||||||
|                                    char delimiter) FMT_NOEXCEPT { |                                    char delimiter) FMT_NOEXCEPT { | ||||||
|     out[0] = static_cast<Char>('0' + c / 100); |     out[0] = static_cast<Char>('0' + c / 100); | ||||||
|     out[1] = static_cast<Char>('0' + c / 10 % 10); |     out[1] = static_cast<Char>('0' + c / 10 % 10); | ||||||
| @@ -465,67 +428,90 @@ private: | |||||||
| }; | }; | ||||||
|  |  | ||||||
| template <typename Char> | template <typename Char> | ||||||
| FMT_CONSTEXPR ansi_color_escape<Char> | FMT_CONSTEXPR ansi_color_escape<Char> make_foreground_color( | ||||||
| make_foreground_color(internal::color_type foreground) FMT_NOEXCEPT { |     internal::color_type foreground) FMT_NOEXCEPT { | ||||||
|   return ansi_color_escape<Char>(foreground, internal::data::FOREGROUND_COLOR); |   return ansi_color_escape<Char>(foreground, internal::data::foreground_color); | ||||||
| } | } | ||||||
|  |  | ||||||
| template <typename Char> | template <typename Char> | ||||||
| FMT_CONSTEXPR ansi_color_escape<Char> | FMT_CONSTEXPR ansi_color_escape<Char> make_background_color( | ||||||
| make_background_color(internal::color_type background) FMT_NOEXCEPT { |     internal::color_type background) FMT_NOEXCEPT { | ||||||
|   return ansi_color_escape<Char>(background, internal::data::BACKGROUND_COLOR); |   return ansi_color_escape<Char>(background, internal::data::background_color); | ||||||
| } | } | ||||||
|  |  | ||||||
| template <typename Char> | template <typename Char> | ||||||
| FMT_CONSTEXPR ansi_color_escape<Char> | FMT_CONSTEXPR ansi_color_escape<Char> make_emphasis(emphasis em) FMT_NOEXCEPT { | ||||||
| make_emphasis(emphasis em) FMT_NOEXCEPT { |  | ||||||
|   return ansi_color_escape<Char>(em); |   return ansi_color_escape<Char>(em); | ||||||
| } | } | ||||||
|  |  | ||||||
| template <typename Char> | template <typename Char> | ||||||
| inline void fputs(const Char *chars, FILE *stream) FMT_NOEXCEPT { | inline void fputs(const Char* chars, FILE* stream) FMT_NOEXCEPT { | ||||||
|   std::fputs(chars, stream); |   std::fputs(chars, stream); | ||||||
| } | } | ||||||
|  |  | ||||||
| template <> | template <> | ||||||
| inline void fputs<wchar_t>(const wchar_t *chars, FILE *stream) FMT_NOEXCEPT { | inline void fputs<wchar_t>(const wchar_t* chars, FILE* stream) FMT_NOEXCEPT { | ||||||
|   std::fputws(chars, stream); |   std::fputws(chars, stream); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | template <typename Char> inline void reset_color(FILE* stream) FMT_NOEXCEPT { | ||||||
|  |   fputs(internal::data::reset_color, stream); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | template <> inline void reset_color<wchar_t>(FILE* stream) FMT_NOEXCEPT { | ||||||
|  |   fputs(internal::data::wreset_color, stream); | ||||||
|  | } | ||||||
|  |  | ||||||
| template <typename Char> | template <typename Char> | ||||||
| inline void reset_color(FILE *stream) FMT_NOEXCEPT { | inline void reset_color(basic_memory_buffer<Char>& buffer) FMT_NOEXCEPT { | ||||||
|   fputs(internal::data::RESET_COLOR, stream); |   const char* begin = data::reset_color; | ||||||
|  |   const char* end = begin + sizeof(data::reset_color) - 1; | ||||||
|  |   buffer.append(begin, end); | ||||||
| } | } | ||||||
|  |  | ||||||
| template <> | template <typename Char> | ||||||
| inline void reset_color<wchar_t>(FILE *stream) FMT_NOEXCEPT { | std::basic_string<Char> vformat(const text_style& ts, | ||||||
|   fputs(internal::data::WRESET_COLOR, stream); |                                 basic_string_view<Char> format_str, | ||||||
| } |                                 basic_format_args<buffer_context<Char> > args) { | ||||||
|  |   basic_memory_buffer<Char> buffer; | ||||||
| // The following specialiazation disables using std::FILE as a character type, |  | ||||||
| // which is needed because or else |  | ||||||
| //   fmt::print(stderr, fmt::emphasis::bold, ""); |  | ||||||
| // would take stderr (a std::FILE *) as the format string. |  | ||||||
| template <> |  | ||||||
| struct is_string<std::FILE *> : std::false_type {}; |  | ||||||
| template <> |  | ||||||
| struct is_string<const std::FILE *> : std::false_type {}; |  | ||||||
| } // namespace internal |  | ||||||
|  |  | ||||||
| template < |  | ||||||
|   typename S, typename Char = typename internal::char_t<S>::type> |  | ||||||
| void vprint(std::FILE *f, const text_style &ts, const S &format, |  | ||||||
|             basic_format_args<typename buffer_context<Char>::type> args) { |  | ||||||
|   bool has_style = false; |   bool has_style = false; | ||||||
|   if (ts.has_emphasis()) { |   if (ts.has_emphasis()) { | ||||||
|     has_style = true; |     has_style = true; | ||||||
|     internal::fputs<Char>( |     ansi_color_escape<Char> escape = make_emphasis<Char>(ts.get_emphasis()); | ||||||
|           internal::make_emphasis<Char>(ts.get_emphasis()), f); |     buffer.append(escape.begin(), escape.end()); | ||||||
|  |   } | ||||||
|  |   if (ts.has_foreground()) { | ||||||
|  |     has_style = true; | ||||||
|  |     ansi_color_escape<Char> escape = | ||||||
|  |         make_foreground_color<Char>(ts.get_foreground()); | ||||||
|  |     buffer.append(escape.begin(), escape.end()); | ||||||
|  |   } | ||||||
|  |   if (ts.has_background()) { | ||||||
|  |     has_style = true; | ||||||
|  |     ansi_color_escape<Char> escape = | ||||||
|  |         make_background_color<Char>(ts.get_background()); | ||||||
|  |     buffer.append(escape.begin(), escape.end()); | ||||||
|  |   } | ||||||
|  |   internal::vformat_to(buffer, format_str, args); | ||||||
|  |   if (has_style) { | ||||||
|  |     reset_color<Char>(buffer); | ||||||
|  |   } | ||||||
|  |   return fmt::to_string(buffer); | ||||||
|  | } | ||||||
|  | }  // namespace internal | ||||||
|  |  | ||||||
|  | template <typename S, typename Char = char_t<S> > | ||||||
|  | void vprint(std::FILE* f, const text_style& ts, const S& format, | ||||||
|  |             basic_format_args<buffer_context<Char> > args) { | ||||||
|  |   bool has_style = false; | ||||||
|  |   if (ts.has_emphasis()) { | ||||||
|  |     has_style = true; | ||||||
|  |     internal::fputs<Char>(internal::make_emphasis<Char>(ts.get_emphasis()), f); | ||||||
|   } |   } | ||||||
|   if (ts.has_foreground()) { |   if (ts.has_foreground()) { | ||||||
|     has_style = true; |     has_style = true; | ||||||
|     internal::fputs<Char>( |     internal::fputs<Char>( | ||||||
|           internal::make_foreground_color<Char>(ts.get_foreground()), f); |         internal::make_foreground_color<Char>(ts.get_foreground()), f); | ||||||
|   } |   } | ||||||
|   if (ts.has_background()) { |   if (ts.has_background()) { | ||||||
|     has_style = true; |     has_style = true; | ||||||
| @@ -545,15 +531,14 @@ void vprint(std::FILE *f, const text_style &ts, const S &format, | |||||||
|     fmt::print(fmt::emphasis::bold | fg(fmt::color::red), |     fmt::print(fmt::emphasis::bold | fg(fmt::color::red), | ||||||
|                "Elapsed time: {0:.2f} seconds", 1.23); |                "Elapsed time: {0:.2f} seconds", 1.23); | ||||||
|  */ |  */ | ||||||
| template <typename String, typename... Args> | template <typename S, typename... Args, | ||||||
| typename std::enable_if<internal::is_string<String>::value>::type print( |           FMT_ENABLE_IF(internal::is_string<S>::value)> | ||||||
|     std::FILE *f, const text_style &ts, const String &format_str, | void print(std::FILE* f, const text_style& ts, const S& format_str, | ||||||
|     const Args &... args) { |            const Args&... args) { | ||||||
|   internal::check_format_string<Args...>(format_str); |   internal::check_format_string<Args...>(format_str); | ||||||
|   typedef typename internal::char_t<String>::type char_t; |   using context = buffer_context<char_t<S> >; | ||||||
|   typedef typename buffer_context<char_t>::type context_t; |   format_arg_store<context, Args...> as{args...}; | ||||||
|   format_arg_store<context_t, Args...> as{args...}; |   vprint(f, ts, format_str, basic_format_args<context>(as)); | ||||||
|   vprint(f, ts, format_str, basic_format_args<context_t>(as)); |  | ||||||
| } | } | ||||||
|  |  | ||||||
| /** | /** | ||||||
| @@ -563,14 +548,37 @@ typename std::enable_if<internal::is_string<String>::value>::type print( | |||||||
|     fmt::print(fmt::emphasis::bold | fg(fmt::color::red), |     fmt::print(fmt::emphasis::bold | fg(fmt::color::red), | ||||||
|                "Elapsed time: {0:.2f} seconds", 1.23); |                "Elapsed time: {0:.2f} seconds", 1.23); | ||||||
|  */ |  */ | ||||||
| template <typename String, typename... Args> | template <typename S, typename... Args, | ||||||
| typename std::enable_if<internal::is_string<String>::value>::type print( |           FMT_ENABLE_IF(internal::is_string<S>::value)> | ||||||
|     const text_style &ts, const String &format_str, | void print(const text_style& ts, const S& format_str, const Args&... args) { | ||||||
|     const Args &... args) { |  | ||||||
|   return print(stdout, ts, format_str, args...); |   return print(stdout, ts, format_str, args...); | ||||||
| } | } | ||||||
|  |  | ||||||
| #endif | template <typename S, typename Char = char_t<S> > | ||||||
|  | inline std::basic_string<Char> vformat( | ||||||
|  |     const text_style& ts, const S& format_str, | ||||||
|  |     basic_format_args<buffer_context<Char> > args) { | ||||||
|  |   return internal::vformat(ts, to_string_view(format_str), args); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |   \rst | ||||||
|  |   Formats arguments and returns the result as a string using ANSI | ||||||
|  |   escape sequences to specify text formatting. | ||||||
|  |  | ||||||
|  |   **Example**:: | ||||||
|  |  | ||||||
|  |     #include <fmt/color.h> | ||||||
|  |     std::string message = fmt::format(fmt::emphasis::bold | fg(fmt::color::red), | ||||||
|  |                                       "The answer is {}", 42); | ||||||
|  |   \endrst | ||||||
|  | */ | ||||||
|  | template <typename S, typename... Args, typename Char = char_t<S> > | ||||||
|  | inline std::basic_string<Char> format(const text_style& ts, const S& format_str, | ||||||
|  |                                       const Args&... args) { | ||||||
|  |   return internal::vformat(ts, to_string_view(format_str), | ||||||
|  |                            {internal::make_args_checked(format_str, args...)}); | ||||||
|  | } | ||||||
|  |  | ||||||
| FMT_END_NAMESPACE | FMT_END_NAMESPACE | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										466
									
								
								third_party/spdlog/include/spdlog/fmt/bundled/compile.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										466
									
								
								third_party/spdlog/include/spdlog/fmt/bundled/compile.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,466 @@ | |||||||
|  | // Formatting library for C++ - experimental format string compilation | ||||||
|  | // | ||||||
|  | // Copyright (c) 2012 - present, Victor Zverovich and fmt contributors | ||||||
|  | // All rights reserved. | ||||||
|  | // | ||||||
|  | // For the license information refer to format.h. | ||||||
|  |  | ||||||
|  | #ifndef FMT_COMPILE_H_ | ||||||
|  | #define FMT_COMPILE_H_ | ||||||
|  |  | ||||||
|  | #include <vector> | ||||||
|  | #include "format.h" | ||||||
|  |  | ||||||
|  | FMT_BEGIN_NAMESPACE | ||||||
|  | namespace internal { | ||||||
|  |  | ||||||
|  | template <typename Char> struct format_part { | ||||||
|  |  public: | ||||||
|  |   struct named_argument_id { | ||||||
|  |     FMT_CONSTEXPR named_argument_id(internal::string_view_metadata id) | ||||||
|  |         : id(id) {} | ||||||
|  |     internal::string_view_metadata id; | ||||||
|  |   }; | ||||||
|  |  | ||||||
|  |   struct argument_id { | ||||||
|  |     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 { | ||||||
|  |       FMT_CONSTEXPR value() : index(0u) {} | ||||||
|  |       FMT_CONSTEXPR value(unsigned id) : index(id) {} | ||||||
|  |       FMT_CONSTEXPR value(internal::string_view_metadata id) | ||||||
|  |           : named_index(id) {} | ||||||
|  |  | ||||||
|  |       unsigned index; | ||||||
|  |       internal::string_view_metadata named_index; | ||||||
|  |     } val; | ||||||
|  |   }; | ||||||
|  |  | ||||||
|  |   struct specification { | ||||||
|  |     FMT_CONSTEXPR specification() : arg_id(0u) {} | ||||||
|  |     FMT_CONSTEXPR specification(unsigned id) : arg_id(id) {} | ||||||
|  |  | ||||||
|  |     FMT_CONSTEXPR specification(internal::string_view_metadata id) | ||||||
|  |         : arg_id(id) {} | ||||||
|  |  | ||||||
|  |     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))); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   FMT_CONSTEXPR void on_arg_id() { | ||||||
|  |     parts_.push_back(part(parse_context_.next_arg_id())); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   FMT_CONSTEXPR void on_arg_id(unsigned id) { | ||||||
|  |     parse_context_.check_arg_id(id); | ||||||
|  |     parts_.push_back(part(id)); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   FMT_CONSTEXPR void on_arg_id(basic_string_view<Char> id) { | ||||||
|  |     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 { | ||||||
|  |   unsigned num_parts = 0; | ||||||
|  |  | ||||||
|  |   FMT_CONSTEXPR void on_text(const Char* begin, const Char* end) { | ||||||
|  |     if (begin != end) ++num_parts; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   FMT_CONSTEXPR void on_arg_id() { ++num_parts; } | ||||||
|  |   FMT_CONSTEXPR void on_arg_id(unsigned) { ++num_parts; } | ||||||
|  |   FMT_CONSTEXPR void on_arg_id(basic_string_view<Char>) { ++num_parts; } | ||||||
|  |  | ||||||
|  |   FMT_CONSTEXPR void on_replacement_field(const Char*) {} | ||||||
|  |  | ||||||
|  |   FMT_CONSTEXPR const Char* on_format_specs(const Char* begin, | ||||||
|  |                                             const Char* end) { | ||||||
|  |     // Find the matching brace. | ||||||
|  |     unsigned braces_counter = 0; | ||||||
|  |     for (; begin != end; ++begin) { | ||||||
|  |       if (*begin == '{') { | ||||||
|  |         ++braces_counter; | ||||||
|  |       } else if (*begin == '}') { | ||||||
|  |         if (braces_counter == 0u) break; | ||||||
|  |         --braces_counter; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |     return begin; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   FMT_CONSTEXPR void on_error(const char*) {} | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | template <typename Format> class compiletime_prepared_parts_type_provider { | ||||||
|  |  private: | ||||||
|  |   using char_type = char_t<Format>; | ||||||
|  |  | ||||||
|  |   static FMT_CONSTEXPR unsigned count_parts() { | ||||||
|  |     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; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  | // Workaround for old compilers. Compiletime parts preparation will not be | ||||||
|  | // performed with them anyway. | ||||||
|  | #if FMT_USE_CONSTEXPR | ||||||
|  |   static FMT_CONSTEXPR_DECL const unsigned number_of_format_parts = | ||||||
|  |       compiletime_prepared_parts_type_provider::count_parts(); | ||||||
|  | #else | ||||||
|  |   static const unsigned number_of_format_parts = 0u; | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  |  public: | ||||||
|  |   template <unsigned N> struct format_parts_array { | ||||||
|  |     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: | ||||||
|  |     value_type arr[N]; | ||||||
|  |   }; | ||||||
|  |  | ||||||
|  |   struct empty { | ||||||
|  |     // Parts preparator will search for it | ||||||
|  |     using value_type = format_part<char_type>; | ||||||
|  |   }; | ||||||
|  |  | ||||||
|  |   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: | ||||||
|  |   FMT_CONSTEXPR explicit compiletime_prepared_parts_collector(Parts& parts) | ||||||
|  |       : parts_{parts}, counter_{0u} {} | ||||||
|  |  | ||||||
|  |   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> | ||||||
|  | FMT_CONSTEXPR PartsContainer prepare_parts(basic_string_view<Char> format) { | ||||||
|  |   PartsContainer parts; | ||||||
|  |   internal::parse_format_string</*IS_CONSTEXPR=*/false>( | ||||||
|  |       format, format_preparation_handler<Char, PartsContainer>(format, parts)); | ||||||
|  |   return parts; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | template <typename PartsContainer, typename Char> | ||||||
|  | FMT_CONSTEXPR PartsContainer | ||||||
|  | prepare_compiletime_parts(basic_string_view<Char> format) { | ||||||
|  |   using collector = compiletime_prepared_parts_collector<PartsContainer>; | ||||||
|  |  | ||||||
|  |   PartsContainer parts; | ||||||
|  |   collector c(parts); | ||||||
|  |   internal::parse_format_string</*IS_CONSTEXPR=*/true>( | ||||||
|  |       format, format_preparation_handler<Char, collector>(format, c)); | ||||||
|  |   return parts; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | template <typename PartsContainer> class runtime_parts_provider { | ||||||
|  |  public: | ||||||
|  |   runtime_parts_provider() = delete; | ||||||
|  |   template <typename Char> | ||||||
|  |   runtime_parts_provider(basic_string_view<Char> format) | ||||||
|  |       : parts_(prepare_parts<PartsContainer>(format)) {} | ||||||
|  |  | ||||||
|  |   const PartsContainer& parts() const { return parts_; } | ||||||
|  |  | ||||||
|  |  private: | ||||||
|  |   PartsContainer parts_; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | template <typename Format, typename PartsContainer> | ||||||
|  | struct compiletime_parts_provider { | ||||||
|  |   compiletime_parts_provider() = delete; | ||||||
|  |   template <typename Char> | ||||||
|  |   FMT_CONSTEXPR compiletime_parts_provider(basic_string_view<Char>) {} | ||||||
|  |  | ||||||
|  |   const PartsContainer& parts() const { | ||||||
|  |     static FMT_CONSTEXPR_DECL const PartsContainer prepared_parts = | ||||||
|  |         prepare_compiletime_parts<PartsContainer>( | ||||||
|  |             internal::to_string_view(Format{})); | ||||||
|  |  | ||||||
|  |     return prepared_parts; | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  | }  // namespace internal | ||||||
|  |  | ||||||
|  | #if FMT_USE_CONSTEXPR | ||||||
|  | template <typename... Args, typename S, | ||||||
|  |           FMT_ENABLE_IF(is_compile_string<S>::value)> | ||||||
|  | FMT_CONSTEXPR auto compile(S format_str) -> internal::prepared_format< | ||||||
|  |     S, | ||||||
|  |     internal::compiletime_parts_provider< | ||||||
|  |         S, | ||||||
|  |         typename internal::compiletime_prepared_parts_type_provider<S>::type>, | ||||||
|  |     Args...> { | ||||||
|  |   return format_str; | ||||||
|  | } | ||||||
|  | #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, | ||||||
|  |           typename Char = typename CompiledFormat::char_type> | ||||||
|  | std::basic_string<Char> format(const CompiledFormat& cf, const Args&... args) { | ||||||
|  |   basic_memory_buffer<Char> buffer; | ||||||
|  |   using range = internal::buffer_range<Char>; | ||||||
|  |   using context = buffer_context<Char>; | ||||||
|  |   cf.template vformat_to<range, context>(range(buffer), | ||||||
|  |                                          {make_format_args<context>(args...)}); | ||||||
|  |   return to_string(buffer); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | template <typename OutputIt, typename CompiledFormat, typename... Args> | ||||||
|  | OutputIt format_to(OutputIt out, const CompiledFormat& cf, | ||||||
|  |                    const Args&... args) { | ||||||
|  |   using char_type = typename CompiledFormat::char_type; | ||||||
|  |   using range = internal::output_range<OutputIt, char_type>; | ||||||
|  |   using context = format_context_t<OutputIt, char_type>; | ||||||
|  |   return cf.template vformat_to<range, context>( | ||||||
|  |       range(out), {make_format_args<context>(args...)}); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | template <typename OutputIt, typename CompiledFormat, typename... Args, | ||||||
|  |           FMT_ENABLE_IF(internal::is_output_iterator<OutputIt>::value)> | ||||||
|  | format_to_n_result<OutputIt> format_to_n(OutputIt out, size_t n, | ||||||
|  |                                          const CompiledFormat& cf, | ||||||
|  |                                          const Args&... args) { | ||||||
|  |   auto it = | ||||||
|  |       format_to(internal::truncating_iterator<OutputIt>(out, n), cf, args...); | ||||||
|  |   return {it.base(), it.count()}; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | template <typename CompiledFormat, typename... Args> | ||||||
|  | std::size_t formatted_size(const CompiledFormat& cf, const Args&... args) { | ||||||
|  |   return fmt::format_to( | ||||||
|  |              internal::counting_iterator<typename CompiledFormat::char_type>(), | ||||||
|  |              cf, args...) | ||||||
|  |       .count(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | FMT_END_NAMESPACE | ||||||
|  |  | ||||||
|  | #endif  // FMT_COMPILE_H_ | ||||||
							
								
								
									
										1900
									
								
								third_party/spdlog/include/spdlog/fmt/bundled/core.h
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1900
									
								
								third_party/spdlog/include/spdlog/fmt/bundled/core.h
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										3871
									
								
								third_party/spdlog/include/spdlog/fmt/bundled/format.h
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3871
									
								
								third_party/spdlog/include/spdlog/fmt/bundled/format.h
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -8,65 +8,65 @@ | |||||||
| #ifndef FMT_LOCALE_H_ | #ifndef FMT_LOCALE_H_ | ||||||
| #define FMT_LOCALE_H_ | #define FMT_LOCALE_H_ | ||||||
|  |  | ||||||
| #include "format.h" |  | ||||||
| #include <locale> | #include <locale> | ||||||
|  | #include "format.h" | ||||||
|  |  | ||||||
| FMT_BEGIN_NAMESPACE | FMT_BEGIN_NAMESPACE | ||||||
|  |  | ||||||
| namespace internal { | namespace internal { | ||||||
| template <typename Char> | template <typename Char> | ||||||
| typename buffer_context<Char>::type::iterator vformat_to( | typename buffer_context<Char>::iterator vformat_to( | ||||||
|     const std::locale &loc, basic_buffer<Char> &buf, |     const std::locale& loc, buffer<Char>& buf, | ||||||
|     basic_string_view<Char> format_str, |     basic_string_view<Char> format_str, | ||||||
|     basic_format_args<typename buffer_context<Char>::type> args) { |     basic_format_args<buffer_context<Char>> args) { | ||||||
|   typedef back_insert_range<basic_buffer<Char> > range; |   using range = buffer_range<Char>; | ||||||
|   return vformat_to<arg_formatter<range>>( |   return vformat_to<arg_formatter<range>>(buf, to_string_view(format_str), args, | ||||||
|     buf, to_string_view(format_str), args, internal::locale_ref(loc)); |                                           internal::locale_ref(loc)); | ||||||
| } | } | ||||||
|  |  | ||||||
| template <typename Char> | template <typename Char> | ||||||
| std::basic_string<Char> vformat( | std::basic_string<Char> vformat(const std::locale& loc, | ||||||
|     const std::locale &loc, basic_string_view<Char> format_str, |                                 basic_string_view<Char> format_str, | ||||||
|     basic_format_args<typename buffer_context<Char>::type> args) { |                                 basic_format_args<buffer_context<Char>> args) { | ||||||
|   basic_memory_buffer<Char> buffer; |   basic_memory_buffer<Char> buffer; | ||||||
|   internal::vformat_to(loc, buffer, format_str, args); |   internal::vformat_to(loc, buffer, format_str, args); | ||||||
|   return fmt::to_string(buffer); |   return fmt::to_string(buffer); | ||||||
| } | } | ||||||
| } | }  // namespace internal | ||||||
|  |  | ||||||
| template <typename S, typename Char = FMT_CHAR(S)> | template <typename S, typename Char = char_t<S>> | ||||||
| inline std::basic_string<Char> vformat( | inline std::basic_string<Char> vformat( | ||||||
|     const std::locale &loc, const S &format_str, |     const std::locale& loc, const S& format_str, | ||||||
|     basic_format_args<typename buffer_context<Char>::type> args) { |     basic_format_args<buffer_context<Char>> args) { | ||||||
|   return internal::vformat(loc, to_string_view(format_str), args); |   return internal::vformat(loc, to_string_view(format_str), args); | ||||||
| } | } | ||||||
|  |  | ||||||
| template <typename S, typename... Args> | template <typename S, typename... Args, typename Char = char_t<S>> | ||||||
| inline std::basic_string<FMT_CHAR(S)> format( | inline std::basic_string<Char> format(const std::locale& loc, | ||||||
|     const std::locale &loc, const S &format_str, const Args &... args) { |                                       const S& format_str, Args&&... args) { | ||||||
|   return internal::vformat( |   return internal::vformat( | ||||||
|     loc, to_string_view(format_str), |       loc, to_string_view(format_str), | ||||||
|     *internal::checked_args<S, Args...>(format_str, args...)); |       {internal::make_args_checked<Args...>(format_str, args...)}); | ||||||
| } | } | ||||||
|  |  | ||||||
| template <typename String, typename OutputIt, typename... Args> | template <typename S, typename OutputIt, typename... Args, | ||||||
| inline typename std::enable_if<internal::is_output_iterator<OutputIt>::value, |           typename Char = enable_if_t< | ||||||
|                                OutputIt>::type |               internal::is_output_iterator<OutputIt>::value, char_t<S>>> | ||||||
|     vformat_to(OutputIt out, const std::locale &loc, const String &format_str, | inline OutputIt vformat_to(OutputIt out, const std::locale& loc, | ||||||
|                typename format_args_t<OutputIt, FMT_CHAR(String)>::type args) { |                            const S& format_str, | ||||||
|   typedef output_range<OutputIt, FMT_CHAR(String)> range; |                            format_args_t<OutputIt, Char> args) { | ||||||
|  |   using range = internal::output_range<OutputIt, Char>; | ||||||
|   return vformat_to<arg_formatter<range>>( |   return vformat_to<arg_formatter<range>>( | ||||||
|     range(out), to_string_view(format_str), args, internal::locale_ref(loc)); |       range(out), to_string_view(format_str), args, internal::locale_ref(loc)); | ||||||
| } | } | ||||||
|  |  | ||||||
| template <typename OutputIt, typename S, typename... Args> | template <typename OutputIt, typename S, typename... Args, | ||||||
| inline typename std::enable_if< |           FMT_ENABLE_IF(internal::is_output_iterator<OutputIt>::value&& | ||||||
|     internal::is_string<S>::value && |                             internal::is_string<S>::value)> | ||||||
|     internal::is_output_iterator<OutputIt>::value, OutputIt>::type | inline OutputIt format_to(OutputIt out, const std::locale& loc, | ||||||
|     format_to(OutputIt out, const std::locale &loc, const S &format_str, |                           const S& format_str, Args&&... args) { | ||||||
|               const Args &... args) { |  | ||||||
|   internal::check_format_string<Args...>(format_str); |   internal::check_format_string<Args...>(format_str); | ||||||
|   typedef typename format_context_t<OutputIt, FMT_CHAR(S)>::type context; |   using context = format_context_t<OutputIt, char_t<S>>; | ||||||
|   format_arg_store<context, Args...> as{args...}; |   format_arg_store<context, Args...> as{args...}; | ||||||
|   return vformat_to(out, loc, to_string_view(format_str), |   return vformat_to(out, loc, to_string_view(format_str), | ||||||
|                     basic_format_args<context>(as)); |                     basic_format_args<context>(as)); | ||||||
|   | |||||||
| @@ -8,22 +8,21 @@ | |||||||
| #ifndef FMT_OSTREAM_H_ | #ifndef FMT_OSTREAM_H_ | ||||||
| #define FMT_OSTREAM_H_ | #define FMT_OSTREAM_H_ | ||||||
|  |  | ||||||
| #include "format.h" |  | ||||||
| #include <ostream> | #include <ostream> | ||||||
|  | #include "format.h" | ||||||
|  |  | ||||||
| FMT_BEGIN_NAMESPACE | FMT_BEGIN_NAMESPACE | ||||||
| namespace internal { | namespace internal { | ||||||
|  |  | ||||||
| template <class Char> | template <class Char> class formatbuf : public std::basic_streambuf<Char> { | ||||||
| class formatbuf : public std::basic_streambuf<Char> { |  | ||||||
|  private: |  private: | ||||||
|   typedef typename std::basic_streambuf<Char>::int_type int_type; |   using int_type = typename std::basic_streambuf<Char>::int_type; | ||||||
|   typedef typename std::basic_streambuf<Char>::traits_type traits_type; |   using traits_type = typename std::basic_streambuf<Char>::traits_type; | ||||||
|  |  | ||||||
|   basic_buffer<Char> &buffer_; |   buffer<Char>& buffer_; | ||||||
|  |  | ||||||
|  public: |  public: | ||||||
|   formatbuf(basic_buffer<Char> &buffer) : buffer_(buffer) {} |   formatbuf(buffer<Char>& buf) : buffer_(buf) {} | ||||||
|  |  | ||||||
|  protected: |  protected: | ||||||
|   // The put-area is actually always empty. This makes the implementation |   // The put-area is actually always empty. This makes the implementation | ||||||
| @@ -39,33 +38,32 @@ class formatbuf : public std::basic_streambuf<Char> { | |||||||
|     return ch; |     return ch; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   std::streamsize xsputn(const Char *s, std::streamsize count) FMT_OVERRIDE { |   std::streamsize xsputn(const Char* s, std::streamsize count) FMT_OVERRIDE { | ||||||
|     buffer_.append(s, s + count); |     buffer_.append(s, s + count); | ||||||
|     return count; |     return count; | ||||||
|   } |   } | ||||||
| }; | }; | ||||||
|  |  | ||||||
| template <typename Char> | template <typename Char> struct test_stream : std::basic_ostream<Char> { | ||||||
| struct test_stream : std::basic_ostream<Char> { |  | ||||||
|  private: |  private: | ||||||
|   struct null; |   struct null; | ||||||
|   // Hide all operator<< from std::basic_ostream<Char>. |   // Hide all operator<< from std::basic_ostream<Char>. | ||||||
|   void operator<<(null); |   void operator<<(null); | ||||||
| }; | }; | ||||||
|  |  | ||||||
| // Checks if T has a user-defined operator<< (e.g. not a member of std::ostream). | // Checks if T has a user-defined operator<< (e.g. not a member of | ||||||
| template <typename T, typename Char> | // std::ostream). | ||||||
| class is_streamable { | template <typename T, typename Char> class is_streamable { | ||||||
|  private: |  private: | ||||||
|   template <typename U> |   template <typename U> | ||||||
|   static decltype( |   static decltype((void)(std::declval<test_stream<Char>&>() | ||||||
|     internal::declval<test_stream<Char>&>() |                          << std::declval<U>()), | ||||||
|       << internal::declval<U>(), std::true_type()) test(int); |                   std::true_type()) | ||||||
|  |   test(int); | ||||||
|  |  | ||||||
|   template <typename> |   template <typename> static std::false_type test(...); | ||||||
|   static std::false_type test(...); |  | ||||||
|  |  | ||||||
|   typedef decltype(test<T>(0)) result; |   using result = decltype(test<T>(0)); | ||||||
|  |  | ||||||
|  public: |  public: | ||||||
|   static const bool value = result::value; |   static const bool value = result::value; | ||||||
| @@ -73,65 +71,51 @@ class is_streamable { | |||||||
|  |  | ||||||
| // Write the content of buf to os. | // Write the content of buf to os. | ||||||
| template <typename Char> | template <typename Char> | ||||||
| void write(std::basic_ostream<Char> &os, basic_buffer<Char> &buf) { | void write(std::basic_ostream<Char>& os, buffer<Char>& buf) { | ||||||
|   const Char *data = buf.data(); |   const Char* buf_data = buf.data(); | ||||||
|   typedef std::make_unsigned<std::streamsize>::type UnsignedStreamSize; |   using unsigned_streamsize = std::make_unsigned<std::streamsize>::type; | ||||||
|   UnsignedStreamSize size = buf.size(); |   unsigned_streamsize size = buf.size(); | ||||||
|   UnsignedStreamSize max_size = |   unsigned_streamsize max_size = | ||||||
|       internal::to_unsigned((std::numeric_limits<std::streamsize>::max)()); |       to_unsigned((std::numeric_limits<std::streamsize>::max)()); | ||||||
|   do { |   do { | ||||||
|     UnsignedStreamSize n = size <= max_size ? size : max_size; |     unsigned_streamsize n = size <= max_size ? size : max_size; | ||||||
|     os.write(data, static_cast<std::streamsize>(n)); |     os.write(buf_data, static_cast<std::streamsize>(n)); | ||||||
|     data += n; |     buf_data += n; | ||||||
|     size -= n; |     size -= n; | ||||||
|   } while (size != 0); |   } while (size != 0); | ||||||
| } | } | ||||||
|  |  | ||||||
| template <typename Char, typename T> | template <typename Char, typename T> | ||||||
| void format_value(basic_buffer<Char> &buffer, const T &value) { | void format_value(buffer<Char>& buf, const T& value) { | ||||||
|   internal::formatbuf<Char> format_buf(buffer); |   formatbuf<Char> format_buf(buf); | ||||||
|   std::basic_ostream<Char> output(&format_buf); |   std::basic_ostream<Char> output(&format_buf); | ||||||
|   output.exceptions(std::ios_base::failbit | std::ios_base::badbit); |   output.exceptions(std::ios_base::failbit | std::ios_base::badbit); | ||||||
|   output << value; |   output << value; | ||||||
|   buffer.resize(buffer.size()); |   buf.resize(buf.size()); | ||||||
| } | } | ||||||
| }  // namespace internal |  | ||||||
|  |  | ||||||
| // Disable conversion to int if T has an overloaded operator<< which is a free |  | ||||||
| // function (not a member of std::ostream). |  | ||||||
| template <typename T, typename Char> |  | ||||||
| struct convert_to_int<T, Char, void> { |  | ||||||
|   static const bool value = |  | ||||||
|     convert_to_int<T, Char, int>::value && |  | ||||||
|     !internal::is_streamable<T, Char>::value; |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| // Formats an object of type T that has an overloaded ostream operator<<. | // Formats an object of type T that has an overloaded ostream operator<<. | ||||||
| template <typename T, typename Char> | template <typename T, typename Char> | ||||||
| struct formatter<T, Char, | struct fallback_formatter<T, Char, enable_if_t<is_streamable<T, Char>::value>> | ||||||
|     typename std::enable_if< |  | ||||||
|       internal::is_streamable<T, Char>::value && |  | ||||||
|       !internal::format_type< |  | ||||||
|         typename buffer_context<Char>::type, T>::value>::type> |  | ||||||
|     : formatter<basic_string_view<Char>, Char> { |     : formatter<basic_string_view<Char>, Char> { | ||||||
|  |  | ||||||
|   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; | ||||||
|     internal::format_value(buffer, value); |     format_value(buffer, value); | ||||||
|     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); | ||||||
|   } |   } | ||||||
| }; | }; | ||||||
|  | }  // namespace internal | ||||||
|  |  | ||||||
| template <typename Char> | template <typename Char> | ||||||
| inline void vprint(std::basic_ostream<Char> &os, | void vprint(std::basic_ostream<Char>& os, basic_string_view<Char> format_str, | ||||||
|                    basic_string_view<Char> format_str, |             basic_format_args<buffer_context<Char>> args) { | ||||||
|                    basic_format_args<typename buffer_context<Char>::type> args) { |  | ||||||
|   basic_memory_buffer<Char> buffer; |   basic_memory_buffer<Char> buffer; | ||||||
|   internal::vformat_to(buffer, format_str, args); |   internal::vformat_to(buffer, format_str, args); | ||||||
|   internal::write(os, buffer); |   internal::write(os, buffer); | ||||||
| } | } | ||||||
|  |  | ||||||
| /** | /** | ||||||
|   \rst |   \rst | ||||||
|   Prints formatted data to the stream *os*. |   Prints formatted data to the stream *os*. | ||||||
| @@ -141,12 +125,11 @@ inline void vprint(std::basic_ostream<Char> &os, | |||||||
|     fmt::print(cerr, "Don't {}!", "panic"); |     fmt::print(cerr, "Don't {}!", "panic"); | ||||||
|   \endrst |   \endrst | ||||||
|  */ |  */ | ||||||
| template <typename S, typename... Args> | template <typename S, typename... Args, | ||||||
| inline typename std::enable_if<internal::is_string<S>::value>::type |           typename Char = enable_if_t<internal::is_string<S>::value, char_t<S>>> | ||||||
| print(std::basic_ostream<FMT_CHAR(S)> &os, const S &format_str, | void print(std::basic_ostream<Char>& os, const S& format_str, Args&&... args) { | ||||||
|       const Args & ... args) { |   vprint(os, to_string_view(format_str), | ||||||
|   internal::checked_args<S, Args...> ca(format_str, args...); |          {internal::make_args_checked<Args...>(format_str, args...)}); | ||||||
|   vprint(os, to_string_view(format_str), *ca); |  | ||||||
| } | } | ||||||
| FMT_END_NAMESPACE | FMT_END_NAMESPACE | ||||||
|  |  | ||||||
|   | |||||||
| @@ -10,7 +10,7 @@ | |||||||
|  |  | ||||||
| #if defined(__MINGW32__) || defined(__CYGWIN__) | #if defined(__MINGW32__) || defined(__CYGWIN__) | ||||||
| // Workaround MinGW bug https://sourceforge.net/p/mingw/bugs/2024/. | // Workaround MinGW bug https://sourceforge.net/p/mingw/bugs/2024/. | ||||||
| # undef __STRICT_ANSI__ | #  undef __STRICT_ANSI__ | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| #include <errno.h> | #include <errno.h> | ||||||
| @@ -22,42 +22,42 @@ | |||||||
| #include <cstddef> | #include <cstddef> | ||||||
|  |  | ||||||
| #if defined __APPLE__ || defined(__FreeBSD__) | #if defined __APPLE__ || defined(__FreeBSD__) | ||||||
| # include <xlocale.h>  // for LC_NUMERIC_MASK on OS X | #  include <xlocale.h>  // for LC_NUMERIC_MASK on OS X | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| #include "format.h" | #include "format.h" | ||||||
|  |  | ||||||
| #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. | ||||||
| #  define FMT_POSIX(call) _##call | #    define FMT_POSIX(call) _##call | ||||||
| # else | #  else | ||||||
| #  define FMT_POSIX(call) call | #    define FMT_POSIX(call) call | ||||||
| # endif | #  endif | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| // Calls to system functions are wrapped in FMT_SYSTEM for testability. | // Calls to system functions are wrapped in FMT_SYSTEM for testability. | ||||||
| #ifdef FMT_SYSTEM | #ifdef FMT_SYSTEM | ||||||
| # define FMT_POSIX_CALL(call) FMT_SYSTEM(call) | #  define FMT_POSIX_CALL(call) FMT_SYSTEM(call) | ||||||
| #else | #else | ||||||
| # define FMT_SYSTEM(call) call | #  define FMT_SYSTEM(call) call | ||||||
| # ifdef _WIN32 | #  ifdef _WIN32 | ||||||
| // Fix warnings about deprecated symbols. | // Fix warnings about deprecated symbols. | ||||||
| #  define FMT_POSIX_CALL(call) ::_##call | #    define FMT_POSIX_CALL(call) ::_##call | ||||||
| # else | #  else | ||||||
| #  define FMT_POSIX_CALL(call) ::call | #    define FMT_POSIX_CALL(call) ::call | ||||||
| # endif | #  endif | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| // Retries the expression while it evaluates to error_result and errno | // Retries the expression while it evaluates to error_result and errno | ||||||
| // equals to EINTR. | // equals to EINTR. | ||||||
| #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 | ||||||
|  |  | ||||||
| #define FMT_RETRY(result, expression) FMT_RETRY_VAL(result, expression, -1) | #define FMT_RETRY(result, expression) FMT_RETRY_VAL(result, expression, -1) | ||||||
| @@ -69,7 +69,7 @@ FMT_BEGIN_NAMESPACE | |||||||
|   A reference to a null-terminated string. It can be constructed from a C |   A reference to a null-terminated string. It can be constructed from a C | ||||||
|   string or ``std::string``. |   string or ``std::string``. | ||||||
|  |  | ||||||
|   You can use one of the following typedefs for common character types: |   You can use one of the following type aliases for common character types: | ||||||
|  |  | ||||||
|   +---------------+-----------------------------+ |   +---------------+-----------------------------+ | ||||||
|   | Type          | Definition                  | |   | Type          | Definition                  | | ||||||
| @@ -89,28 +89,27 @@ FMT_BEGIN_NAMESPACE | |||||||
|     format(std::string("{}"), 42); |     format(std::string("{}"), 42); | ||||||
|   \endrst |   \endrst | ||||||
|  */ |  */ | ||||||
| template <typename Char> | template <typename Char> class basic_cstring_view { | ||||||
| class basic_cstring_view { |  | ||||||
|  private: |  private: | ||||||
|   const Char *data_; |   const Char* data_; | ||||||
|  |  | ||||||
|  public: |  public: | ||||||
|   /** Constructs a string reference object from a C string. */ |   /** Constructs a string reference object from a C string. */ | ||||||
|   basic_cstring_view(const Char *s) : data_(s) {} |   basic_cstring_view(const Char* s) : data_(s) {} | ||||||
|  |  | ||||||
|   /** |   /** | ||||||
|     \rst |     \rst | ||||||
|     Constructs a string reference from an ``std::string`` object. |     Constructs a string reference from an ``std::string`` object. | ||||||
|     \endrst |     \endrst | ||||||
|    */ |    */ | ||||||
|   basic_cstring_view(const std::basic_string<Char> &s) : data_(s.c_str()) {} |   basic_cstring_view(const std::basic_string<Char>& s) : data_(s.c_str()) {} | ||||||
|  |  | ||||||
|   /** Returns the pointer to a C string. */ |   /** Returns the pointer to a C string. */ | ||||||
|   const Char *c_str() const { return data_; } |   const Char* c_str() const { return data_; } | ||||||
| }; | }; | ||||||
|  |  | ||||||
| typedef basic_cstring_view<char> cstring_view; | using cstring_view = basic_cstring_view<char>; | ||||||
| typedef basic_cstring_view<wchar_t> wcstring_view; | using wcstring_view = basic_cstring_view<wchar_t>; | ||||||
|  |  | ||||||
| // An error code. | // An error code. | ||||||
| class error_code { | class error_code { | ||||||
| @@ -126,33 +125,32 @@ class error_code { | |||||||
| // A buffered file. | // A buffered file. | ||||||
| class buffered_file { | class buffered_file { | ||||||
|  private: |  private: | ||||||
|   FILE *file_; |   FILE* file_; | ||||||
|  |  | ||||||
|   friend class file; |   friend class file; | ||||||
|  |  | ||||||
|   explicit buffered_file(FILE *f) : file_(f) {} |   explicit buffered_file(FILE* f) : file_(f) {} | ||||||
|  |  | ||||||
|  public: |  public: | ||||||
|   // 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_(FMT_NULL) {} |   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: |  private: | ||||||
|   buffered_file(const buffered_file &) = delete; |   buffered_file(const buffered_file&) = delete; | ||||||
|   void operator=(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_ = FMT_NULL; |     other.file_ = nullptr; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   buffered_file& operator=(buffered_file &&other) { |   buffered_file& operator=(buffered_file&& other) { | ||||||
|     close(); |     close(); | ||||||
|     file_ = other.file_; |     file_ = other.file_; | ||||||
|     other.file_ = FMT_NULL; |     other.file_ = nullptr; | ||||||
|     return *this; |     return *this; | ||||||
|   } |   } | ||||||
|  |  | ||||||
| @@ -163,18 +161,18 @@ class buffered_file { | |||||||
|   FMT_API void close(); |   FMT_API void close(); | ||||||
|  |  | ||||||
|   // Returns the pointer to a FILE object representing this file. |   // Returns the pointer to a FILE object representing this file. | ||||||
|   FILE *get() const FMT_NOEXCEPT { return file_; } |   FILE* get() const FMT_NOEXCEPT { return file_; } | ||||||
|  |  | ||||||
|   // We place parentheses around fileno to workaround a bug in some versions |   // We place parentheses around fileno to workaround a bug in some versions | ||||||
|   // of MinGW that define fileno as a macro. |   // of MinGW that define fileno as a macro. | ||||||
|   FMT_API int (fileno)() const; |   FMT_API int(fileno)() const; | ||||||
|  |  | ||||||
|   void vprint(string_view format_str, format_args args) { |   void vprint(string_view format_str, format_args args) { | ||||||
|     fmt::vprint(file_, format_str, args); |     fmt::vprint(file_, format_str, args); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   template <typename... Args> |   template <typename... Args> | ||||||
|   inline void print(string_view format_str, const Args & ... args) { |   inline void print(string_view format_str, const Args&... args) { | ||||||
|     vprint(format_str, make_format_args(args...)); |     vprint(format_str, make_format_args(args...)); | ||||||
|   } |   } | ||||||
| }; | }; | ||||||
| @@ -195,9 +193,9 @@ class file { | |||||||
|  public: |  public: | ||||||
|   // Possible values for the oflag argument to the constructor. |   // Possible values for the oflag argument to the constructor. | ||||||
|   enum { |   enum { | ||||||
|     RDONLY = FMT_POSIX(O_RDONLY), // Open for reading only. |     RDONLY = FMT_POSIX(O_RDONLY),  // Open for reading only. | ||||||
|     WRONLY = FMT_POSIX(O_WRONLY), // Open for writing only. |     WRONLY = FMT_POSIX(O_WRONLY),  // Open for writing only. | ||||||
|     RDWR   = FMT_POSIX(O_RDWR)    // Open for reading and writing. |     RDWR = FMT_POSIX(O_RDWR)       // Open for reading and writing. | ||||||
|   }; |   }; | ||||||
|  |  | ||||||
|   // Constructs a file object which doesn't represent any file. |   // Constructs a file object which doesn't represent any file. | ||||||
| @@ -207,15 +205,13 @@ class file { | |||||||
|   FMT_API file(cstring_view path, int oflag); |   FMT_API file(cstring_view path, int oflag); | ||||||
|  |  | ||||||
|  private: |  private: | ||||||
|   file(const file &) = delete; |   file(const file&) = delete; | ||||||
|   void operator=(const file &) = delete; |   void operator=(const file&) = delete; | ||||||
|  |  | ||||||
|  public: |  public: | ||||||
|   file(file &&other) FMT_NOEXCEPT : fd_(other.fd_) { |   file(file&& other) FMT_NOEXCEPT : fd_(other.fd_) { other.fd_ = -1; } | ||||||
|     other.fd_ = -1; |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   file& operator=(file &&other) { |   file& operator=(file&& other) { | ||||||
|     close(); |     close(); | ||||||
|     fd_ = other.fd_; |     fd_ = other.fd_; | ||||||
|     other.fd_ = -1; |     other.fd_ = -1; | ||||||
| @@ -236,10 +232,10 @@ class file { | |||||||
|   FMT_API long long size() const; |   FMT_API long long size() const; | ||||||
|  |  | ||||||
|   // Attempts to read count bytes from the file into the specified buffer. |   // Attempts to read count bytes from the file into the specified buffer. | ||||||
|   FMT_API std::size_t read(void *buffer, std::size_t count); |   FMT_API std::size_t read(void* buffer, std::size_t count); | ||||||
|  |  | ||||||
|   // Attempts to write count bytes from the specified buffer to the file. |   // Attempts to write count bytes from the specified buffer to the file. | ||||||
|   FMT_API std::size_t write(const void *buffer, std::size_t count); |   FMT_API std::size_t write(const void* buffer, std::size_t count); | ||||||
|  |  | ||||||
|   // Duplicates a file descriptor with the dup function and returns |   // Duplicates a file descriptor with the dup function and returns | ||||||
|   // the duplicate as a file object. |   // the duplicate as a file object. | ||||||
| @@ -251,68 +247,59 @@ class file { | |||||||
|  |  | ||||||
|   // Makes fd be the copy of this file descriptor, closing fd first if |   // Makes fd be the copy of this file descriptor, closing fd first if | ||||||
|   // necessary. |   // necessary. | ||||||
|   FMT_API void dup2(int fd, error_code &ec) FMT_NOEXCEPT; |   FMT_API void dup2(int fd, error_code& ec) FMT_NOEXCEPT; | ||||||
|  |  | ||||||
|   // Creates a pipe setting up read_end and write_end file objects for reading |   // Creates a pipe setting up read_end and write_end file objects for reading | ||||||
|   // and writing respectively. |   // and writing respectively. | ||||||
|   FMT_API static void pipe(file &read_end, file &write_end); |   FMT_API static void pipe(file& read_end, file& write_end); | ||||||
|  |  | ||||||
|   // Creates a buffered_file object associated with this file and detaches |   // Creates a buffered_file object associated with this file and detaches | ||||||
|   // this file object from the file. |   // this file object from the file. | ||||||
|   FMT_API buffered_file fdopen(const char *mode); |   FMT_API buffered_file fdopen(const char* mode); | ||||||
| }; | }; | ||||||
|  |  | ||||||
| // Returns the memory page size. | // Returns the memory page size. | ||||||
| long getpagesize(); | long getpagesize(); | ||||||
|  |  | ||||||
| #if (defined(LC_NUMERIC_MASK) || defined(_MSC_VER)) && \ |  | ||||||
|     !defined(__ANDROID__) && !defined(__CYGWIN__) && !defined(__OpenBSD__) && \ |  | ||||||
|     !defined(__NEWLIB_H__) |  | ||||||
| # define FMT_LOCALE |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| #ifdef FMT_LOCALE | #ifdef FMT_LOCALE | ||||||
| // A "C" numeric locale. | // A "C" numeric locale. | ||||||
| class Locale { | class Locale { | ||||||
|  private: |  private: | ||||||
| # ifdef _MSC_VER | #  ifdef _WIN32 | ||||||
|   typedef _locale_t locale_t; |   using locale_t = _locale_t; | ||||||
|  |  | ||||||
|   enum { LC_NUMERIC_MASK = LC_NUMERIC }; |   enum { LC_NUMERIC_MASK = LC_NUMERIC }; | ||||||
|  |  | ||||||
|   static locale_t newlocale(int category_mask, const char *locale, locale_t) { |   static locale_t newlocale(int category_mask, const char* locale, locale_t) { | ||||||
|     return _create_locale(category_mask, locale); |     return _create_locale(category_mask, locale); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   static void freelocale(locale_t locale) { |   static void freelocale(locale_t locale) { _free_locale(locale); } | ||||||
|     _free_locale(locale); |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   static double strtod_l(const char *nptr, char **endptr, _locale_t locale) { |   static double strtod_l(const char* nptr, char** endptr, _locale_t locale) { | ||||||
|     return _strtod_l(nptr, endptr, locale); |     return _strtod_l(nptr, endptr, locale); | ||||||
|   } |   } | ||||||
| # endif | #  endif | ||||||
|  |  | ||||||
|   locale_t locale_; |   locale_t locale_; | ||||||
|  |  | ||||||
|   Locale(const Locale &) = delete; |   Locale(const Locale&) = delete; | ||||||
|   void operator=(const Locale &) = delete; |   void operator=(const Locale&) = delete; | ||||||
|  |  | ||||||
|  public: |  public: | ||||||
|   typedef locale_t Type; |   using type = locale_t; | ||||||
|  |  | ||||||
|   Locale() : locale_(newlocale(LC_NUMERIC_MASK, "C", FMT_NULL)) { |   Locale() : locale_(newlocale(LC_NUMERIC_MASK, "C", nullptr)) { | ||||||
|     if (!locale_) |     if (!locale_) FMT_THROW(system_error(errno, "cannot create locale")); | ||||||
|       FMT_THROW(system_error(errno, "cannot create locale")); |  | ||||||
|   } |   } | ||||||
|   ~Locale() { freelocale(locale_); } |   ~Locale() { freelocale(locale_); } | ||||||
|  |  | ||||||
|   Type get() const { return locale_; } |   type get() const { return locale_; } | ||||||
|  |  | ||||||
|   // Converts string to floating-point number and advances str past the end |   // Converts string to floating-point number and advances str past the end | ||||||
|   // of the parsed input. |   // of the parsed input. | ||||||
|   double strtod(const char *&str) const { |   double strtod(const char*& str) const { | ||||||
|     char *end = FMT_NULL; |     char* end = nullptr; | ||||||
|     double result = strtod_l(str, &end, locale_); |     double result = strtod_l(str, &end, locale_); | ||||||
|     str = end; |     str = end; | ||||||
|     return result; |     return result; | ||||||
|   | |||||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -1,4 +1,4 @@ | |||||||
| // Formatting library for C++ - the core API | // Formatting library for C++ - experimental range support | ||||||
| // | // | ||||||
| // Copyright (c) 2012 - present, Victor Zverovich | // Copyright (c) 2012 - present, Victor Zverovich | ||||||
| // All rights reserved. | // All rights reserved. | ||||||
| @@ -12,20 +12,19 @@ | |||||||
| #ifndef FMT_RANGES_H_ | #ifndef FMT_RANGES_H_ | ||||||
| #define FMT_RANGES_H_ | #define FMT_RANGES_H_ | ||||||
|  |  | ||||||
| #include "format.h" |  | ||||||
| #include <type_traits> | #include <type_traits> | ||||||
|  | #include "format.h" | ||||||
|  |  | ||||||
| // output only up to N items from the range. | // output only up to N items from the range. | ||||||
| #ifndef FMT_RANGE_OUTPUT_LENGTH_LIMIT | #ifndef FMT_RANGE_OUTPUT_LENGTH_LIMIT | ||||||
| # define FMT_RANGE_OUTPUT_LENGTH_LIMIT 256 | #  define FMT_RANGE_OUTPUT_LENGTH_LIMIT 256 | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| FMT_BEGIN_NAMESPACE | FMT_BEGIN_NAMESPACE | ||||||
|  |  | ||||||
| template <typename Char> | template <typename Char> struct formatting_base { | ||||||
| struct formatting_base { |  | ||||||
|   template <typename ParseContext> |   template <typename ParseContext> | ||||||
|   FMT_CONSTEXPR auto parse(ParseContext &ctx) -> decltype(ctx.begin()) { |   FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { | ||||||
|     return ctx.begin(); |     return ctx.begin(); | ||||||
|   } |   } | ||||||
| }; | }; | ||||||
| @@ -33,7 +32,8 @@ struct formatting_base { | |||||||
| template <typename Char, typename Enable = void> | template <typename Char, typename Enable = void> | ||||||
| struct formatting_range : formatting_base<Char> { | struct formatting_range : formatting_base<Char> { | ||||||
|   static FMT_CONSTEXPR_DECL const std::size_t range_length_limit = |   static FMT_CONSTEXPR_DECL const std::size_t range_length_limit = | ||||||
|       FMT_RANGE_OUTPUT_LENGTH_LIMIT; // output only up to N items from the range. |       FMT_RANGE_OUTPUT_LENGTH_LIMIT;  // output only up to N items from the | ||||||
|  |                                       // range. | ||||||
|   Char prefix; |   Char prefix; | ||||||
|   Char delimiter; |   Char delimiter; | ||||||
|   Char postfix; |   Char postfix; | ||||||
| @@ -55,87 +55,78 @@ struct formatting_tuple : formatting_base<Char> { | |||||||
| namespace internal { | namespace internal { | ||||||
|  |  | ||||||
| template <typename RangeT, typename OutputIterator> | template <typename RangeT, typename OutputIterator> | ||||||
| void copy(const RangeT &range, OutputIterator out) { | OutputIterator copy(const RangeT& range, OutputIterator out) { | ||||||
|   for (auto it = range.begin(), end = range.end(); it != end; ++it) |   for (auto it = range.begin(), end = range.end(); it != end; ++it) | ||||||
|     *out++ = *it; |     *out++ = *it; | ||||||
|  |   return out; | ||||||
| } | } | ||||||
|  |  | ||||||
| template <typename OutputIterator> | template <typename OutputIterator> | ||||||
| void copy(const char *str, OutputIterator out) { | OutputIterator copy(const char* str, OutputIterator out) { | ||||||
|   const char *p_curr = str; |   while (*str) *out++ = *str++; | ||||||
|   while (*p_curr) { |   return out; | ||||||
|     *out++ = *p_curr++; |  | ||||||
|   } |  | ||||||
| } | } | ||||||
|  |  | ||||||
| template <typename OutputIterator> | template <typename OutputIterator> | ||||||
| void copy(char ch, OutputIterator out) { | OutputIterator copy(char ch, OutputIterator out) { | ||||||
|   *out++ = ch; |   *out++ = ch; | ||||||
|  |   return out; | ||||||
| } | } | ||||||
|  |  | ||||||
| /// Return true value if T has std::string interface, like std::string_view. | /// Return true value if T has std::string interface, like std::string_view. | ||||||
| template <typename T> | template <typename T> class is_like_std_string { | ||||||
| class is_like_std_string { |  | ||||||
|   template <typename U> |   template <typename U> | ||||||
|   static auto check(U *p) -> |   static auto check(U* p) | ||||||
|     decltype(p->find('a'), p->length(), p->data(), int()); |       -> decltype((void)p->find('a'), p->length(), (void)p->data(), int()); | ||||||
|   template <typename> |   template <typename> static void check(...); | ||||||
|   static void check(...); |  | ||||||
|  |  | ||||||
|  public: |  public: | ||||||
|   static FMT_CONSTEXPR_DECL const bool value = |   static FMT_CONSTEXPR_DECL const bool value = | ||||||
|     !std::is_void<decltype(check<T>(FMT_NULL))>::value; |       is_string<T>::value || !std::is_void<decltype(check<T>(nullptr))>::value; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| template <typename Char> | template <typename Char> | ||||||
| struct is_like_std_string<fmt::basic_string_view<Char>> : std::true_type {}; | struct is_like_std_string<fmt::basic_string_view<Char>> : std::true_type {}; | ||||||
|  |  | ||||||
| template <typename... Ts> | template <typename... Ts> struct conditional_helper {}; | ||||||
| struct conditional_helper {}; |  | ||||||
|  |  | ||||||
| template <typename T, typename _ = void> | template <typename T, typename _ = void> struct is_range_ : std::false_type {}; | ||||||
| struct is_range_ : std::false_type {}; |  | ||||||
|  |  | ||||||
| #if !FMT_MSC_VER || FMT_MSC_VER > 1800 | #if !FMT_MSC_VER || FMT_MSC_VER > 1800 | ||||||
| template <typename T> | template <typename T> | ||||||
| struct is_range_<T, typename std::conditional< | struct is_range_< | ||||||
|                     false, |     T, conditional_t<false, | ||||||
|                     conditional_helper<decltype(internal::declval<T>().begin()), |                      conditional_helper<decltype(std::declval<T>().begin()), | ||||||
|                                        decltype(internal::declval<T>().end())>, |                                         decltype(std::declval<T>().end())>, | ||||||
|                     void>::type> : std::true_type {}; |                      void>> : std::true_type {}; | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| /// tuple_size and tuple_element check. | /// tuple_size and tuple_element check. | ||||||
| template <typename T> | template <typename T> class is_tuple_like_ { | ||||||
| class is_tuple_like_ { |  | ||||||
|   template <typename U> |   template <typename U> | ||||||
|   static auto check(U *p) -> |   static auto check(U* p) | ||||||
|     decltype(std::tuple_size<U>::value, |       -> decltype(std::tuple_size<U>::value, | ||||||
|       internal::declval<typename std::tuple_element<0, U>::type>(), int()); |                   (void)std::declval<typename std::tuple_element<0, U>::type>(), | ||||||
|   template <typename> |                   int()); | ||||||
|   static void check(...); |   template <typename> static void check(...); | ||||||
|  |  | ||||||
|  public: |  public: | ||||||
|   static FMT_CONSTEXPR_DECL const bool value = |   static FMT_CONSTEXPR_DECL const bool value = | ||||||
|     !std::is_void<decltype(check<T>(FMT_NULL))>::value; |       !std::is_void<decltype(check<T>(nullptr))>::value; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| // Check for integer_sequence | // Check for integer_sequence | ||||||
| #if defined(__cpp_lib_integer_sequence) || FMT_MSC_VER >= 1900 | #if defined(__cpp_lib_integer_sequence) || FMT_MSC_VER >= 1900 | ||||||
| template <typename T, T... N> | template <typename T, T... N> | ||||||
| using integer_sequence = std::integer_sequence<T, N...>; | using integer_sequence = std::integer_sequence<T, N...>; | ||||||
| template <std::size_t... N> | template <std::size_t... N> using index_sequence = std::index_sequence<N...>; | ||||||
| using index_sequence = std::index_sequence<N...>; |  | ||||||
| template <std::size_t N> | template <std::size_t N> | ||||||
| using make_index_sequence = std::make_index_sequence<N>; | using make_index_sequence = std::make_index_sequence<N>; | ||||||
| #else | #else | ||||||
| template <typename T, T... N> | template <typename T, T... N> struct integer_sequence { | ||||||
| struct integer_sequence { |   using value_type = T; | ||||||
|   typedef T value_type; |  | ||||||
|  |  | ||||||
|   static FMT_CONSTEXPR std::size_t size() { |   static FMT_CONSTEXPR std::size_t size() { return sizeof...(N); } | ||||||
|     return sizeof...(N); |  | ||||||
|   } |  | ||||||
| }; | }; | ||||||
|  |  | ||||||
| template <std::size_t... N> | template <std::size_t... N> | ||||||
| @@ -151,7 +142,7 @@ using make_index_sequence = make_integer_sequence<std::size_t, N>; | |||||||
| #endif | #endif | ||||||
|  |  | ||||||
| template <class Tuple, class F, size_t... Is> | template <class Tuple, class F, size_t... Is> | ||||||
| void for_each(index_sequence<Is...>, Tuple &&tup, F &&f) FMT_NOEXCEPT { | void for_each(index_sequence<Is...>, Tuple&& tup, F&& f) FMT_NOEXCEPT { | ||||||
|   using std::get; |   using std::get; | ||||||
|   // using free function get<I>(T) now. |   // using free function get<I>(T) now. | ||||||
|   const int _[] = {0, ((void)f(get<Is>(tup)), 0)...}; |   const int _[] = {0, ((void)f(get<Is>(tup)), 0)...}; | ||||||
| @@ -159,26 +150,25 @@ void for_each(index_sequence<Is...>, Tuple &&tup, F &&f) FMT_NOEXCEPT { | |||||||
| } | } | ||||||
|  |  | ||||||
| template <class T> | template <class T> | ||||||
| FMT_CONSTEXPR make_index_sequence<std::tuple_size<T>::value> | FMT_CONSTEXPR make_index_sequence<std::tuple_size<T>::value> get_indexes( | ||||||
| get_indexes(T const &) { return {}; } |     T const&) { | ||||||
|  |   return {}; | ||||||
|  | } | ||||||
|  |  | ||||||
| template <class Tuple, class F> | template <class Tuple, class F> void for_each(Tuple&& tup, F&& f) { | ||||||
| void for_each(Tuple &&tup, F &&f) { |  | ||||||
|   const auto indexes = get_indexes(tup); |   const auto indexes = get_indexes(tup); | ||||||
|   for_each(indexes, std::forward<Tuple>(tup), std::forward<F>(f)); |   for_each(indexes, std::forward<Tuple>(tup), std::forward<F>(f)); | ||||||
| } | } | ||||||
|  |  | ||||||
| template<typename Arg> | template <typename Arg, FMT_ENABLE_IF(!is_like_std_string< | ||||||
| FMT_CONSTEXPR const char* format_str_quoted(bool add_space, const Arg&, |                                       typename std::decay<Arg>::type>::value)> | ||||||
|   typename std::enable_if< | FMT_CONSTEXPR const char* format_str_quoted(bool add_space, const Arg&) { | ||||||
|     !is_like_std_string<typename std::decay<Arg>::type>::value>::type* = nullptr) { |  | ||||||
|   return add_space ? " {}" : "{}"; |   return add_space ? " {}" : "{}"; | ||||||
| } | } | ||||||
|  |  | ||||||
| template<typename Arg> | template <typename Arg, FMT_ENABLE_IF(is_like_std_string< | ||||||
| FMT_CONSTEXPR const char* format_str_quoted(bool add_space, const Arg&, |                                       typename std::decay<Arg>::type>::value)> | ||||||
|   typename std::enable_if< | FMT_CONSTEXPR const char* format_str_quoted(bool add_space, const Arg&) { | ||||||
|     is_like_std_string<typename std::decay<Arg>::type>::value>::type* = nullptr) { |  | ||||||
|   return add_space ? " \"{}\"" : "\"{}\""; |   return add_space ? " \"{}\"" : "\"{}\""; | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -186,61 +176,58 @@ FMT_CONSTEXPR const char* format_str_quoted(bool add_space, const char*) { | |||||||
|   return add_space ? " \"{}\"" : "\"{}\""; |   return add_space ? " \"{}\"" : "\"{}\""; | ||||||
| } | } | ||||||
| FMT_CONSTEXPR const wchar_t* format_str_quoted(bool add_space, const wchar_t*) { | FMT_CONSTEXPR const wchar_t* format_str_quoted(bool add_space, const wchar_t*) { | ||||||
|     return add_space ? L" \"{}\"" : L"\"{}\""; |   return add_space ? L" \"{}\"" : L"\"{}\""; | ||||||
| } | } | ||||||
|  |  | ||||||
| FMT_CONSTEXPR const char* format_str_quoted(bool add_space, const char) { | FMT_CONSTEXPR const char* format_str_quoted(bool add_space, const char) { | ||||||
|     return add_space ? " '{}'" : "'{}'"; |   return add_space ? " '{}'" : "'{}'"; | ||||||
| } | } | ||||||
| FMT_CONSTEXPR const wchar_t* format_str_quoted(bool add_space, const wchar_t) { | FMT_CONSTEXPR const wchar_t* format_str_quoted(bool add_space, const wchar_t) { | ||||||
|     return add_space ? L" '{}'" : L"'{}'"; |   return add_space ? L" '{}'" : L"'{}'"; | ||||||
| } | } | ||||||
|  |  | ||||||
| }  // namespace internal | }  // namespace internal | ||||||
|  |  | ||||||
| template <typename T> | template <typename T> struct is_tuple_like { | ||||||
| struct is_tuple_like { |  | ||||||
|   static FMT_CONSTEXPR_DECL const bool value = |   static FMT_CONSTEXPR_DECL const bool value = | ||||||
|     internal::is_tuple_like_<T>::value && !internal::is_range_<T>::value; |       internal::is_tuple_like_<T>::value && !internal::is_range_<T>::value; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| template <typename TupleT, typename Char> | template <typename TupleT, typename Char> | ||||||
| struct formatter<TupleT, Char, | struct formatter<TupleT, Char, enable_if_t<fmt::is_tuple_like<TupleT>::value>> { | ||||||
|     typename std::enable_if<fmt::is_tuple_like<TupleT>::value>::type> { |  private: | ||||||
| private: |  | ||||||
|   // C++11 generic lambda for format() |   // C++11 generic lambda for format() | ||||||
|   template <typename FormatContext> |   template <typename FormatContext> struct format_each { | ||||||
|   struct format_each { |     template <typename T> void operator()(const T& v) { | ||||||
|     template <typename T> |  | ||||||
|     void operator()(const T& v) { |  | ||||||
|       if (i > 0) { |       if (i > 0) { | ||||||
|         if (formatting.add_prepostfix_space) { |         if (formatting.add_prepostfix_space) { | ||||||
|           *out++ = ' '; |           *out++ = ' '; | ||||||
|         } |         } | ||||||
|         internal::copy(formatting.delimiter, out); |         out = internal::copy(formatting.delimiter, out); | ||||||
|       } |       } | ||||||
|       format_to(out, |       out = format_to(out, | ||||||
|                 internal::format_str_quoted( |                       internal::format_str_quoted( | ||||||
|                     (formatting.add_delimiter_spaces && i > 0), v), |                           (formatting.add_delimiter_spaces && i > 0), v), | ||||||
|                 v); |                       v); | ||||||
|       ++i; |       ++i; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     formatting_tuple<Char>& formatting; |     formatting_tuple<Char>& formatting; | ||||||
|     std::size_t& i; |     std::size_t& i; | ||||||
|     typename std::add_lvalue_reference<decltype(std::declval<FormatContext>().out())>::type out; |     typename std::add_lvalue_reference<decltype( | ||||||
|  |         std::declval<FormatContext>().out())>::type out; | ||||||
|   }; |   }; | ||||||
|  |  | ||||||
| public: |  public: | ||||||
|   formatting_tuple<Char> formatting; |   formatting_tuple<Char> formatting; | ||||||
|  |  | ||||||
|   template <typename ParseContext> |   template <typename ParseContext> | ||||||
|   FMT_CONSTEXPR auto parse(ParseContext &ctx) -> decltype(ctx.begin()) { |   FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { | ||||||
|     return formatting.parse(ctx); |     return formatting.parse(ctx); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   template <typename FormatContext = format_context> |   template <typename FormatContext = format_context> | ||||||
|   auto format(const TupleT &values, FormatContext &ctx) -> decltype(ctx.out()) { |   auto format(const TupleT& values, FormatContext& ctx) -> decltype(ctx.out()) { | ||||||
|     auto out = ctx.out(); |     auto out = ctx.out(); | ||||||
|     std::size_t i = 0; |     std::size_t i = 0; | ||||||
|     internal::copy(formatting.prefix, out); |     internal::copy(formatting.prefix, out); | ||||||
| @@ -255,54 +242,47 @@ public: | |||||||
|   } |   } | ||||||
| }; | }; | ||||||
|  |  | ||||||
| template <typename T> | template <typename T, typename Char> struct is_range { | ||||||
| struct is_range { |  | ||||||
|   static FMT_CONSTEXPR_DECL const bool value = |   static FMT_CONSTEXPR_DECL const bool value = | ||||||
|     internal::is_range_<T>::value && !internal::is_like_std_string<T>::value; |       internal::is_range_<T>::value && | ||||||
|  |       !internal::is_like_std_string<T>::value && | ||||||
|  |       !std::is_convertible<T, std::basic_string<Char>>::value; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| template <typename RangeT, typename Char> | template <typename RangeT, typename Char> | ||||||
| struct formatter<RangeT, Char, | struct formatter<RangeT, Char, | ||||||
|     typename std::enable_if<fmt::is_range<RangeT>::value>::type> { |                  enable_if_t<fmt::is_range<RangeT, Char>::value>> { | ||||||
|  |  | ||||||
|   formatting_range<Char> formatting; |   formatting_range<Char> formatting; | ||||||
|  |  | ||||||
|   template <typename ParseContext> |   template <typename ParseContext> | ||||||
|   FMT_CONSTEXPR auto parse(ParseContext &ctx) -> decltype(ctx.begin()) { |   FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { | ||||||
|     return formatting.parse(ctx); |     return formatting.parse(ctx); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   template <typename FormatContext> |   template <typename FormatContext> | ||||||
|   typename FormatContext::iterator format( |   typename FormatContext::iterator format(const RangeT& values, | ||||||
|       const RangeT &values, FormatContext &ctx) { |                                           FormatContext& ctx) { | ||||||
|     auto out = ctx.out(); |     auto out = internal::copy(formatting.prefix, ctx.out()); | ||||||
|     internal::copy(formatting.prefix, out); |  | ||||||
|     std::size_t i = 0; |     std::size_t i = 0; | ||||||
|     for (auto it = values.begin(), end = values.end(); it != end; ++it) { |     for (auto it = values.begin(), end = values.end(); it != end; ++it) { | ||||||
|       if (i > 0) { |       if (i > 0) { | ||||||
|         if (formatting.add_prepostfix_space) { |         if (formatting.add_prepostfix_space) *out++ = ' '; | ||||||
|           *out++ = ' '; |         out = internal::copy(formatting.delimiter, out); | ||||||
|         } |  | ||||||
|         internal::copy(formatting.delimiter, out); |  | ||||||
|       } |       } | ||||||
|       format_to(out, |       out = format_to(out, | ||||||
|                 internal::format_str_quoted( |                       internal::format_str_quoted( | ||||||
|                     (formatting.add_delimiter_spaces && i > 0), *it), |                           (formatting.add_delimiter_spaces && i > 0), *it), | ||||||
|                 *it); |                       *it); | ||||||
|       if (++i > formatting.range_length_limit) { |       if (++i > formatting.range_length_limit) { | ||||||
|         format_to(out, " ... <other elements>"); |         out = format_to(out, " ... <other elements>"); | ||||||
|         break; |         break; | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|     if (formatting.add_prepostfix_space) { |     if (formatting.add_prepostfix_space) *out++ = ' '; | ||||||
|       *out++ = ' '; |     return internal::copy(formatting.postfix, out); | ||||||
|     } |  | ||||||
|     internal::copy(formatting.postfix, out); |  | ||||||
|     return ctx.out(); |  | ||||||
|   } |   } | ||||||
| }; | }; | ||||||
|  |  | ||||||
| FMT_END_NAMESPACE | FMT_END_NAMESPACE | ||||||
|  |  | ||||||
| #endif // FMT_RANGES_H_ | #endif  // FMT_RANGES_H_ | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										293
									
								
								third_party/spdlog/include/spdlog/fmt/bundled/safe-duration-cast.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										293
									
								
								third_party/spdlog/include/spdlog/fmt/bundled/safe-duration-cast.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,293 @@ | |||||||
|  | /* | ||||||
|  |  * 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 | ||||||
							
								
								
									
										160
									
								
								third_party/spdlog/include/spdlog/fmt/bundled/time.h
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										160
									
								
								third_party/spdlog/include/spdlog/fmt/bundled/time.h
									
									
									
									
										vendored
									
									
								
							| @@ -1,160 +0,0 @@ | |||||||
| // Formatting library for C++ - time formatting |  | ||||||
| // |  | ||||||
| // Copyright (c) 2012 - present, Victor Zverovich |  | ||||||
| // All rights reserved. |  | ||||||
| // |  | ||||||
| // For the license information refer to format.h. |  | ||||||
|  |  | ||||||
| #ifndef FMT_TIME_H_ |  | ||||||
| #define FMT_TIME_H_ |  | ||||||
|  |  | ||||||
| #include "format.h" |  | ||||||
| #include <ctime> |  | ||||||
| #include <locale> |  | ||||||
|  |  | ||||||
| FMT_BEGIN_NAMESPACE |  | ||||||
|  |  | ||||||
| // Prevents expansion of a preceding token as a function-style macro. |  | ||||||
| // Usage: f FMT_NOMACRO() |  | ||||||
| #define FMT_NOMACRO |  | ||||||
|  |  | ||||||
| namespace internal{ |  | ||||||
| inline null<> localtime_r FMT_NOMACRO(...) { return null<>(); } |  | ||||||
| inline null<> localtime_s(...) { return null<>(); } |  | ||||||
| inline null<> gmtime_r(...) { return null<>(); } |  | ||||||
| inline null<> gmtime_s(...) { return null<>(); } |  | ||||||
| }  // namespace internal |  | ||||||
|  |  | ||||||
| // Thread-safe replacement for std::localtime |  | ||||||
| inline std::tm localtime(std::time_t time) { |  | ||||||
|   struct dispatcher { |  | ||||||
|     std::time_t time_; |  | ||||||
|     std::tm tm_; |  | ||||||
|  |  | ||||||
|     dispatcher(std::time_t t): time_(t) {} |  | ||||||
|  |  | ||||||
|     bool run() { |  | ||||||
|       using namespace fmt::internal; |  | ||||||
|       return handle(localtime_r(&time_, &tm_)); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     bool handle(std::tm *tm) { return tm != FMT_NULL; } |  | ||||||
|  |  | ||||||
|     bool handle(internal::null<>) { |  | ||||||
|       using namespace fmt::internal; |  | ||||||
|       return fallback(localtime_s(&tm_, &time_)); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     bool fallback(int res) { return res == 0; } |  | ||||||
|  |  | ||||||
| #if !FMT_MSC_VER |  | ||||||
|     bool fallback(internal::null<>) { |  | ||||||
|       using namespace fmt::internal; |  | ||||||
|       std::tm *tm = std::localtime(&time_); |  | ||||||
|       if (tm) tm_ = *tm; |  | ||||||
|       return tm != FMT_NULL; |  | ||||||
|     } |  | ||||||
| #endif |  | ||||||
|   }; |  | ||||||
|   dispatcher lt(time); |  | ||||||
|   // Too big time values may be unsupported. |  | ||||||
|   if (!lt.run()) |  | ||||||
|     FMT_THROW(format_error("time_t value out of range")); |  | ||||||
|   return lt.tm_; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // Thread-safe replacement for std::gmtime |  | ||||||
| inline std::tm gmtime(std::time_t time) { |  | ||||||
|   struct dispatcher { |  | ||||||
|     std::time_t time_; |  | ||||||
|     std::tm tm_; |  | ||||||
|  |  | ||||||
|     dispatcher(std::time_t t): time_(t) {} |  | ||||||
|  |  | ||||||
|     bool run() { |  | ||||||
|       using namespace fmt::internal; |  | ||||||
|       return handle(gmtime_r(&time_, &tm_)); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     bool handle(std::tm *tm) { return tm != FMT_NULL; } |  | ||||||
|  |  | ||||||
|     bool handle(internal::null<>) { |  | ||||||
|       using namespace fmt::internal; |  | ||||||
|       return fallback(gmtime_s(&tm_, &time_)); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     bool fallback(int res) { return res == 0; } |  | ||||||
|  |  | ||||||
| #if !FMT_MSC_VER |  | ||||||
|     bool fallback(internal::null<>) { |  | ||||||
|       std::tm *tm = std::gmtime(&time_); |  | ||||||
|       if (tm) tm_ = *tm; |  | ||||||
|       return tm != FMT_NULL; |  | ||||||
|     } |  | ||||||
| #endif |  | ||||||
|   }; |  | ||||||
|   dispatcher gt(time); |  | ||||||
|   // Too big time values may be unsupported. |  | ||||||
|   if (!gt.run()) |  | ||||||
|     FMT_THROW(format_error("time_t value out of range")); |  | ||||||
|   return gt.tm_; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| namespace internal { |  | ||||||
| inline std::size_t strftime(char *str, std::size_t count, const char *format, |  | ||||||
|                             const std::tm *time) { |  | ||||||
|   return std::strftime(str, count, format, time); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| inline std::size_t strftime(wchar_t *str, std::size_t count, |  | ||||||
|                             const wchar_t *format, const std::tm *time) { |  | ||||||
|   return std::wcsftime(str, count, format, time); |  | ||||||
| } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| template <typename Char> |  | ||||||
| struct formatter<std::tm, Char> { |  | ||||||
|   template <typename ParseContext> |  | ||||||
|   auto parse(ParseContext &ctx) -> decltype(ctx.begin()) { |  | ||||||
|     auto it = ctx.begin(); |  | ||||||
|     if (it != ctx.end() && *it == ':') |  | ||||||
|       ++it; |  | ||||||
|     auto end = it; |  | ||||||
|     while (end != ctx.end() && *end != '}') |  | ||||||
|       ++end; |  | ||||||
|     tm_format.reserve(internal::to_unsigned(end - it + 1)); |  | ||||||
|     tm_format.append(it, end); |  | ||||||
|     tm_format.push_back('\0'); |  | ||||||
|     return end; |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   template <typename FormatContext> |  | ||||||
|   auto format(const std::tm &tm, FormatContext &ctx) -> decltype(ctx.out()) { |  | ||||||
|     basic_memory_buffer<Char> buf; |  | ||||||
|     std::size_t start = buf.size(); |  | ||||||
|     for (;;) { |  | ||||||
|       std::size_t size = buf.capacity() - start; |  | ||||||
|       std::size_t count = |  | ||||||
|         internal::strftime(&buf[start], size, &tm_format[0], &tm); |  | ||||||
|       if (count != 0) { |  | ||||||
|         buf.resize(start + count); |  | ||||||
|         break; |  | ||||||
|       } |  | ||||||
|       if (size >= tm_format.size() * 256) { |  | ||||||
|         // If the buffer is 256 times larger than the format string, assume |  | ||||||
|         // that `strftime` gives an empty result. There doesn't seem to be a |  | ||||||
|         // better way to distinguish the two cases: |  | ||||||
|         // https://github.com/fmtlib/fmt/issues/367 |  | ||||||
|         break; |  | ||||||
|       } |  | ||||||
|       const std::size_t MIN_GROWTH = 10; |  | ||||||
|       buf.reserve(buf.capacity() + (size > MIN_GROWTH ? size : MIN_GROWTH)); |  | ||||||
|     } |  | ||||||
|     return std::copy(buf.begin(), buf.end(), ctx.out()); |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   basic_memory_buffer<Char> tm_format; |  | ||||||
| }; |  | ||||||
| FMT_END_NAMESPACE |  | ||||||
|  |  | ||||||
| #endif  // FMT_TIME_H_ |  | ||||||
							
								
								
									
										8
									
								
								third_party/spdlog/include/spdlog/fmt/fmt.h
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										8
									
								
								third_party/spdlog/include/spdlog/fmt/fmt.h
									
									
									
									
										vendored
									
									
								
							| @@ -11,15 +11,17 @@ | |||||||
| // | // | ||||||
|  |  | ||||||
| #if !defined(SPDLOG_FMT_EXTERNAL) | #if !defined(SPDLOG_FMT_EXTERNAL) | ||||||
|  | #ifdef SPDLOG_HEADER_ONLY | ||||||
| #ifndef FMT_HEADER_ONLY | #ifndef FMT_HEADER_ONLY | ||||||
| #define FMT_HEADER_ONLY | #define FMT_HEADER_ONLY | ||||||
| #endif | #endif | ||||||
|  | #endif | ||||||
| #ifndef FMT_USE_WINDOWS_H | #ifndef FMT_USE_WINDOWS_H | ||||||
| #define FMT_USE_WINDOWS_H 0 | #define FMT_USE_WINDOWS_H 0 | ||||||
| #endif | #endif | ||||||
| #include "bundled/core.h" | #include "bundled/core.h" | ||||||
| #include "bundled/format.h" | #include "bundled/format.h" | ||||||
| #else // 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 | #endif | ||||||
|   | |||||||
| @@ -1,7 +1,5 @@ | |||||||
| // | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. | ||||||
| // Copyright(c) 2015 Gabi Melman. |  | ||||||
| // Distributed under the MIT License (http://opensource.org/licenses/MIT) | // Distributed under the MIT License (http://opensource.org/licenses/MIT) | ||||||
| // |  | ||||||
|  |  | ||||||
| #pragma once | #pragma once | ||||||
|  |  | ||||||
| @@ -14,7 +12,7 @@ class formatter | |||||||
| { | { | ||||||
| public: | public: | ||||||
|     virtual ~formatter() = default; |     virtual ~formatter() = default; | ||||||
|     virtual void format(const details::log_msg &msg, fmt::memory_buffer &dest) = 0; |     virtual void format(const details::log_msg &msg, memory_buf_t &dest) = 0; | ||||||
|     virtual std::unique_ptr<formatter> clone() const = 0; |     virtual std::unique_ptr<formatter> clone() const = 0; | ||||||
| }; | }; | ||||||
| } // namespace spdlog | } // namespace spdlog | ||||||
|   | |||||||
							
								
								
									
										246
									
								
								third_party/spdlog/include/spdlog/logger-inl.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										246
									
								
								third_party/spdlog/include/spdlog/logger-inl.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,246 @@ | |||||||
|  | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. | ||||||
|  | // Distributed under the MIT License (http://opensource.org/licenses/MIT) | ||||||
|  |  | ||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #ifndef SPDLOG_HEADER_ONLY | ||||||
|  | #include "spdlog/logger.h" | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #include "spdlog/sinks/sink.h" | ||||||
|  | #include "spdlog/details/backtracer.h" | ||||||
|  | #include "spdlog/details/pattern_formatter.h" | ||||||
|  |  | ||||||
|  | #include <cstdio> | ||||||
|  |  | ||||||
|  | namespace spdlog { | ||||||
|  |  | ||||||
|  | // public methods | ||||||
|  | SPDLOG_INLINE logger::logger(const logger &other) | ||||||
|  |     : name_(other.name_) | ||||||
|  |     , sinks_(other.sinks_) | ||||||
|  |     , level_(other.level_.load(std::memory_order_relaxed)) | ||||||
|  |     , flush_level_(other.flush_level_.load(std::memory_order_relaxed)) | ||||||
|  |     , custom_err_handler_(other.custom_err_handler_) | ||||||
|  |     , tracer_(other.tracer_) | ||||||
|  | {} | ||||||
|  |  | ||||||
|  | SPDLOG_INLINE logger::logger(logger &&other) SPDLOG_NOEXCEPT : name_(std::move(other.name_)), | ||||||
|  |                                                                sinks_(std::move(other.sinks_)), | ||||||
|  |                                                                level_(other.level_.load(std::memory_order_relaxed)), | ||||||
|  |                                                                flush_level_(other.flush_level_.load(std::memory_order_relaxed)), | ||||||
|  |                                                                custom_err_handler_(std::move(other.custom_err_handler_)), | ||||||
|  |                                                                tracer_(std::move(other.tracer_)) | ||||||
|  |  | ||||||
|  | {} | ||||||
|  |  | ||||||
|  | SPDLOG_INLINE logger &logger::operator=(logger other) SPDLOG_NOEXCEPT | ||||||
|  | { | ||||||
|  |     this->swap(other); | ||||||
|  |     return *this; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | SPDLOG_INLINE void logger::swap(spdlog::logger &other) SPDLOG_NOEXCEPT | ||||||
|  | { | ||||||
|  |     name_.swap(other.name_); | ||||||
|  |     sinks_.swap(other.sinks_); | ||||||
|  |  | ||||||
|  |     // swap level_ | ||||||
|  |     auto other_level = other.level_.load(); | ||||||
|  |     auto my_level = level_.exchange(other_level); | ||||||
|  |     other.level_.store(my_level); | ||||||
|  |  | ||||||
|  |     // swap flush level_ | ||||||
|  |     other_level = other.flush_level_.load(); | ||||||
|  |     my_level = flush_level_.exchange(other_level); | ||||||
|  |     other.flush_level_.store(my_level); | ||||||
|  |  | ||||||
|  |     custom_err_handler_.swap(other.custom_err_handler_); | ||||||
|  |     std::swap(tracer_, other.tracer_); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | SPDLOG_INLINE void swap(logger &a, logger &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) | ||||||
|  | { | ||||||
|  |     level_.store(log_level); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | SPDLOG_INLINE level::level_enum logger::level() const | ||||||
|  | { | ||||||
|  |     return static_cast<level::level_enum>(level_.load(std::memory_order_relaxed)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | SPDLOG_INLINE const std::string &logger::name() const | ||||||
|  | { | ||||||
|  |     return name_; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // set formatting for the sinks in this logger. | ||||||
|  | // each sink will get a seperate instance of the formatter object. | ||||||
|  | SPDLOG_INLINE void logger::set_formatter(std::unique_ptr<formatter> f) | ||||||
|  | { | ||||||
|  |     for (auto it = sinks_.begin(); it != sinks_.end(); ++it) | ||||||
|  |     { | ||||||
|  |         if (std::next(it) == sinks_.end()) | ||||||
|  |         { | ||||||
|  |             // last element - we can be move it. | ||||||
|  |             (*it)->set_formatter(std::move(f)); | ||||||
|  |         } | ||||||
|  |         else | ||||||
|  |         { | ||||||
|  |             (*it)->set_formatter(f->clone()); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | SPDLOG_INLINE void logger::set_pattern(std::string pattern, pattern_time_type time_type) | ||||||
|  | { | ||||||
|  |     auto new_formatter = details::make_unique<pattern_formatter>(std::move(pattern), time_type); | ||||||
|  |     set_formatter(std::move(new_formatter)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // create new backtrace sink and move to it all our child sinks | ||||||
|  | SPDLOG_INLINE void logger::enable_backtrace(size_t n_messages) | ||||||
|  | { | ||||||
|  |     tracer_.enable(n_messages); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // restore orig sinks and level and delete the backtrace sink | ||||||
|  | SPDLOG_INLINE void logger::disable_backtrace() | ||||||
|  | { | ||||||
|  |     tracer_.disable(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | SPDLOG_INLINE void logger::dump_backtrace() | ||||||
|  | { | ||||||
|  |     dump_backtrace_(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // flush functions | ||||||
|  | SPDLOG_INLINE void logger::flush() | ||||||
|  | { | ||||||
|  |     flush_(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | SPDLOG_INLINE void logger::flush_on(level::level_enum log_level) | ||||||
|  | { | ||||||
|  |     flush_level_.store(log_level); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | SPDLOG_INLINE level::level_enum logger::flush_level() const | ||||||
|  | { | ||||||
|  |     return static_cast<level::level_enum>(flush_level_.load(std::memory_order_relaxed)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // sinks | ||||||
|  | SPDLOG_INLINE const std::vector<sink_ptr> &logger::sinks() const | ||||||
|  | { | ||||||
|  |     return sinks_; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | SPDLOG_INLINE std::vector<sink_ptr> &logger::sinks() | ||||||
|  | { | ||||||
|  |     return sinks_; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // error handler | ||||||
|  | SPDLOG_INLINE void logger::set_error_handler(err_handler handler) | ||||||
|  | { | ||||||
|  |     custom_err_handler_ = handler; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // create new logger with same sinks and configuration. | ||||||
|  | SPDLOG_INLINE std::shared_ptr<logger> logger::clone(std::string logger_name) | ||||||
|  | { | ||||||
|  |     auto cloned = std::make_shared<logger>(*this); | ||||||
|  |     cloned->name_ = std::move(logger_name); | ||||||
|  |     return cloned; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // protected methods | ||||||
|  | SPDLOG_INLINE void logger::sink_it_(const details::log_msg &msg) | ||||||
|  | { | ||||||
|  |     for (auto &sink : sinks_) | ||||||
|  |     { | ||||||
|  |         if (sink->should_log(msg.level)) | ||||||
|  |         { | ||||||
|  |             SPDLOG_TRY | ||||||
|  |             { | ||||||
|  |                 sink->log(msg); | ||||||
|  |             } | ||||||
|  |             SPDLOG_LOGGER_CATCH() | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (should_flush_(msg)) | ||||||
|  |     { | ||||||
|  |         flush_(); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | SPDLOG_INLINE void logger::flush_() | ||||||
|  | { | ||||||
|  |     for (auto &sink : sinks_) | ||||||
|  |     { | ||||||
|  |         SPDLOG_TRY | ||||||
|  |         { | ||||||
|  |             sink->flush(); | ||||||
|  |         } | ||||||
|  |         SPDLOG_LOGGER_CATCH() | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | SPDLOG_INLINE void logger::dump_backtrace_() | ||||||
|  | { | ||||||
|  |     using details::log_msg; | ||||||
|  |     if (tracer_) | ||||||
|  |     { | ||||||
|  |         sink_it_(log_msg{name(), level::info, "****************** Backtrace Start ******************"}); | ||||||
|  |         tracer_.foreach_pop([this](const details::log_msg &msg) { this->sink_it_(msg); }); | ||||||
|  |         sink_it_(log_msg{name(), level::info, "****************** Backtrace End ********************"}); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | SPDLOG_INLINE bool logger::should_flush_(const details::log_msg &msg) | ||||||
|  | { | ||||||
|  |     auto flush_level = flush_level_.load(std::memory_order_relaxed); | ||||||
|  |     return (msg.level >= flush_level) && (msg.level != level::off); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | SPDLOG_INLINE void logger::err_handler_(const std::string &msg) | ||||||
|  | { | ||||||
|  |  | ||||||
|  |     if (custom_err_handler_) | ||||||
|  |     { | ||||||
|  |         custom_err_handler_(msg); | ||||||
|  |     } | ||||||
|  |     else | ||||||
|  |     { | ||||||
|  |         using std::chrono::system_clock; | ||||||
|  |         static std::mutex mutex; | ||||||
|  |         static std::chrono::system_clock::time_point last_report_time; | ||||||
|  |         static size_t err_counter = 0; | ||||||
|  |         std::lock_guard<std::mutex> lk{mutex}; | ||||||
|  |         auto now = system_clock::now(); | ||||||
|  |         err_counter++; | ||||||
|  |         if (now - last_report_time < std::chrono::seconds(1)) | ||||||
|  |         { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |         last_report_time = now; | ||||||
|  |         auto tm_time = details::os::localtime(system_clock::to_time_t(now)); | ||||||
|  |         char date_buf[64]; | ||||||
|  |         std::strftime(date_buf, sizeof(date_buf), "%Y-%m-%d %H:%M:%S", &tm_time); | ||||||
|  |         fprintf(stderr, "[*** LOG ERROR #%04zu ***] [%s] [%s] {%s}\n", err_counter, date_buf, name().c_str(), msg.c_str()); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | } // namespace spdlog | ||||||
							
								
								
									
										377
									
								
								third_party/spdlog/include/spdlog/logger.h
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										377
									
								
								third_party/spdlog/include/spdlog/logger.h
									
									
									
									
										vendored
									
									
								
							| @@ -1,7 +1,5 @@ | |||||||
| // | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. | ||||||
| // Copyright(c) 2015-2108 Gabi Melman. |  | ||||||
| // Distributed under the MIT License (http://opensource.org/licenses/MIT) | // Distributed under the MIT License (http://opensource.org/licenses/MIT) | ||||||
| // |  | ||||||
|  |  | ||||||
| #pragma once | #pragma once | ||||||
|  |  | ||||||
| @@ -15,137 +13,333 @@ | |||||||
| // and send to its destination. | // and send to its destination. | ||||||
| // | // | ||||||
| // 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, | // formatted data, and support for different format per sink. | ||||||
| // and support customize format per each sink. |  | ||||||
|  |  | ||||||
| #include "spdlog/common.h" | #include "spdlog/common.h" | ||||||
| #include "spdlog/formatter.h" | #include "spdlog/details/log_msg.h" | ||||||
| #include "spdlog/sinks/sink.h" | #include "spdlog/details/backtracer.h" | ||||||
|  |  | ||||||
|  | #ifdef SPDLOG_WCHAR_TO_UTF8_SUPPORT | ||||||
|  | #include "spdlog/details/os.h" | ||||||
|  | #endif | ||||||
|  |  | ||||||
| #include <memory> |  | ||||||
| #include <string> |  | ||||||
| #include <vector> | #include <vector> | ||||||
|  | #ifndef SPDLOG_NO_EXCEPTIONS | ||||||
|  | #define SPDLOG_LOGGER_CATCH()                                                                                                              \ | ||||||
|  |     catch (const std::exception &ex)                                                                                                       \ | ||||||
|  |     {                                                                                                                                      \ | ||||||
|  |         err_handler_(ex.what());                                                                                                           \ | ||||||
|  |     }                                                                                                                                      \ | ||||||
|  |     catch (...)                                                                                                                            \ | ||||||
|  |     {                                                                                                                                      \ | ||||||
|  |         err_handler_("Unknown exception in logger");                                                                                       \ | ||||||
|  |     } | ||||||
|  | #else | ||||||
|  | #define SPDLOG_LOGGER_CATCH() | ||||||
|  | #endif | ||||||
|  |  | ||||||
| namespace spdlog { | namespace spdlog { | ||||||
|  |  | ||||||
| class logger | class logger | ||||||
| { | { | ||||||
| public: | public: | ||||||
|     logger(std::string name, sink_ptr single_sink); |     // Empty logger | ||||||
|     logger(std::string name, sinks_init_list sinks); |     explicit logger(std::string name) | ||||||
|  |         : name_(std::move(name)) | ||||||
|  |         , sinks_() | ||||||
|  |     {} | ||||||
|  |  | ||||||
|  |     // Logger with range on sinks | ||||||
|     template<typename It> |     template<typename It> | ||||||
|     logger(std::string name, It begin, It end); |     logger(std::string name, It begin, It end) | ||||||
|  |         : name_(std::move(name)) | ||||||
|  |         , sinks_(begin, end) | ||||||
|  |     {} | ||||||
|  |  | ||||||
|     virtual ~logger(); |     // Logger with single sink | ||||||
|  |     logger(std::string name, sink_ptr single_sink) | ||||||
|  |         : logger(std::move(name), {std::move(single_sink)}) | ||||||
|  |     {} | ||||||
|  |  | ||||||
|     logger(const logger &) = delete; |     // Logger with sinks init list | ||||||
|     logger &operator=(const logger &) = delete; |     logger(std::string name, sinks_init_list sinks) | ||||||
|  |         : logger(std::move(name), sinks.begin(), sinks.end()) | ||||||
|  |     {} | ||||||
|  |  | ||||||
|  |     virtual ~logger() = default; | ||||||
|  |  | ||||||
|  |     logger(const logger &other); | ||||||
|  |     logger(logger &&other) SPDLOG_NOEXCEPT; | ||||||
|  |     logger &operator=(logger other) SPDLOG_NOEXCEPT; | ||||||
|  |  | ||||||
|  |     void swap(spdlog::logger &other) SPDLOG_NOEXCEPT; | ||||||
|  |  | ||||||
|     template<typename... Args> |     template<typename... Args> | ||||||
|     void log(level::level_enum lvl, const char *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); | ||||||
|  |         if (!level_enabled && !tracer_) | ||||||
|  |         { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |         SPDLOG_TRY | ||||||
|  |         { | ||||||
|  |             memory_buf_t buf; | ||||||
|  |             fmt::format_to(buf, fmt, args...); | ||||||
|  |             details::log_msg log_msg(loc, name_, lvl, string_view_t(buf.data(), buf.size())); | ||||||
|  |             if (level_enabled) | ||||||
|  |             { | ||||||
|  |                 sink_it_(log_msg); | ||||||
|  |             } | ||||||
|  |             if (tracer_) | ||||||
|  |             { | ||||||
|  |                 tracer_.push_back(log_msg); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         SPDLOG_LOGGER_CATCH() | ||||||
|  |     } | ||||||
|  |  | ||||||
|     template<typename... Args> |     template<typename... Args> | ||||||
|     void log(source_loc loc, level::level_enum lvl, const char *fmt, const Args &... args); |     void log(level::level_enum lvl, string_view_t fmt, const Args &... args) | ||||||
|  |     { | ||||||
|     void log(level::level_enum lvl, const char *msg); |         log(source_loc{}, lvl, fmt, args...); | ||||||
|  |     } | ||||||
|     void log(source_loc loc, level::level_enum lvl, const char *msg); |  | ||||||
|  |  | ||||||
|     template<typename... Args> |     template<typename... Args> | ||||||
|     void trace(const char *fmt, const Args &... args); |     void trace(string_view_t fmt, const Args &... args) | ||||||
|  |     { | ||||||
|  |         log(level::trace, fmt, args...); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     template<typename... Args> |     template<typename... Args> | ||||||
|     void debug(const char *fmt, const Args &... args); |     void debug(string_view_t fmt, const Args &... args) | ||||||
|  |     { | ||||||
|  |         log(level::debug, fmt, args...); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     template<typename... Args> |     template<typename... Args> | ||||||
|     void info(const char *fmt, const Args &... args); |     void info(string_view_t fmt, const Args &... args) | ||||||
|  |     { | ||||||
|  |         log(level::info, fmt, args...); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     template<typename... Args> |     template<typename... Args> | ||||||
|     void warn(const char *fmt, const Args &... args); |     void warn(string_view_t fmt, const Args &... args) | ||||||
|  |     { | ||||||
|  |         log(level::warn, fmt, args...); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     template<typename... Args> |     template<typename... Args> | ||||||
|     void error(const char *fmt, const Args &... args); |     void error(string_view_t fmt, const Args &... args) | ||||||
|  |     { | ||||||
|  |         log(level::err, fmt, args...); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     template<typename... Args> |     template<typename... Args> | ||||||
|     void critical(const char *fmt, const Args &... args); |     void critical(string_view_t fmt, const Args &... args) | ||||||
|  |     { | ||||||
|  |         log(level::critical, fmt, args...); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     template<typename T> | ||||||
|  |     void log(level::level_enum lvl, const T &msg) | ||||||
|  |     { | ||||||
|  |         log(source_loc{}, lvl, msg); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // T can be statically converted to string_view | ||||||
|  |     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) | ||||||
|  |     { | ||||||
|  |         auto level_enabled = should_log(lvl); | ||||||
|  |         if (!level_enabled && !tracer_) | ||||||
|  |         { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |         SPDLOG_TRY | ||||||
|  |         { | ||||||
|  |             details::log_msg log_msg(loc, name_, lvl, msg); | ||||||
|  |             if (level_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) | ||||||
|  |     { | ||||||
|  |         log(source_loc{}, lvl, msg); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // T cannot be statically converted to string_view or wstring_view | ||||||
|  |     template<class T, typename std::enable_if<!std::is_convertible<const T &, spdlog::string_view_t>::value && | ||||||
|  |                                                   !is_convertible_to_wstring_view<const T &>::value, | ||||||
|  |                           T>::type * = nullptr> | ||||||
|  |     void log(source_loc loc, level::level_enum lvl, const T &msg) | ||||||
|  |     { | ||||||
|  |         log(loc, lvl, "{}", msg); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     template<typename T> | ||||||
|  |     void trace(const T &msg) | ||||||
|  |     { | ||||||
|  |         log(level::trace, msg); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     template<typename T> | ||||||
|  |     void debug(const T &msg) | ||||||
|  |     { | ||||||
|  |         log(level::debug, msg); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     template<typename T> | ||||||
|  |     void info(const T &msg) | ||||||
|  |     { | ||||||
|  |         log(level::info, msg); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     template<typename T> | ||||||
|  |     void warn(const T &msg) | ||||||
|  |     { | ||||||
|  |         log(level::warn, msg); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     template<typename T> | ||||||
|  |     void error(const T &msg) | ||||||
|  |     { | ||||||
|  |         log(level::err, msg); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     template<typename T> | ||||||
|  |     void critical(const T &msg) | ||||||
|  |     { | ||||||
|  |         log(level::critical, msg); | ||||||
|  |     } | ||||||
|  |  | ||||||
| #ifdef SPDLOG_WCHAR_TO_UTF8_SUPPORT | #ifdef SPDLOG_WCHAR_TO_UTF8_SUPPORT | ||||||
| #ifndef _WIN32 | #ifndef _WIN32 | ||||||
| #error SPDLOG_WCHAR_TO_UTF8_SUPPORT only supported on windows | #error SPDLOG_WCHAR_TO_UTF8_SUPPORT only supported on windows | ||||||
| #else | #else | ||||||
|     template<typename... Args> |  | ||||||
|     void log(level::level_enum lvl, const wchar_t *fmt, const Args &... args); |  | ||||||
|  |  | ||||||
|     template<typename... Args> |     template<typename... Args> | ||||||
|     void log(source_loc source, level::level_enum lvl, const wchar_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); | ||||||
|  |         if (!level_enabled && !tracer_) | ||||||
|  |         { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |         SPDLOG_TRY | ||||||
|  |         { | ||||||
|  |             // format to wmemory_buffer and convert to utf8 | ||||||
|  |             fmt::wmemory_buffer wbuf; | ||||||
|  |             fmt::format_to(wbuf, fmt, args...); | ||||||
|  |  | ||||||
|  |             memory_buf_t 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())); | ||||||
|  |  | ||||||
|  |             if (level_enabled) | ||||||
|  |             { | ||||||
|  |                 sink_it_(log_msg); | ||||||
|  |             } | ||||||
|  |             if (tracer_) | ||||||
|  |             { | ||||||
|  |                 tracer_.push_back(log_msg); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         SPDLOG_LOGGER_CATCH() | ||||||
|  |     } | ||||||
|  |  | ||||||
|     template<typename... Args> |     template<typename... Args> | ||||||
|     void trace(const wchar_t *fmt, const Args &... args); |     void log(level::level_enum lvl, wstring_view_t fmt, const Args &... args) | ||||||
|  |     { | ||||||
|  |         log(source_loc{}, lvl, fmt, args...); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     template<typename... Args> |     template<typename... Args> | ||||||
|     void debug(const wchar_t *fmt, const Args &... args); |     void trace(wstring_view_t fmt, const Args &... args) | ||||||
|  |     { | ||||||
|  |         log(level::trace, fmt, args...); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     template<typename... Args> |     template<typename... Args> | ||||||
|     void info(const wchar_t *fmt, const Args &... args); |     void debug(wstring_view_t fmt, const Args &... args) | ||||||
|  |     { | ||||||
|  |         log(level::debug, fmt, args...); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     template<typename... Args> |     template<typename... Args> | ||||||
|     void warn(const wchar_t *fmt, const Args &... args); |     void info(wstring_view_t fmt, const Args &... args) | ||||||
|  |     { | ||||||
|  |         log(level::info, fmt, args...); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     template<typename... Args> |     template<typename... Args> | ||||||
|     void error(const wchar_t *fmt, const Args &... args); |     void warn(wstring_view_t fmt, const Args &... args) | ||||||
|  |     { | ||||||
|  |         log(level::warn, fmt, args...); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     template<typename... Args> |     template<typename... Args> | ||||||
|     void critical(const wchar_t *fmt, const Args &... args); |     void error(wstring_view_t fmt, const Args &... args) | ||||||
|  |     { | ||||||
|  |         log(level::err, fmt, args...); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     template<typename... Args> | ||||||
|  |     void critical(wstring_view_t fmt, const Args &... args) | ||||||
|  |     { | ||||||
|  |         log(level::critical, fmt, args...); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // T can be statically converted to wstring_view | ||||||
|  |     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) | ||||||
|  |     { | ||||||
|  |         if (!should_log(lvl)) | ||||||
|  |         { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         try | ||||||
|  |         { | ||||||
|  |             memory_buf_t buf; | ||||||
|  |             details::os::wstr_to_utf8buf(msg, buf); | ||||||
|  |  | ||||||
|  |             details::log_msg log_msg(loc, name_, lvl, string_view_t(buf.data(), buf.size())); | ||||||
|  |             sink_it_(log_msg); | ||||||
|  |         } | ||||||
|  |         SPDLOG_LOGGER_CATCH() | ||||||
|  |     } | ||||||
| #endif // _WIN32 | #endif // _WIN32 | ||||||
| #endif // SPDLOG_WCHAR_TO_UTF8_SUPPORT | #endif // SPDLOG_WCHAR_TO_UTF8_SUPPORT | ||||||
|  |  | ||||||
|     // T can be statically converted to string_view |  | ||||||
|     template<class T, typename std::enable_if<std::is_convertible<T, spdlog::string_view_t>::value, T>::type * = nullptr> |  | ||||||
|     void log(level::level_enum lvl, const T &); |  | ||||||
|  |  | ||||||
|     // T can be statically converted to string_view |  | ||||||
|     template<class T, typename std::enable_if<std::is_convertible<T, spdlog::string_view_t>::value, T>::type * = nullptr> |  | ||||||
|     void log(source_loc loc, level::level_enum lvl, const T &); |  | ||||||
|  |  | ||||||
|     // T cannot be statically converted to string_view |  | ||||||
|     template<class T, typename std::enable_if<!std::is_convertible<T, spdlog::string_view_t>::value, T>::type * = nullptr> |  | ||||||
|     void log(level::level_enum lvl, const T &); |  | ||||||
|  |  | ||||||
|     // T cannot be statically converted to string_view |  | ||||||
|     template<class T, typename std::enable_if<!std::is_convertible<T, spdlog::string_view_t>::value, T>::type * = nullptr> |  | ||||||
|     void log(source_loc loc, level::level_enum lvl, const T &); |  | ||||||
|  |  | ||||||
|     template<typename T> |  | ||||||
|     void trace(const T &msg); |  | ||||||
|  |  | ||||||
|     template<typename T> |  | ||||||
|     void debug(const T &msg); |  | ||||||
|  |  | ||||||
|     template<typename T> |  | ||||||
|     void info(const T &msg); |  | ||||||
|  |  | ||||||
|     template<typename T> |  | ||||||
|     void warn(const T &msg); |  | ||||||
|  |  | ||||||
|     template<typename T> |  | ||||||
|     void error(const T &msg); |  | ||||||
|  |  | ||||||
|     template<typename T> |  | ||||||
|     void critical(const T &msg); |  | ||||||
|  |  | ||||||
|     bool should_log(level::level_enum msg_level) const; |     bool should_log(level::level_enum msg_level) const; | ||||||
|  |  | ||||||
|     void set_level(level::level_enum log_level); |     void set_level(level::level_enum log_level); | ||||||
|  |  | ||||||
|     static level::level_enum default_level(); |  | ||||||
|     level::level_enum level() const; |     level::level_enum level() const; | ||||||
|  |  | ||||||
|     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 seperate instance of the formatter object. | ||||||
|     void set_formatter(std::unique_ptr<formatter> formatter); |     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); | ||||||
|  |  | ||||||
|  |     // backtrace support. | ||||||
|  |     // efficiently store all debug/trace messages in a circular buffer until needed for debugging. | ||||||
|  |     void enable_backtrace(size_t n_messages); | ||||||
|  |     void disable_backtrace(); | ||||||
|  |     void dump_backtrace(); | ||||||
|  |  | ||||||
|     // flush functions |     // flush functions | ||||||
|     void flush(); |     void flush(); | ||||||
|     void flush_on(level::level_enum log_level); |     void flush_on(level::level_enum log_level); | ||||||
| @@ -153,36 +347,37 @@ public: | |||||||
|  |  | ||||||
|     // sinks |     // sinks | ||||||
|     const std::vector<sink_ptr> &sinks() const; |     const std::vector<sink_ptr> &sinks() const; | ||||||
|  |  | ||||||
|     std::vector<sink_ptr> &sinks(); |     std::vector<sink_ptr> &sinks(); | ||||||
|  |  | ||||||
|     // error handler |     // error handler | ||||||
|     void set_error_handler(log_err_handler err_handler); |     void set_error_handler(err_handler); | ||||||
|     log_err_handler error_handler() const; |  | ||||||
|  |  | ||||||
|     // create new logger with same sinks and configuration. |     // create new logger with same sinks and configuration. | ||||||
|     virtual std::shared_ptr<logger> clone(std::string logger_name); |     virtual std::shared_ptr<logger> clone(std::string logger_name); | ||||||
|  |  | ||||||
| protected: | protected: | ||||||
|     virtual void sink_it_(details::log_msg &msg); |     std::string name_; | ||||||
|     virtual void flush_(); |     std::vector<sink_ptr> sinks_; | ||||||
|  |     spdlog::level_t level_{level::info}; | ||||||
|  |     spdlog::level_t flush_level_{level::off}; | ||||||
|  |     err_handler custom_err_handler_{nullptr}; | ||||||
|  |     details::backtracer tracer_; | ||||||
|  |  | ||||||
|  |     virtual void sink_it_(const details::log_msg &msg); | ||||||
|  |     virtual void flush_(); | ||||||
|  |     void dump_backtrace_(); | ||||||
|     bool should_flush_(const details::log_msg &msg); |     bool should_flush_(const details::log_msg &msg); | ||||||
|  |  | ||||||
|     // default error handler. |     // handle errors during logging. | ||||||
|     // print the error to stderr with the max rate of 1 message/minute. |     // default handler prints the error to stderr at max rate of 1 message/sec. | ||||||
|     void default_err_handler_(const std::string &msg); |     void err_handler_(const std::string &msg); | ||||||
|  |  | ||||||
|     // increment the message count (only if defined(SPDLOG_ENABLE_MESSAGE_COUNTER)) |  | ||||||
|     void incr_msg_counter_(details::log_msg &msg); |  | ||||||
|  |  | ||||||
|     const std::string name_; |  | ||||||
|     std::vector<sink_ptr> sinks_; |  | ||||||
|     spdlog::level_t level_{spdlog::logger::default_level()}; |  | ||||||
|     spdlog::level_t flush_level_{level::off}; |  | ||||||
|     log_err_handler err_handler_{[this](const std::string &msg) { this->default_err_handler_(msg); }}; |  | ||||||
|     std::atomic<time_t> last_err_time_{0}; |  | ||||||
|     std::atomic<size_t> msg_counter_{1}; |  | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | void swap(logger &a, logger &b); | ||||||
|  |  | ||||||
| } // namespace spdlog | } // namespace spdlog | ||||||
|  |  | ||||||
| #include "details/logger_impl.h" | #ifdef SPDLOG_HEADER_ONLY | ||||||
|  | #include "logger-inl.h" | ||||||
|  | #endif | ||||||
|   | |||||||
| @@ -1,18 +1,15 @@ | |||||||
| // | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. | ||||||
| // Copyright(c) 2015 Gabi Melman. |  | ||||||
| // Distributed under the MIT License (http://opensource.org/licenses/MIT) | // Distributed under the MIT License (http://opensource.org/licenses/MIT) | ||||||
| // |  | ||||||
|  |  | ||||||
| #pragma once | #pragma once | ||||||
|  |  | ||||||
| #ifndef SPDLOG_H | #ifdef __ANDROID__ | ||||||
| #include "spdlog/spdlog.h" |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| #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 <android/log.h> | #include <android/log.h> | ||||||
| #include <chrono> | #include <chrono> | ||||||
| @@ -37,21 +34,20 @@ public: | |||||||
|     explicit android_sink(std::string tag = "spdlog", bool use_raw_msg = false) |     explicit android_sink(std::string tag = "spdlog", bool use_raw_msg = false) | ||||||
|         : tag_(std::move(tag)) |         : tag_(std::move(tag)) | ||||||
|         , use_raw_msg_(use_raw_msg) |         , use_raw_msg_(use_raw_msg) | ||||||
|     { |     {} | ||||||
|     } |  | ||||||
|  |  | ||||||
| protected: | protected: | ||||||
|     void sink_it_(const details::log_msg &msg) override |     void sink_it_(const details::log_msg &msg) override | ||||||
|     { |     { | ||||||
|         const android_LogPriority priority = convert_to_android_(msg.level); |         const android_LogPriority priority = convert_to_android_(msg.level); | ||||||
|         fmt::memory_buffer formatted; |         memory_buf_t formatted; | ||||||
|         if (use_raw_msg_) |         if (use_raw_msg_) | ||||||
|         { |         { | ||||||
|             details::fmt_helper::append_string_view(msg.payload, formatted); |             details::fmt_helper::append_string_view(msg.payload, formatted); | ||||||
|         } |         } | ||||||
|         else |         else | ||||||
|         { |         { | ||||||
|             sink::formatter_->format(msg, formatted); |             base_sink<Mutex>::formatter_->format(msg, formatted); | ||||||
|         } |         } | ||||||
|         formatted.push_back('\0'); |         formatted.push_back('\0'); | ||||||
|         const char *msg_output = formatted.data(); |         const char *msg_output = formatted.data(); | ||||||
| @@ -68,7 +64,7 @@ protected: | |||||||
|  |  | ||||||
|         if (ret < 0) |         if (ret < 0) | ||||||
|         { |         { | ||||||
|             throw spdlog_ex("__android_log_write() failed", ret); |             SPDLOG_THROW(spdlog_ex("__android_log_write() failed", ret)); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -106,16 +102,18 @@ using android_sink_st = android_sink<details::null_mutex>; | |||||||
|  |  | ||||||
| // Create and register android syslog logger | // Create and register android syslog logger | ||||||
|  |  | ||||||
| template<typename Factory = default_factory> | template<typename Factory = spdlog::synchronous_factory> | ||||||
| inline std::shared_ptr<logger> android_logger_mt(const std::string &logger_name, const std::string &tag = "spdlog") | inline std::shared_ptr<logger> android_logger_mt(const std::string &logger_name, const std::string &tag = "spdlog") | ||||||
| { | { | ||||||
|     return Factory::template create<sinks::android_sink_mt>(logger_name, tag); |     return Factory::template create<sinks::android_sink_mt>(logger_name, tag); | ||||||
| } | } | ||||||
|  |  | ||||||
| template<typename Factory = default_factory> | template<typename Factory = spdlog::synchronous_factory> | ||||||
| inline std::shared_ptr<logger> android_logger_st(const std::string &logger_name, const std::string &tag = "spdlog") | inline std::shared_ptr<logger> android_logger_st(const std::string &logger_name, const std::string &tag = "spdlog") | ||||||
| { | { | ||||||
|     return Factory::template create<sinks::android_sink_st>(logger_name, tag); |     return Factory::template create<sinks::android_sink_st>(logger_name, tag); | ||||||
| } | } | ||||||
|  |  | ||||||
| } // namespace spdlog | } // namespace spdlog | ||||||
|  |  | ||||||
|  | #endif // __ANDROID__ | ||||||
							
								
								
									
										136
									
								
								third_party/spdlog/include/spdlog/sinks/ansicolor_sink-inl.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										136
									
								
								third_party/spdlog/include/spdlog/sinks/ansicolor_sink-inl.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,136 @@ | |||||||
|  | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. | ||||||
|  | // Distributed under the MIT License (http://opensource.org/licenses/MIT) | ||||||
|  |  | ||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #ifndef SPDLOG_HEADER_ONLY | ||||||
|  | #include "spdlog/sinks/ansicolor_sink.h" | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #include "spdlog/details/pattern_formatter.h" | ||||||
|  | #include "spdlog/details/os.h" | ||||||
|  |  | ||||||
|  | namespace spdlog { | ||||||
|  | namespace sinks { | ||||||
|  |  | ||||||
|  | template<typename ConsoleMutex> | ||||||
|  | SPDLOG_INLINE ansicolor_sink<ConsoleMutex>::ansicolor_sink(FILE *target_file, color_mode mode) | ||||||
|  |     : target_file_(target_file) | ||||||
|  |     , mutex_(ConsoleMutex::mutex()) | ||||||
|  |     , formatter_(details::make_unique<spdlog::pattern_formatter>()) | ||||||
|  |  | ||||||
|  | { | ||||||
|  |     set_color_mode(mode); | ||||||
|  |     colors_[level::trace] = white; | ||||||
|  |     colors_[level::debug] = cyan; | ||||||
|  |     colors_[level::info] = green; | ||||||
|  |     colors_[level::warn] = yellow_bold; | ||||||
|  |     colors_[level::err] = red_bold; | ||||||
|  |     colors_[level::critical] = bold_on_red; | ||||||
|  |     colors_[level::off] = reset; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | template<typename ConsoleMutex> | ||||||
|  | SPDLOG_INLINE void ansicolor_sink<ConsoleMutex>::set_color(level::level_enum color_level, string_view_t color) | ||||||
|  | { | ||||||
|  |     std::lock_guard<mutex_t> lock(mutex_); | ||||||
|  |     colors_[color_level] = color; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | template<typename ConsoleMutex> | ||||||
|  | SPDLOG_INLINE void ansicolor_sink<ConsoleMutex>::log(const details::log_msg &msg) | ||||||
|  | { | ||||||
|  |     // Wrap the originally formatted message in color codes. | ||||||
|  |     // If color is not supported in the terminal, log as is instead. | ||||||
|  |     std::lock_guard<mutex_t> lock(mutex_); | ||||||
|  |  | ||||||
|  |     memory_buf_t formatted; | ||||||
|  |     formatter_->format(msg, formatted); | ||||||
|  |     if (should_do_colors_ && msg.color_range_end > msg.color_range_start) | ||||||
|  |     { | ||||||
|  |         // before color range | ||||||
|  |         print_range_(formatted, 0, msg.color_range_start); | ||||||
|  |         // in color range | ||||||
|  |         print_ccode_(colors_[msg.level]); | ||||||
|  |         print_range_(formatted, msg.color_range_start, msg.color_range_end); | ||||||
|  |         print_ccode_(reset); | ||||||
|  |         // after color range | ||||||
|  |         print_range_(formatted, msg.color_range_end, formatted.size()); | ||||||
|  |     } | ||||||
|  |     else // no color | ||||||
|  |     { | ||||||
|  |         print_range_(formatted, 0, formatted.size()); | ||||||
|  |     } | ||||||
|  |     fflush(target_file_); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | template<typename ConsoleMutex> | ||||||
|  | SPDLOG_INLINE void ansicolor_sink<ConsoleMutex>::flush() | ||||||
|  | { | ||||||
|  |     std::lock_guard<mutex_t> lock(mutex_); | ||||||
|  |     fflush(target_file_); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | template<typename ConsoleMutex> | ||||||
|  | SPDLOG_INLINE void ansicolor_sink<ConsoleMutex>::set_pattern(const std::string &pattern) | ||||||
|  | { | ||||||
|  |     std::lock_guard<mutex_t> lock(mutex_); | ||||||
|  |     formatter_ = std::unique_ptr<spdlog::formatter>(new pattern_formatter(pattern)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | template<typename ConsoleMutex> | ||||||
|  | SPDLOG_INLINE void ansicolor_sink<ConsoleMutex>::set_formatter(std::unique_ptr<spdlog::formatter> sink_formatter) | ||||||
|  | { | ||||||
|  |     std::lock_guard<mutex_t> lock(mutex_); | ||||||
|  |     formatter_ = std::move(sink_formatter); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | template<typename ConsoleMutex> | ||||||
|  | SPDLOG_INLINE bool ansicolor_sink<ConsoleMutex>::should_color() | ||||||
|  | { | ||||||
|  |     return should_do_colors_; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | template<typename ConsoleMutex> | ||||||
|  | SPDLOG_INLINE void ansicolor_sink<ConsoleMutex>::set_color_mode(color_mode mode) | ||||||
|  | { | ||||||
|  |     switch (mode) | ||||||
|  |     { | ||||||
|  |     case color_mode::always: | ||||||
|  |         should_do_colors_ = true; | ||||||
|  |         return; | ||||||
|  |     case color_mode::automatic: | ||||||
|  |         should_do_colors_ = details::os::in_terminal(target_file_) && details::os::is_color_terminal(); | ||||||
|  |         return; | ||||||
|  |     case color_mode::never: | ||||||
|  |         should_do_colors_ = false; | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | template<typename ConsoleMutex> | ||||||
|  | SPDLOG_INLINE void ansicolor_sink<ConsoleMutex>::print_ccode_(const string_view_t &color_code) | ||||||
|  | { | ||||||
|  |     fwrite(color_code.data(), sizeof(string_view_t::char_type), color_code.size(), target_file_); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | template<typename ConsoleMutex> | ||||||
|  | SPDLOG_INLINE void ansicolor_sink<ConsoleMutex>::print_range_(const memory_buf_t &formatted, size_t start, size_t end) | ||||||
|  | { | ||||||
|  |     fwrite(formatted.data() + start, sizeof(char), end - start, target_file_); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // ansicolor_stdout_sink | ||||||
|  | template<typename ConsoleMutex> | ||||||
|  | SPDLOG_INLINE ansicolor_stdout_sink<ConsoleMutex>::ansicolor_stdout_sink(color_mode mode) | ||||||
|  |     : ansicolor_sink<ConsoleMutex>(stdout, mode) | ||||||
|  | {} | ||||||
|  |  | ||||||
|  | // ansicolor_stderr_sink | ||||||
|  | template<typename ConsoleMutex> | ||||||
|  | SPDLOG_INLINE ansicolor_stderr_sink<ConsoleMutex>::ansicolor_stderr_sink(color_mode mode) | ||||||
|  |     : ansicolor_sink<ConsoleMutex>(stderr, mode) | ||||||
|  | {} | ||||||
|  |  | ||||||
|  | } // namespace sinks | ||||||
|  | } // namespace spdlog | ||||||
| @@ -1,19 +1,11 @@ | |||||||
| // | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. | ||||||
| // Copyright(c) 2017 spdlog authors. |  | ||||||
| // Distributed under the MIT License (http://opensource.org/licenses/MIT) | // Distributed under the MIT License (http://opensource.org/licenses/MIT) | ||||||
| // |  | ||||||
|  |  | ||||||
| #pragma once | #pragma once | ||||||
|  |  | ||||||
| #ifndef SPDLOG_H |  | ||||||
| #include "spdlog/spdlog.h" |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| #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/details/os.h" |  | ||||||
| #include "spdlog/sinks/sink.h" | #include "spdlog/sinks/sink.h" | ||||||
|  |  | ||||||
| #include <memory> | #include <memory> | ||||||
| #include <mutex> | #include <mutex> | ||||||
| #include <string> | #include <string> | ||||||
| @@ -28,134 +20,94 @@ namespace sinks { | |||||||
|  * of the message. |  * of the message. | ||||||
|  * If no color terminal detected, omit the escape codes. |  * If no color terminal detected, omit the escape codes. | ||||||
|  */ |  */ | ||||||
| template<typename TargetStream, class ConsoleMutex> |  | ||||||
| class ansicolor_sink final : public sink | template<typename ConsoleMutex> | ||||||
|  | class ansicolor_sink : public sink | ||||||
| { | { | ||||||
| public: | public: | ||||||
|     using mutex_t = typename ConsoleMutex::mutex_t; |     using mutex_t = typename ConsoleMutex::mutex_t; | ||||||
|     ansicolor_sink() |     ansicolor_sink(FILE *target_file, color_mode mode); | ||||||
|         : target_file_(TargetStream::stream()) |  | ||||||
|         , mutex_(ConsoleMutex::mutex()) |  | ||||||
|  |  | ||||||
|     { |  | ||||||
|         should_do_colors_ = details::os::in_terminal(target_file_) && details::os::is_color_terminal(); |  | ||||||
|         colors_[level::trace] = white; |  | ||||||
|         colors_[level::debug] = cyan; |  | ||||||
|         colors_[level::info] = green; |  | ||||||
|         colors_[level::warn] = yellow + bold; |  | ||||||
|         colors_[level::err] = red + bold; |  | ||||||
|         colors_[level::critical] = bold + on_red; |  | ||||||
|         colors_[level::off] = reset; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     ~ansicolor_sink() override = default; |     ~ansicolor_sink() override = default; | ||||||
|  |  | ||||||
|     ansicolor_sink(const ansicolor_sink &other) = delete; |     ansicolor_sink(const ansicolor_sink &other) = delete; | ||||||
|     ansicolor_sink &operator=(const ansicolor_sink &other) = delete; |     ansicolor_sink &operator=(const ansicolor_sink &other) = delete; | ||||||
|  |     void set_color(level::level_enum color_level, string_view_t color); | ||||||
|  |     void set_color_mode(color_mode mode); | ||||||
|  |     bool should_color(); | ||||||
|  |  | ||||||
|     void set_color(level::level_enum color_level, const std::string &color) |     void log(const details::log_msg &msg) override; | ||||||
|     { |     void flush() override; | ||||||
|         std::lock_guard<mutex_t> lock(mutex_); |     void set_pattern(const std::string &pattern) final; | ||||||
|         colors_[color_level] = color; |     void set_formatter(std::unique_ptr<spdlog::formatter> sink_formatter) override; | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /// Formatting codes |     // Formatting codes | ||||||
|     const std::string reset = "\033[m"; |     const string_view_t reset = "\033[m"; | ||||||
|     const std::string bold = "\033[1m"; |     const string_view_t bold = "\033[1m"; | ||||||
|     const std::string dark = "\033[2m"; |     const string_view_t dark = "\033[2m"; | ||||||
|     const std::string underline = "\033[4m"; |     const string_view_t underline = "\033[4m"; | ||||||
|     const std::string blink = "\033[5m"; |     const string_view_t blink = "\033[5m"; | ||||||
|     const std::string reverse = "\033[7m"; |     const string_view_t reverse = "\033[7m"; | ||||||
|     const std::string concealed = "\033[8m"; |     const string_view_t concealed = "\033[8m"; | ||||||
|     const std::string clear_line = "\033[K"; |     const string_view_t clear_line = "\033[K"; | ||||||
|  |  | ||||||
|     // Foreground colors |     // Foreground colors | ||||||
|     const std::string black = "\033[30m"; |     const string_view_t black = "\033[30m"; | ||||||
|     const std::string red = "\033[31m"; |     const string_view_t red = "\033[31m"; | ||||||
|     const std::string green = "\033[32m"; |     const string_view_t green = "\033[32m"; | ||||||
|     const std::string yellow = "\033[33m"; |     const string_view_t yellow = "\033[33m"; | ||||||
|     const std::string blue = "\033[34m"; |     const string_view_t blue = "\033[34m"; | ||||||
|     const std::string magenta = "\033[35m"; |     const string_view_t magenta = "\033[35m"; | ||||||
|     const std::string cyan = "\033[36m"; |     const string_view_t cyan = "\033[36m"; | ||||||
|     const std::string white = "\033[37m"; |     const string_view_t white = "\033[37m"; | ||||||
|  |  | ||||||
|     /// Background colors |     /// Background colors | ||||||
|     const std::string on_black = "\033[40m"; |     const string_view_t on_black = "\033[40m"; | ||||||
|     const std::string on_red = "\033[41m"; |     const string_view_t on_red = "\033[41m"; | ||||||
|     const std::string on_green = "\033[42m"; |     const string_view_t on_green = "\033[42m"; | ||||||
|     const std::string on_yellow = "\033[43m"; |     const string_view_t on_yellow = "\033[43m"; | ||||||
|     const std::string on_blue = "\033[44m"; |     const string_view_t on_blue = "\033[44m"; | ||||||
|     const std::string on_magenta = "\033[45m"; |     const string_view_t on_magenta = "\033[45m"; | ||||||
|     const std::string on_cyan = "\033[46m"; |     const string_view_t on_cyan = "\033[46m"; | ||||||
|     const std::string on_white = "\033[47m"; |     const string_view_t on_white = "\033[47m"; | ||||||
|  |  | ||||||
|     void log(const details::log_msg &msg) override |     /// Bold colors | ||||||
|     { |     const string_view_t yellow_bold = "\033[33m\033[1m"; | ||||||
|         // Wrap the originally formatted message in color codes. |     const string_view_t red_bold = "\033[31m\033[1m"; | ||||||
|         // If color is not supported in the terminal, log as is instead. |     const string_view_t bold_on_red = "\033[1m\033[41m"; | ||||||
|         std::lock_guard<mutex_t> lock(mutex_); |  | ||||||
|  |  | ||||||
|         fmt::memory_buffer formatted; |  | ||||||
|         formatter_->format(msg, formatted); |  | ||||||
|         if (should_do_colors_ && msg.color_range_end > msg.color_range_start) |  | ||||||
|         { |  | ||||||
|             // before color range |  | ||||||
|             print_range_(formatted, 0, msg.color_range_start); |  | ||||||
|             // in color range |  | ||||||
|             print_ccode_(colors_[msg.level]); |  | ||||||
|             print_range_(formatted, msg.color_range_start, msg.color_range_end); |  | ||||||
|             print_ccode_(reset); |  | ||||||
|             // after color range |  | ||||||
|             print_range_(formatted, msg.color_range_end, formatted.size()); |  | ||||||
|         } |  | ||||||
|         else // no color |  | ||||||
|         { |  | ||||||
|             print_range_(formatted, 0, formatted.size()); |  | ||||||
|         } |  | ||||||
|         fflush(target_file_); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     void flush() override |  | ||||||
|     { |  | ||||||
|         std::lock_guard<mutex_t> lock(mutex_); |  | ||||||
|         fflush(target_file_); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     void set_pattern(const std::string &pattern) final |  | ||||||
|     { |  | ||||||
|         std::lock_guard<mutex_t> lock(mutex_); |  | ||||||
|         formatter_ = std::unique_ptr<spdlog::formatter>(new pattern_formatter(pattern)); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     void set_formatter(std::unique_ptr<spdlog::formatter> sink_formatter) override |  | ||||||
|     { |  | ||||||
|         std::lock_guard<mutex_t> lock(mutex_); |  | ||||||
|         formatter_ = std::move(sink_formatter); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
| private: | private: | ||||||
|     void print_ccode_(const std::string &color_code) |  | ||||||
|     { |  | ||||||
|         fwrite(color_code.data(), sizeof(char), color_code.size(), target_file_); |  | ||||||
|     } |  | ||||||
|     void print_range_(const fmt::memory_buffer &formatted, size_t start, size_t end) |  | ||||||
|     { |  | ||||||
|         fwrite(formatted.data() + start, sizeof(char), end - start, target_file_); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     FILE *target_file_; |     FILE *target_file_; | ||||||
|     mutex_t &mutex_; |     mutex_t &mutex_; | ||||||
|  |  | ||||||
|     bool should_do_colors_; |     bool should_do_colors_; | ||||||
|     std::unordered_map<level::level_enum, std::string, level::level_hasher> colors_; |     std::unique_ptr<spdlog::formatter> formatter_; | ||||||
|  |     std::unordered_map<level::level_enum, string_view_t, level::level_hasher> colors_; | ||||||
|  |     void print_ccode_(const string_view_t &color_code); | ||||||
|  |     void print_range_(const memory_buf_t &formatted, size_t start, size_t end); | ||||||
| }; | }; | ||||||
|  |  | ||||||
| using ansicolor_stdout_sink_mt = ansicolor_sink<details::console_stdout, details::console_mutex>; | template<typename ConsoleMutex> | ||||||
| using ansicolor_stdout_sink_st = ansicolor_sink<details::console_stdout, details::console_nullmutex>; | class ansicolor_stdout_sink : public ansicolor_sink<ConsoleMutex> | ||||||
|  | { | ||||||
|  | public: | ||||||
|  |     explicit ansicolor_stdout_sink(color_mode mode = color_mode::automatic); | ||||||
|  | }; | ||||||
|  |  | ||||||
| using ansicolor_stderr_sink_mt = ansicolor_sink<details::console_stderr, details::console_mutex>; | template<typename ConsoleMutex> | ||||||
| using ansicolor_stderr_sink_st = ansicolor_sink<details::console_stderr, details::console_nullmutex>; | class ansicolor_stderr_sink : public ansicolor_sink<ConsoleMutex> | ||||||
|  | { | ||||||
|  | public: | ||||||
|  |     explicit ansicolor_stderr_sink(color_mode mode = color_mode::automatic); | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | using ansicolor_stdout_sink_mt = ansicolor_stdout_sink<details::console_mutex>; | ||||||
|  | using ansicolor_stdout_sink_st = ansicolor_stdout_sink<details::console_nullmutex>; | ||||||
|  |  | ||||||
|  | using ansicolor_stderr_sink_mt = ansicolor_stderr_sink<details::console_mutex>; | ||||||
|  | using ansicolor_stderr_sink_st = ansicolor_stderr_sink<details::console_nullmutex>; | ||||||
|  |  | ||||||
| } // namespace sinks | } // namespace sinks | ||||||
|  |  | ||||||
| } // namespace spdlog | } // namespace spdlog | ||||||
|  |  | ||||||
|  | #ifdef SPDLOG_HEADER_ONLY | ||||||
|  | #include "ansicolor_sink-inl.h" | ||||||
|  | #endif | ||||||
|   | |||||||
							
								
								
									
										63
									
								
								third_party/spdlog/include/spdlog/sinks/base_sink-inl.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								third_party/spdlog/include/spdlog/sinks/base_sink-inl.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,63 @@ | |||||||
|  | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. | ||||||
|  | // Distributed under the MIT License (http://opensource.org/licenses/MIT) | ||||||
|  |  | ||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #ifndef SPDLOG_HEADER_ONLY | ||||||
|  | #include "spdlog/sinks/base_sink.h" | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #include "spdlog/common.h" | ||||||
|  | #include "spdlog/details/pattern_formatter.h" | ||||||
|  |  | ||||||
|  | #include <memory> | ||||||
|  |  | ||||||
|  | template<typename Mutex> | ||||||
|  | SPDLOG_INLINE spdlog::sinks::base_sink<Mutex>::base_sink() | ||||||
|  |     : formatter_{details::make_unique<spdlog::pattern_formatter>()} | ||||||
|  | {} | ||||||
|  |  | ||||||
|  | template<typename Mutex> | ||||||
|  | SPDLOG_INLINE spdlog::sinks::base_sink<Mutex>::base_sink(std::unique_ptr<spdlog::formatter> formatter) | ||||||
|  |     : formatter_{std::move(formatter)} | ||||||
|  | {} | ||||||
|  |  | ||||||
|  | template<typename Mutex> | ||||||
|  | void SPDLOG_INLINE spdlog::sinks::base_sink<Mutex>::log(const details::log_msg &msg) | ||||||
|  | { | ||||||
|  |     std::lock_guard<Mutex> lock(mutex_); | ||||||
|  |     sink_it_(msg); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | template<typename Mutex> | ||||||
|  | void SPDLOG_INLINE spdlog::sinks::base_sink<Mutex>::flush() | ||||||
|  | { | ||||||
|  |     std::lock_guard<Mutex> lock(mutex_); | ||||||
|  |     flush_(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | template<typename Mutex> | ||||||
|  | void SPDLOG_INLINE spdlog::sinks::base_sink<Mutex>::set_pattern(const std::string &pattern) | ||||||
|  | { | ||||||
|  |     std::lock_guard<Mutex> lock(mutex_); | ||||||
|  |     set_pattern_(pattern); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | template<typename Mutex> | ||||||
|  | void SPDLOG_INLINE spdlog::sinks::base_sink<Mutex>::set_formatter(std::unique_ptr<spdlog::formatter> sink_formatter) | ||||||
|  | { | ||||||
|  |     std::lock_guard<Mutex> lock(mutex_); | ||||||
|  |     set_formatter_(std::move(sink_formatter)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | template<typename Mutex> | ||||||
|  | void SPDLOG_INLINE spdlog::sinks::base_sink<Mutex>::set_pattern_(const std::string &pattern) | ||||||
|  | { | ||||||
|  |     set_formatter_(details::make_unique<spdlog::pattern_formatter>(pattern)); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | template<typename Mutex> | ||||||
|  | void SPDLOG_INLINE spdlog::sinks::base_sink<Mutex>::set_formatter_(std::unique_ptr<spdlog::formatter> sink_formatter) | ||||||
|  | { | ||||||
|  |     formatter_ = std::move(sink_formatter); | ||||||
|  | } | ||||||
| @@ -1,7 +1,5 @@ | |||||||
| // | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. | ||||||
| // Copyright(c) 2015 Gabi Melman. |  | ||||||
| // Distributed under the MIT License (http://opensource.org/licenses/MIT) | // Distributed under the MIT License (http://opensource.org/licenses/MIT) | ||||||
| // |  | ||||||
|  |  | ||||||
| #pragma once | #pragma once | ||||||
| // | // | ||||||
| @@ -13,7 +11,6 @@ | |||||||
|  |  | ||||||
| #include "spdlog/common.h" | #include "spdlog/common.h" | ||||||
| #include "spdlog/details/log_msg.h" | #include "spdlog/details/log_msg.h" | ||||||
| #include "spdlog/formatter.h" |  | ||||||
| #include "spdlog/sinks/sink.h" | #include "spdlog/sinks/sink.h" | ||||||
|  |  | ||||||
| namespace spdlog { | namespace spdlog { | ||||||
| @@ -22,48 +19,28 @@ template<typename Mutex> | |||||||
| class base_sink : public sink | class base_sink : public sink | ||||||
| { | { | ||||||
| public: | public: | ||||||
|     base_sink() = default; |     base_sink(); | ||||||
|  |     explicit base_sink(std::unique_ptr<spdlog::formatter> formatter); | ||||||
|     base_sink(const base_sink &) = delete; |     base_sink(const base_sink &) = delete; | ||||||
|     base_sink &operator=(const base_sink &) = delete; |     base_sink &operator=(const base_sink &) = delete; | ||||||
|  |     void log(const details::log_msg &msg) final; | ||||||
|     void log(const details::log_msg &msg) final |     void flush() final; | ||||||
|     { |     void set_pattern(const std::string &pattern) final; | ||||||
|         std::lock_guard<Mutex> lock(mutex_); |     void set_formatter(std::unique_ptr<spdlog::formatter> sink_formatter) final; | ||||||
|         sink_it_(msg); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     void flush() final |  | ||||||
|     { |  | ||||||
|         std::lock_guard<Mutex> lock(mutex_); |  | ||||||
|         flush_(); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     void set_pattern(const std::string &pattern) final |  | ||||||
|     { |  | ||||||
|         std::lock_guard<Mutex> lock(mutex_); |  | ||||||
|         set_pattern_(pattern); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     void set_formatter(std::unique_ptr<spdlog::formatter> sink_formatter) final |  | ||||||
|     { |  | ||||||
|         std::lock_guard<Mutex> lock(mutex_); |  | ||||||
|         set_formatter_(std::move(sink_formatter)); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
| protected: | protected: | ||||||
|  |     // sink formatter | ||||||
|  |     std::unique_ptr<spdlog::formatter> formatter_; | ||||||
|  |     Mutex mutex_; | ||||||
|  |  | ||||||
|     virtual void sink_it_(const details::log_msg &msg) = 0; |     virtual void sink_it_(const details::log_msg &msg) = 0; | ||||||
|     virtual void flush_() = 0; |     virtual void flush_() = 0; | ||||||
|  |     virtual void set_pattern_(const std::string &pattern); | ||||||
|     virtual void set_pattern_(const std::string &pattern) |     virtual void set_formatter_(std::unique_ptr<spdlog::formatter> sink_formatter); | ||||||
|     { |  | ||||||
|         set_formatter_(details::make_unique<spdlog::pattern_formatter>(pattern)); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     virtual void set_formatter_(std::unique_ptr<spdlog::formatter> sink_formatter) |  | ||||||
|     { |  | ||||||
|         formatter_ = std::move(sink_formatter); |  | ||||||
|     } |  | ||||||
|     Mutex mutex_; |  | ||||||
| }; | }; | ||||||
| } // namespace sinks | } // namespace sinks | ||||||
| } // namespace spdlog | } // namespace spdlog | ||||||
|  |  | ||||||
|  | #ifdef SPDLOG_HEADER_ONLY | ||||||
|  | #include "base_sink-inl.h" | ||||||
|  | #endif | ||||||
|   | |||||||
							
								
								
									
										43
									
								
								third_party/spdlog/include/spdlog/sinks/basic_file_sink-inl.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								third_party/spdlog/include/spdlog/sinks/basic_file_sink-inl.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,43 @@ | |||||||
|  | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. | ||||||
|  | // Distributed under the MIT License (http://opensource.org/licenses/MIT) | ||||||
|  |  | ||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #ifndef SPDLOG_HEADER_ONLY | ||||||
|  | #include "spdlog/sinks/basic_file_sink.h" | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #include "spdlog/common.h" | ||||||
|  | #include "spdlog/details/os.h" | ||||||
|  |  | ||||||
|  | namespace spdlog { | ||||||
|  | namespace sinks { | ||||||
|  |  | ||||||
|  | template<typename Mutex> | ||||||
|  | SPDLOG_INLINE basic_file_sink<Mutex>::basic_file_sink(const filename_t &filename, bool truncate) | ||||||
|  | { | ||||||
|  |     file_helper_.open(filename, truncate); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | template<typename Mutex> | ||||||
|  | SPDLOG_INLINE const filename_t &basic_file_sink<Mutex>::filename() const | ||||||
|  | { | ||||||
|  |     return file_helper_.filename(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | template<typename Mutex> | ||||||
|  | SPDLOG_INLINE void basic_file_sink<Mutex>::sink_it_(const details::log_msg &msg) | ||||||
|  | { | ||||||
|  |     memory_buf_t formatted; | ||||||
|  |     base_sink<Mutex>::formatter_->format(msg, formatted); | ||||||
|  |     file_helper_.write(formatted); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | template<typename Mutex> | ||||||
|  | SPDLOG_INLINE void basic_file_sink<Mutex>::flush_() | ||||||
|  | { | ||||||
|  |     file_helper_.flush(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | } // namespace sinks | ||||||
|  | } // namespace spdlog | ||||||
| @@ -1,17 +1,12 @@ | |||||||
| // | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. | ||||||
| // Copyright(c) 2015-2018 Gabi Melman. |  | ||||||
| // Distributed under the MIT License (http://opensource.org/licenses/MIT) | // Distributed under the MIT License (http://opensource.org/licenses/MIT) | ||||||
| // |  | ||||||
|  |  | ||||||
| #pragma once | #pragma once | ||||||
|  |  | ||||||
| #ifndef SPDLOG_H |  | ||||||
| #include "spdlog/spdlog.h" |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| #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 <mutex> | #include <mutex> | ||||||
| #include <string> | #include <string> | ||||||
| @@ -25,23 +20,12 @@ template<typename Mutex> | |||||||
| class basic_file_sink final : public base_sink<Mutex> | class basic_file_sink final : public base_sink<Mutex> | ||||||
| { | { | ||||||
| public: | public: | ||||||
|     explicit basic_file_sink(const filename_t &filename, bool truncate = false) |     explicit basic_file_sink(const filename_t &filename, bool truncate = false); | ||||||
|     { |     const filename_t &filename() const; | ||||||
|         file_helper_.open(filename, truncate); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
| protected: | protected: | ||||||
|     void sink_it_(const details::log_msg &msg) override |     void sink_it_(const details::log_msg &msg) override; | ||||||
|     { |     void flush_() override; | ||||||
|         fmt::memory_buffer formatted; |  | ||||||
|         sink::formatter_->format(msg, formatted); |  | ||||||
|         file_helper_.write(formatted); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     void flush_() override |  | ||||||
|     { |  | ||||||
|         file_helper_.flush(); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
| private: | private: | ||||||
|     details::file_helper file_helper_; |     details::file_helper file_helper_; | ||||||
| @@ -55,16 +39,20 @@ using basic_file_sink_st = basic_file_sink<details::null_mutex>; | |||||||
| // | // | ||||||
| // factory functions | // factory functions | ||||||
| // | // | ||||||
| template<typename Factory = default_factory> | template<typename Factory = spdlog::synchronous_factory> | ||||||
| inline std::shared_ptr<logger> basic_logger_mt(const std::string &logger_name, const filename_t &filename, bool truncate = false) | inline std::shared_ptr<logger> basic_logger_mt(const std::string &logger_name, const filename_t &filename, bool truncate = false) | ||||||
| { | { | ||||||
|     return Factory::template create<sinks::basic_file_sink_mt>(logger_name, filename, truncate); |     return Factory::template create<sinks::basic_file_sink_mt>(logger_name, filename, truncate); | ||||||
| } | } | ||||||
|  |  | ||||||
| template<typename Factory = default_factory> | template<typename Factory = spdlog::synchronous_factory> | ||||||
| inline std::shared_ptr<logger> basic_logger_st(const std::string &logger_name, const filename_t &filename, bool truncate = false) | inline std::shared_ptr<logger> basic_logger_st(const std::string &logger_name, const filename_t &filename, bool truncate = false) | ||||||
| { | { | ||||||
|     return Factory::template create<sinks::basic_file_sink_st>(logger_name, filename, truncate); |     return Factory::template create<sinks::basic_file_sink_st>(logger_name, filename, truncate); | ||||||
| } | } | ||||||
|  |  | ||||||
| } // namespace spdlog | } // namespace spdlog | ||||||
|  |  | ||||||
|  | #ifdef SPDLOG_HEADER_ONLY | ||||||
|  | #include "basic_file_sink-inl.h" | ||||||
|  | #endif | ||||||
| @@ -1,18 +1,15 @@ | |||||||
| // | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. | ||||||
| // Copyright(c) 2015 Gabi Melman. |  | ||||||
| // Distributed under the MIT License (http://opensource.org/licenses/MIT) | // Distributed under the MIT License (http://opensource.org/licenses/MIT) | ||||||
| // |  | ||||||
|  |  | ||||||
| #pragma once | #pragma once | ||||||
|  |  | ||||||
| #ifndef SPDLOG_H | #include "spdlog/common.h" | ||||||
| #include "spdlog/spdlog.h" |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| #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/synchronous_factory.h" | ||||||
|  |  | ||||||
| #include <chrono> | #include <chrono> | ||||||
| #include <cstdio> | #include <cstdio> | ||||||
| @@ -33,48 +30,76 @@ struct daily_filename_calculator | |||||||
|     { |     { | ||||||
|         filename_t basename, ext; |         filename_t basename, ext; | ||||||
|         std::tie(basename, ext) = details::file_helper::split_by_extension(filename); |         std::tie(basename, ext) = details::file_helper::split_by_extension(filename); | ||||||
|         std::conditional<std::is_same<filename_t::value_type, char>::value, fmt::memory_buffer, fmt::wmemory_buffer>::type w; |         return fmt::format( | ||||||
|         fmt::format_to( |             SPDLOG_FILENAME_T("{}_{:04d}-{:02d}-{:02d}{}"), basename, now_tm.tm_year + 1900, now_tm.tm_mon + 1, now_tm.tm_mday, ext); | ||||||
|             w, SPDLOG_FILENAME_T("{}_{:04d}-{:02d}-{:02d}{}"), basename, now_tm.tm_year + 1900, now_tm.tm_mon + 1, now_tm.tm_mday, ext); |  | ||||||
|         return fmt::to_string(w); |  | ||||||
|     } |     } | ||||||
| }; | }; | ||||||
|  |  | ||||||
| /* | /* | ||||||
|  * Rotating file sink based on date. rotates at midnight |  * Rotating file sink based on date. | ||||||
|  |  * If truncate != false , the created file will be truncated. | ||||||
|  |  * If max_files > 0, retain only the last max_files and delete previous. | ||||||
|  */ |  */ | ||||||
| template<typename Mutex, typename FileNameCalc = daily_filename_calculator> | template<typename Mutex, typename FileNameCalc = daily_filename_calculator> | ||||||
| class daily_file_sink final : public base_sink<Mutex> | class daily_file_sink final : public base_sink<Mutex> | ||||||
| { | { | ||||||
| public: | public: | ||||||
|     // create daily file sink which rotates on given time |     // create daily file sink which rotates on given time | ||||||
|     daily_file_sink(filename_t base_filename, int rotation_hour, int rotation_minute, bool truncate = false) |     daily_file_sink(filename_t base_filename, int rotation_hour, int rotation_minute, bool truncate = false, uint16_t max_files = 0) | ||||||
|         : base_filename_(std::move(base_filename)) |         : base_filename_(std::move(base_filename)) | ||||||
|         , rotation_h_(rotation_hour) |         , rotation_h_(rotation_hour) | ||||||
|         , rotation_m_(rotation_minute) |         , rotation_m_(rotation_minute) | ||||||
|         , truncate_(truncate) |         , truncate_(truncate) | ||||||
|  |         , max_files_(max_files) | ||||||
|  |         , filenames_q_() | ||||||
|     { |     { | ||||||
|         if (rotation_hour < 0 || rotation_hour > 23 || rotation_minute < 0 || rotation_minute > 59) |         if (rotation_hour < 0 || rotation_hour > 23 || rotation_minute < 0 || rotation_minute > 59) | ||||||
|         { |         { | ||||||
|             throw spdlog_ex("daily_file_sink: Invalid rotation time in ctor"); |             SPDLOG_THROW(spdlog_ex("daily_file_sink: Invalid rotation time in ctor")); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         auto now = log_clock::now(); |         auto now = log_clock::now(); | ||||||
|         file_helper_.open(FileNameCalc::calc_filename(base_filename_, now_tm(now)), truncate_); |         auto filename = FileNameCalc::calc_filename(base_filename_, now_tm(now)); | ||||||
|  |         file_helper_.open(filename, truncate_); | ||||||
|         rotation_tp_ = next_rotation_tp_(); |         rotation_tp_ = next_rotation_tp_(); | ||||||
|  |  | ||||||
|  |         if (max_files_ > 0) | ||||||
|  |         { | ||||||
|  |             filenames_q_ = details::circular_q<filename_t>(static_cast<size_t>(max_files_)); | ||||||
|  |             filenames_q_.push_back(std::move(filename)); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     const filename_t &filename() const | ||||||
|  |     { | ||||||
|  |         return file_helper_.filename(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
| 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; | ||||||
|  | #endif | ||||||
|  |  | ||||||
|         if (msg.time >= rotation_tp_) |         bool should_rotate = time >= rotation_tp_; | ||||||
|  |         if (should_rotate) | ||||||
|         { |         { | ||||||
|             file_helper_.open(FileNameCalc::calc_filename(base_filename_, now_tm(msg.time)), truncate_); |             auto filename = FileNameCalc::calc_filename(base_filename_, now_tm(time)); | ||||||
|  |             file_helper_.open(filename, truncate_); | ||||||
|             rotation_tp_ = next_rotation_tp_(); |             rotation_tp_ = next_rotation_tp_(); | ||||||
|         } |         } | ||||||
|         fmt::memory_buffer formatted; |         memory_buf_t formatted; | ||||||
|         sink::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. | ||||||
|  |         if (should_rotate && max_files_ > 0) | ||||||
|  |         { | ||||||
|  |             delete_old_(); | ||||||
|  |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     void flush_() override |     void flush_() override | ||||||
| @@ -104,12 +129,36 @@ private: | |||||||
|         return {rotation_time + std::chrono::hours(24)}; |         return {rotation_time + std::chrono::hours(24)}; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     // Delete the file N rotations ago. | ||||||
|  |     // Throw spdlog_ex on failure to delete the old file. | ||||||
|  |     void delete_old_() | ||||||
|  |     { | ||||||
|  |         using details::os::filename_to_str; | ||||||
|  |         using details::os::remove_if_exists; | ||||||
|  |  | ||||||
|  |         filename_t current_file = filename(); | ||||||
|  |         if (filenames_q_.full()) | ||||||
|  |         { | ||||||
|  |             auto old_filename = std::move(filenames_q_.front()); | ||||||
|  |             filenames_q_.pop_front(); | ||||||
|  |             bool ok = remove_if_exists(old_filename) == 0; | ||||||
|  |             if (!ok) | ||||||
|  |             { | ||||||
|  |                 filenames_q_.push_back(std::move(current_file)); | ||||||
|  |                 SPDLOG_THROW(spdlog_ex("Failed removing daily file " + filename_to_str(old_filename), errno)); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         filenames_q_.push_back(std::move(current_file)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     filename_t base_filename_; |     filename_t base_filename_; | ||||||
|     int rotation_h_; |     int rotation_h_; | ||||||
|     int rotation_m_; |     int rotation_m_; | ||||||
|     log_clock::time_point rotation_tp_; |     log_clock::time_point rotation_tp_; | ||||||
|     details::file_helper file_helper_; |     details::file_helper file_helper_; | ||||||
|     bool truncate_; |     bool truncate_; | ||||||
|  |     uint16_t max_files_; | ||||||
|  |     details::circular_q<filename_t> filenames_q_; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| using daily_file_sink_mt = daily_file_sink<std::mutex>; | using daily_file_sink_mt = daily_file_sink<std::mutex>; | ||||||
| @@ -120,14 +169,14 @@ using daily_file_sink_st = daily_file_sink<details::null_mutex>; | |||||||
| // | // | ||||||
| // factory functions | // factory functions | ||||||
| // | // | ||||||
| template<typename Factory = default_factory> | template<typename Factory = spdlog::synchronous_factory> | ||||||
| inline std::shared_ptr<logger> daily_logger_mt( | inline std::shared_ptr<logger> daily_logger_mt( | ||||||
|     const std::string &logger_name, const filename_t &filename, int hour = 0, int minute = 0, bool truncate = false) |     const std::string &logger_name, const filename_t &filename, int hour = 0, int minute = 0, bool truncate = false) | ||||||
| { | { | ||||||
|     return Factory::template create<sinks::daily_file_sink_mt>(logger_name, filename, hour, minute, truncate); |     return Factory::template create<sinks::daily_file_sink_mt>(logger_name, filename, hour, minute, truncate); | ||||||
| } | } | ||||||
|  |  | ||||||
| template<typename Factory = default_factory> | template<typename Factory = spdlog::synchronous_factory> | ||||||
| inline std::shared_ptr<logger> daily_logger_st( | inline std::shared_ptr<logger> daily_logger_st( | ||||||
|     const std::string &logger_name, const filename_t &filename, int hour = 0, int minute = 0, bool truncate = false) |     const std::string &logger_name, const filename_t &filename, int hour = 0, int minute = 0, bool truncate = false) | ||||||
| { | { | ||||||
|   | |||||||
| @@ -1,17 +1,12 @@ | |||||||
| // | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. | ||||||
| // Copyright (c) 2015 David Schury, Gabi Melman |  | ||||||
| // Distributed under the MIT License (http://opensource.org/licenses/MIT) | // Distributed under the MIT License (http://opensource.org/licenses/MIT) | ||||||
| // |  | ||||||
|  |  | ||||||
| #pragma once | #pragma once | ||||||
|  |  | ||||||
| #ifndef SPDLOG_H |  | ||||||
| #include "spdlog/spdlog.h" |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| #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 <algorithm> | #include <algorithm> | ||||||
| #include <memory> | #include <memory> | ||||||
| @@ -50,10 +45,14 @@ public: | |||||||
|         sinks_ = std::move(sinks); |         sinks_ = std::move(sinks); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     std::vector<std::shared_ptr<sink>> &sinks() | ||||||
|  |     { | ||||||
|  |         return sinks_; | ||||||
|  |     } | ||||||
|  |  | ||||||
| protected: | protected: | ||||||
|     void sink_it_(const details::log_msg &msg) override |     void sink_it_(const details::log_msg &msg) override | ||||||
|     { |     { | ||||||
|  |  | ||||||
|         for (auto &sink : sinks_) |         for (auto &sink : sinks_) | ||||||
|         { |         { | ||||||
|             if (sink->should_log(msg.level)) |             if (sink->should_log(msg.level)) | ||||||
|   | |||||||
							
								
								
									
										94
									
								
								third_party/spdlog/include/spdlog/sinks/dup_filter_sink.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										94
									
								
								third_party/spdlog/include/spdlog/sinks/dup_filter_sink.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,94 @@ | |||||||
|  | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. | ||||||
|  | // Distributed under the MIT License (http://opensource.org/licenses/MIT) | ||||||
|  |  | ||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #include "dist_sink.h" | ||||||
|  | #include "spdlog/details/null_mutex.h" | ||||||
|  | #include "spdlog/details/log_msg.h" | ||||||
|  |  | ||||||
|  | #include <mutex> | ||||||
|  | #include <string> | ||||||
|  | #include <chrono> | ||||||
|  |  | ||||||
|  | // Duplicate message removal sink. | ||||||
|  | // Skip the message if previous one is identical and less than "max_skip_duration" have passed | ||||||
|  | // | ||||||
|  | // Example: | ||||||
|  | // | ||||||
|  | //     #include "spdlog/sinks/dup_filter_sink.h" | ||||||
|  | // | ||||||
|  | //     int main() { | ||||||
|  | //         auto dup_filter = std::make_shared<dup_filter_sink_st>(std::chrono::seconds(5)); | ||||||
|  | //         dup_filter->add_sink(std::make_shared<stdout_color_sink_mt>()); | ||||||
|  | //         spdlog::logger l("logger", dup_filter); | ||||||
|  | //         l.info("Hello"); | ||||||
|  | //         l.info("Hello"); | ||||||
|  | //         l.info("Hello"); | ||||||
|  | //         l.info("Different Hello"); | ||||||
|  | //     } | ||||||
|  | // | ||||||
|  | // Will produce: | ||||||
|  | //       [2019-06-25 17:50:56.511] [logger] [info] Hello | ||||||
|  | //       [2019-06-25 17:50:56.512] [logger] [info] Skipped 3 duplicate messages.. | ||||||
|  | //       [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 sinks { | ||||||
|  | template<typename Mutex> | ||||||
|  | class dup_filter_sink : public dist_sink<Mutex> | ||||||
|  | { | ||||||
|  | public: | ||||||
|  |     template<class Rep, class Period> | ||||||
|  |     explicit dup_filter_sink(std::chrono::duration<Rep, Period> max_skip_duration) | ||||||
|  |         : max_skip_duration_{max_skip_duration} | ||||||
|  |     {} | ||||||
|  |  | ||||||
|  | protected: | ||||||
|  |     std::chrono::microseconds max_skip_duration_; | ||||||
|  |     log_clock::time_point last_msg_time_; | ||||||
|  |     std::string last_msg_payload_; | ||||||
|  |     size_t skip_counter_ = 0; | ||||||
|  |  | ||||||
|  |     void sink_it_(const details::log_msg &msg) override | ||||||
|  |     { | ||||||
|  |         bool filtered = filter_(msg); | ||||||
|  |         if (!filtered) | ||||||
|  |         { | ||||||
|  |             skip_counter_ += 1; | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // log the "skipped.." message | ||||||
|  |         if (skip_counter_ > 0) | ||||||
|  |         { | ||||||
|  |             memory_buf_t buf; | ||||||
|  |             fmt::format_to(buf, "Skipped {} duplicate messages..", skip_counter_); | ||||||
|  |             details::log_msg skipped_msg{msg.logger_name, msg.level, string_view_t{buf.data(), buf.size()}}; | ||||||
|  |             dist_sink<Mutex>::sink_it_(skipped_msg); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // log current message | ||||||
|  |         dist_sink<Mutex>::sink_it_(msg); | ||||||
|  |         last_msg_time_ = msg.time; | ||||||
|  |         skip_counter_ = 0; | ||||||
|  |         last_msg_payload_.assign(msg.payload.data(), msg.payload.data() + msg.payload.size()); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // return whether the log msg should be displayed (true) or skipped (false) | ||||||
|  |     bool filter_(const details::log_msg &msg) | ||||||
|  |     { | ||||||
|  |         auto filter_duration = msg.time - last_msg_time_; | ||||||
|  |         return (filter_duration > max_skip_duration_) || (msg.payload != last_msg_payload_); | ||||||
|  |     } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | using dup_filter_sink_mt = dup_filter_sink<std::mutex>; | ||||||
|  | using dup_filter_sink_st = dup_filter_sink<details::null_mutex>; | ||||||
|  |  | ||||||
|  | } // namespace sinks | ||||||
|  | } // namespace spdlog | ||||||
| @@ -1,14 +1,8 @@ | |||||||
| // |  | ||||||
| // Copyright(c) 2016 Alexander Dalshov. | // Copyright(c) 2016 Alexander Dalshov. | ||||||
| // Distributed under the MIT License (http://opensource.org/licenses/MIT) | // Distributed under the MIT License (http://opensource.org/licenses/MIT) | ||||||
| // |  | ||||||
|  |  | ||||||
| #pragma once | #pragma once | ||||||
|  |  | ||||||
| #ifndef SPDLOG_H |  | ||||||
| #include "spdlog/spdlog.h" |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| #if defined(_WIN32) | #if defined(_WIN32) | ||||||
|  |  | ||||||
| #include "spdlog/details/null_mutex.h" | #include "spdlog/details/null_mutex.h" | ||||||
| @@ -34,8 +28,8 @@ protected: | |||||||
|     void sink_it_(const details::log_msg &msg) override |     void sink_it_(const details::log_msg &msg) override | ||||||
|     { |     { | ||||||
|  |  | ||||||
|         fmt::memory_buffer formatted; |         memory_buf_t formatted; | ||||||
|         sink::formatter_->format(msg, formatted); |         base_sink<Mutex>::formatter_->format(msg, formatted); | ||||||
|         OutputDebugStringA(fmt::to_string(formatted).c_str()); |         OutputDebugStringA(fmt::to_string(formatted).c_str()); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,16 +1,11 @@ | |||||||
| // | // Copyright(c) 2015-present, Gabi Melman & spdlog contributors. | ||||||
| // Copyright(c) 2015 Gabi Melman. |  | ||||||
| // Distributed under the MIT License (http://opensource.org/licenses/MIT) | // Distributed under the MIT License (http://opensource.org/licenses/MIT) | ||||||
| // |  | ||||||
|  |  | ||||||
| #pragma once | #pragma once | ||||||
|  |  | ||||||
| #ifndef SPDLOG_H |  | ||||||
| #include "spdlog/spdlog.h" |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| #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 <mutex> | #include <mutex> | ||||||
|  |  | ||||||
| @@ -25,12 +20,12 @@ protected: | |||||||
|     void flush_() override {} |     void flush_() override {} | ||||||
| }; | }; | ||||||
|  |  | ||||||
| using null_sink_mt = null_sink<std::mutex>; | using null_sink_mt = null_sink<details::null_mutex>; | ||||||
| using null_sink_st = null_sink<details::null_mutex>; | using null_sink_st = null_sink<details::null_mutex>; | ||||||
|  |  | ||||||
| } // namespace sinks | } // namespace sinks | ||||||
|  |  | ||||||
| template<typename Factory = default_factory> | template<typename Factory = spdlog::synchronous_factory> | ||||||
| inline std::shared_ptr<logger> null_logger_mt(const std::string &logger_name) | inline std::shared_ptr<logger> null_logger_mt(const std::string &logger_name) | ||||||
| { | { | ||||||
|     auto null_logger = Factory::template create<sinks::null_sink_mt>(logger_name); |     auto null_logger = Factory::template create<sinks::null_sink_mt>(logger_name); | ||||||
| @@ -38,7 +33,7 @@ inline std::shared_ptr<logger> null_logger_mt(const std::string &logger_name) | |||||||
|     return null_logger; |     return null_logger; | ||||||
| } | } | ||||||
|  |  | ||||||
| template<typename Factory = default_factory> | template<typename Factory = spdlog::synchronous_factory> | ||||||
| inline std::shared_ptr<logger> null_logger_st(const std::string &logger_name) | inline std::shared_ptr<logger> null_logger_st(const std::string &logger_name) | ||||||
| { | { | ||||||
|     auto null_logger = Factory::template create<sinks::null_sink_st>(logger_name); |     auto null_logger = Factory::template create<sinks::null_sink_st>(logger_name); | ||||||
|   | |||||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user