update spdlog submodule
This commit is contained in:
		
							parent
							
								
									2c7b3f8cf5
								
							
						
					
					
						commit
						c5f3d6354d
					
				
					 164 changed files with 1 additions and 49817 deletions
				
			
		
							
								
								
									
										1
									
								
								Dependencies/spdlog
									
										
									
									
										vendored
									
									
										Submodule
									
								
							
							
						
						
									
										1
									
								
								Dependencies/spdlog
									
										
									
									
										vendored
									
									
										Submodule
									
								
							|  | @ -0,0 +1 @@ | |||
| Subproject commit 6fa36017cfd5731d617e1a934f0e5ea9c4445b13 | ||||
							
								
								
									
										109
									
								
								Dependencies/spdlog/.clang-format
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										109
									
								
								Dependencies/spdlog/.clang-format
									
										
									
									
										vendored
									
									
								
							|  | @ -1,109 +0,0 @@ | |||
| --- | ||||
| Language:        Cpp | ||||
| # BasedOnStyle:  LLVM | ||||
| AccessModifierOffset: -4 | ||||
| AlignAfterOpenBracket: DontAlign | ||||
| AlignConsecutiveAssignments: false | ||||
| AlignConsecutiveDeclarations: false | ||||
| AlignEscapedNewlines: Right | ||||
| AlignOperands:   true | ||||
| AlignTrailingComments: true | ||||
| AllowAllParametersOfDeclarationOnNextLine: true | ||||
| AllowShortBlocksOnASingleLine: true | ||||
| AllowShortCaseLabelsOnASingleLine: false | ||||
| AllowShortFunctionsOnASingleLine: Empty | ||||
| AllowShortIfStatementsOnASingleLine: false | ||||
| AllowShortLoopsOnASingleLine: false | ||||
| AlwaysBreakAfterDefinitionReturnType: None | ||||
| AlwaysBreakAfterReturnType: None | ||||
| AlwaysBreakBeforeMultilineStrings: false | ||||
| AlwaysBreakTemplateDeclarations: true | ||||
| BinPackArguments: true | ||||
| BinPackParameters: true | ||||
| BraceWrapping:      | ||||
|   AfterClass:      true | ||||
|   AfterControlStatement: true | ||||
|   AfterEnum:       true | ||||
|   AfterFunction:   true | ||||
|   AfterNamespace:  false | ||||
|   AfterObjCDeclaration: true | ||||
|   AfterStruct:     true | ||||
|   AfterUnion:      true | ||||
|   BeforeCatch:     true | ||||
|   BeforeElse:      true | ||||
|   IndentBraces:    false | ||||
|   SplitEmptyFunction: false | ||||
|   SplitEmptyRecord: false | ||||
|   SplitEmptyNamespace: false | ||||
| BreakBeforeBinaryOperators: None | ||||
| BreakBeforeBraces: Custom | ||||
| BreakBeforeInheritanceComma: false | ||||
| BreakBeforeTernaryOperators: true | ||||
| BreakConstructorInitializersBeforeComma: true | ||||
| BreakConstructorInitializers: BeforeColon | ||||
| BreakAfterJavaFieldAnnotations: false | ||||
| BreakStringLiterals: true | ||||
| ColumnLimit:     140 | ||||
| CommentPragmas:  '^ IWYU pragma:' | ||||
| CompactNamespaces:  false | ||||
| ConstructorInitializerAllOnOneLineOrOnePerLine: false | ||||
| ConstructorInitializerIndentWidth: 4 | ||||
| ContinuationIndentWidth: 4 | ||||
| Cpp11BracedListStyle: true | ||||
| DerivePointerAlignment: false | ||||
| DisableFormat:   false | ||||
| ExperimentalAutoDetectBinPacking: false | ||||
| FixNamespaceComments: true | ||||
| ForEachMacros:    | ||||
|   - foreach | ||||
|   - Q_FOREACH | ||||
|   - BOOST_FOREACH | ||||
| IncludeCategories:  | ||||
|   - Regex:           '^"(llvm|llvm-c|clang|clang-c)/' | ||||
|     Priority:        2 | ||||
|   - Regex:           '^(<|"(gtest|gmock|isl|json)/)' | ||||
|     Priority:        3 | ||||
|   - Regex:           '.*' | ||||
|     Priority:        1 | ||||
| IncludeIsMainRegex: '(Test)?$' | ||||
| IndentCaseLabels: false | ||||
| IndentWidth:     4 | ||||
| IndentWrappedFunctionNames: false | ||||
| JavaScriptQuotes: Leave | ||||
| JavaScriptWrapImports: true | ||||
| KeepEmptyLinesAtTheStartOfBlocks: true | ||||
| MacroBlockBegin: '' | ||||
| MacroBlockEnd:   '' | ||||
| MaxEmptyLinesToKeep: 1 | ||||
| NamespaceIndentation: None | ||||
| ObjCBlockIndentWidth: 2 | ||||
| ObjCSpaceAfterProperty: false | ||||
| ObjCSpaceBeforeProtocolList: true | ||||
| PenaltyBreakAssignment: 2 | ||||
| PenaltyBreakBeforeFirstCallParameter: 19 | ||||
| PenaltyBreakComment: 300 | ||||
| PenaltyBreakFirstLessLess: 120 | ||||
| PenaltyBreakString: 1000 | ||||
| PenaltyExcessCharacter: 1000000 | ||||
| PenaltyReturnTypeOnItsOwnLine: 60 | ||||
| PointerAlignment: Right | ||||
| ReflowComments:  true | ||||
| SortIncludes:    false | ||||
| SortUsingDeclarations: true | ||||
| SpaceAfterCStyleCast: false | ||||
| SpaceAfterTemplateKeyword: false | ||||
| SpaceBeforeAssignmentOperators: true | ||||
| SpaceBeforeParens: ControlStatements | ||||
| SpaceInEmptyParentheses: false | ||||
| SpacesBeforeTrailingComments: 1 | ||||
| SpacesInAngles:  false | ||||
| SpacesInContainerLiterals: true | ||||
| SpacesInCStyleCastParentheses: false | ||||
| SpacesInParentheses: false | ||||
| SpacesInSquareBrackets: false | ||||
| Standard:        Cpp11 | ||||
| TabWidth:        8 | ||||
| UseTab:          Never | ||||
| IndentPPDirectives: AfterHash | ||||
| ... | ||||
| 
 | ||||
							
								
								
									
										54
									
								
								Dependencies/spdlog/.clang-tidy
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										54
									
								
								Dependencies/spdlog/.clang-tidy
									
										
									
									
										vendored
									
									
								
							|  | @ -1,54 +0,0 @@ | |||
| Checks: 'cppcoreguidelines-*, | ||||
| performance-*, | ||||
| modernize-*, | ||||
| google-*, | ||||
| misc-* | ||||
| cert-*, | ||||
| readability-*, | ||||
| clang-analyzer-*, | ||||
| -performance-unnecessary-value-param, | ||||
| -modernize-use-trailing-return-type, | ||||
| -google-runtime-references, | ||||
| -misc-non-private-member-variables-in-classes, | ||||
| -readability-braces-around-statements, | ||||
| -google-readability-braces-around-statements, | ||||
| -cppcoreguidelines-avoid-magic-numbers, | ||||
| -readability-magic-numbers, | ||||
| -readability-magic-numbers, | ||||
| -cppcoreguidelines-pro-type-vararg, | ||||
| -cppcoreguidelines-pro-bounds-pointer-arithmetic, | ||||
| -cppcoreguidelines-avoid-c-arrays, | ||||
| -modernize-avoid-c-arrays, | ||||
| -cppcoreguidelines-pro-bounds-array-to-pointer-decay, | ||||
| -readability-named-parameter, | ||||
| -cert-env33-c | ||||
| ' | ||||
| 
 | ||||
| 
 | ||||
| WarningsAsErrors: '' | ||||
| HeaderFilterRegex: '*spdlog/[^f].*' | ||||
| AnalyzeTemporaryDtors: false | ||||
| FormatStyle:     none | ||||
| 
 | ||||
| CheckOptions:     | ||||
|   - key:             google-readability-braces-around-statements.ShortStatementLines | ||||
|     value:           '1' | ||||
|   - key:             google-readability-function-size.StatementThreshold | ||||
|     value:           '800' | ||||
|   - key:             google-readability-namespace-comments.ShortNamespaceLines | ||||
|     value:           '10' | ||||
|   - key:             google-readability-namespace-comments.SpacesBeforeComments | ||||
|     value:           '2' | ||||
|   - key:             modernize-loop-convert.MaxCopySize | ||||
|     value:           '16' | ||||
|   - key:             modernize-loop-convert.MinConfidence | ||||
|     value:           reasonable | ||||
|   - key:             modernize-loop-convert.NamingStyle | ||||
|     value:           CamelCase | ||||
|   - key:             modernize-pass-by-value.IncludeStyle | ||||
|     value:           llvm | ||||
|   - key:             modernize-replace-auto-ptr.IncludeStyle | ||||
|     value:           llvm | ||||
|   - key:             modernize-use-nullptr.NullMacros | ||||
|     value:           'NULL' | ||||
| 
 | ||||
							
								
								
									
										1
									
								
								Dependencies/spdlog/.gitattributes
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								Dependencies/spdlog/.gitattributes
									
										
									
									
										vendored
									
									
								
							|  | @ -1 +0,0 @@ | |||
| * text=false | ||||
							
								
								
									
										92
									
								
								Dependencies/spdlog/.gitignore
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										92
									
								
								Dependencies/spdlog/.gitignore
									
										
									
									
										vendored
									
									
								
							|  | @ -1,92 +0,0 @@ | |||
| # Auto generated files | ||||
| [Dd]ebug/ | ||||
| [Rr]elease/ | ||||
| build/* | ||||
| *.slo | ||||
| *.lo | ||||
| *.o | ||||
| *.obj | ||||
| *.suo | ||||
| *.tlog | ||||
| *.ilk | ||||
| *.log | ||||
| *.pdb | ||||
| *.idb | ||||
| *.iobj | ||||
| *.ipdb | ||||
| *.opensdf | ||||
| *.sdf | ||||
| 
 | ||||
| # Compiled Dynamic libraries | ||||
| *.so | ||||
| *.dylib | ||||
| *.dll | ||||
| 
 | ||||
| # Compiled Static libraries | ||||
| *.lai | ||||
| *.la | ||||
| *.a | ||||
| *.lib | ||||
| 
 | ||||
| # Executables | ||||
| *.exe | ||||
| *.out | ||||
| *.app | ||||
| 
 | ||||
| # Codelite | ||||
| .codelite | ||||
| 
 | ||||
| # KDevelop | ||||
| *.kdev4 | ||||
| 
 | ||||
| # .orig files | ||||
| *.orig | ||||
| 
 | ||||
| # example  files | ||||
| example/* | ||||
| !example/example.cpp | ||||
| !example/bench.cpp | ||||
| !example/utils.h | ||||
| !example/Makefile* | ||||
| !example/example.sln | ||||
| !example/example.vcxproj | ||||
| !example/CMakeLists.txt | ||||
| !example/meson.build | ||||
| !example/multisink.cpp | ||||
| !example/jni | ||||
| 
 | ||||
| # generated files | ||||
| generated | ||||
| version.rc | ||||
| 
 | ||||
| # Cmake | ||||
| CMakeCache.txt | ||||
| CMakeFiles | ||||
| CMakeScripts | ||||
| Makefile | ||||
| cmake_install.cmake | ||||
| install_manifest.txt | ||||
| /tests/tests.VC.VC.opendb | ||||
| /tests/tests.VC.db | ||||
| /tests/tests | ||||
| /tests/logs/* | ||||
| spdlogConfig.cmake | ||||
| spdlogConfigVersion.cmake | ||||
| 
 | ||||
| # idea | ||||
| .idea/ | ||||
| cmake-build-*/ | ||||
| *.db | ||||
| *.ipch | ||||
| *.filters | ||||
| *.db-wal | ||||
| *.opendb | ||||
| *.db-shm | ||||
| *.vcxproj | ||||
| *.tcl | ||||
| *.user | ||||
| *.sln | ||||
| 
 | ||||
| # macos | ||||
| *.DS_store | ||||
| *.xcodeproj/ | ||||
							
								
								
									
										155
									
								
								Dependencies/spdlog/.travis.yml
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										155
									
								
								Dependencies/spdlog/.travis.yml
									
										
									
									
										vendored
									
									
								
							|  | @ -1,155 +0,0 @@ | |||
| # Adapted from various sources, including: | ||||
| # - Louis Dionne's Hana: https://github.com/ldionne/hana | ||||
| # - Paul Fultz II's FIT: https://github.com/pfultz2/Fit | ||||
| # - Eric Niebler's range-v3: https://github.com/ericniebler/range-v3 | ||||
| sudo: required | ||||
| language: cpp | ||||
| 
 | ||||
| # gcc 4.9 | ||||
| addons: &gcc49 | ||||
|   apt: | ||||
|     packages: | ||||
|       - g++-4.9 | ||||
|     sources: | ||||
|       - ubuntu-toolchain-r-test | ||||
| 
 | ||||
| # gcc 7.0 | ||||
| addons: &gcc7 | ||||
|   apt: | ||||
|     packages: | ||||
|       - g++-7 | ||||
|     sources: | ||||
|       - ubuntu-toolchain-r-test | ||||
| 
 | ||||
| 
 | ||||
| # gcc 9.0 | ||||
| addons: &gcc9 | ||||
|   apt: | ||||
|     packages: | ||||
|       - g++-9 | ||||
|     sources: | ||||
|       - ubuntu-toolchain-r-test | ||||
|        | ||||
| # gcc 11.0 | ||||
| addons: &gcc11 | ||||
|   apt: | ||||
|     packages: | ||||
|       - g++-11 | ||||
|     sources: | ||||
|       - ubuntu-toolchain-r-test | ||||
| 
 | ||||
| 
 | ||||
| # Clang 3.5 | ||||
| addons: &clang35 | ||||
|   apt: | ||||
|     packages: | ||||
|       - clang-3.5 | ||||
|     sources: | ||||
|       - ubuntu-toolchain-r-test | ||||
|       - llvm-toolchain-precise-3.5 | ||||
|        | ||||
| 
 | ||||
| addons: &clang10 | ||||
|   apt: | ||||
|     packages: | ||||
|       - clang-10 | ||||
|       - lldb-10 | ||||
|       - lld-10 | ||||
|     sources: | ||||
|       - sourceline: "deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-10 main" | ||||
|         key_url: "https://apt.llvm.org/llvm-snapshot.gpg.key" | ||||
|          | ||||
| addons: &clang12 | ||||
|   apt: | ||||
|     packages: | ||||
|       - clang-12 | ||||
|       - lldb-12 | ||||
|       - lld-12 | ||||
|     sources: | ||||
|       - sourceline: "deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-12 main" | ||||
|         key_url: "https://apt.llvm.org/llvm-snapshot.gpg.key"         | ||||
| 
 | ||||
| env: | ||||
|   global: | ||||
|     - BUILD_EXAMPLE='ON' | ||||
|      | ||||
| matrix: | ||||
|   include: | ||||
|     # Test gcc-4.9: C++11, Build=Release | ||||
|     - env: GCC_VERSION=4.9 BUILD_TYPE=Release CPP=11 BUILD_EXAMPLE='OFF' | ||||
|       os: linux | ||||
|       addons: *gcc49 | ||||
|        | ||||
|     # Test gcc-7: C++11, Build=Release | ||||
|     - env: GCC_VERSION=7 BUILD_TYPE=Release CPP=11 | ||||
|       os: linux | ||||
|       addons: *gcc7 | ||||
|        | ||||
|     # Test gcc-9: C++17, Build=Release | ||||
|     - env: GCC_VERSION=9 BUILD_TYPE=Release CPP=17 | ||||
|       os: linux | ||||
|       addons: *gcc9 | ||||
| 
 | ||||
|     # Test gcc-11.0: C++20, Build=Debug | ||||
|     - env: GCC_VERSION=11 BUILD_TYPE=Debug CPP=20 ASAN=Off | ||||
|       os: linux | ||||
|       dist: bionic | ||||
|       addons: *gcc11 | ||||
|        | ||||
|     # Test clang-3.5: C++11, Build=Release | ||||
|     - env: CLANG_VERSION=3.5 BUILD_TYPE=Release CPP=11 | ||||
|       os: linux | ||||
|       addons: *clang35 | ||||
| 
 | ||||
|     # Text osx | ||||
|     - env: BUILD_TYPE=Release CPP=11 ASAN=Off TSAN=Off | ||||
|       os: osx | ||||
| 
 | ||||
|     # Test clang-10.0: C++11, Build=Release | ||||
|     - env: CLANG_VERSION=10 BUILD_TYPE=Release CPP=11 ASAN=On | ||||
|       os: linux | ||||
|       dist: bionic | ||||
|       addons: *clang10 | ||||
|        | ||||
|     # Test clang-10.0: C++17, Build=Debug | ||||
|     - env: CLANG_VERSION=10 BUILD_TYPE=Debug CPP=17 ASAN=Off | ||||
|       os: linux | ||||
|       dist: bionic | ||||
|       addons: *clang10 | ||||
|        | ||||
|              | ||||
|     # Test clang-12.0: C++17, Build=Debug | ||||
|     - env: CLANG_VERSION=12 BUILD_TYPE=Debug CPP=17 ASAN=Off | ||||
|       os: linux | ||||
|       dist: bionic | ||||
|       addons: *clang12 | ||||
|            | ||||
|                          | ||||
| before_script: | ||||
|   - 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 [[ "$TRAVIS_OS_NAME" == "osx" ]]; then export CXX="clang++" CC="clang"; fi | ||||
|   - which $CXX | ||||
|   - which $CC | ||||
|   - $CXX --version | ||||
|   - cmake --version | ||||
| 
 | ||||
| script: | ||||
|   - cd ${TRAVIS_BUILD_DIR} | ||||
|   - mkdir -p build && cd build | ||||
|   - | | ||||
|     cmake .. \ | ||||
|       --warn-uninitialized \ | ||||
|       -DCMAKE_BUILD_TYPE=$BUILD_TYPE \ | ||||
|       -DCMAKE_CXX_STANDARD=$CPP \ | ||||
|       -DSPDLOG_BUILD_EXAMPLE=$BUILD_EXAMPLE \ | ||||
|       -DSPDLOG_BUILD_EXAMPLE_HO=$BUILD_EXAMPLE \ | ||||
|       -DSPDLOG_BUILD_WARNINGS=ON \ | ||||
|       -DSPDLOG_BUILD_BENCH=OFF \ | ||||
|       -DSPDLOG_BUILD_TESTS=ON \ | ||||
|       -DSPDLOG_BUILD_TESTS_HO=OFF \ | ||||
|       -DSPDLOG_SANITIZE_ADDRESS=$ASAN  | ||||
|        | ||||
|   - make VERBOSE=1 -j2 | ||||
|   - ctest -j2 --output-on-failure | ||||
|    | ||||
							
								
								
									
										323
									
								
								Dependencies/spdlog/CMakeLists.txt
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										323
									
								
								Dependencies/spdlog/CMakeLists.txt
									
										
									
									
										vendored
									
									
								
							|  | @ -1,323 +0,0 @@ | |||
| # Copyright(c) 2019 spdlog authors Distributed under the MIT License (http://opensource.org/licenses/MIT) | ||||
| 
 | ||||
| cmake_minimum_required(VERSION 3.10...3.21) | ||||
| 
 | ||||
| # --------------------------------------------------------------------------------------- | ||||
| # Start spdlog project | ||||
| # --------------------------------------------------------------------------------------- | ||||
| include(cmake/utils.cmake) | ||||
| include(cmake/ide.cmake) | ||||
| 
 | ||||
| spdlog_extract_version() | ||||
| 
 | ||||
| project(spdlog VERSION ${SPDLOG_VERSION} LANGUAGES CXX) | ||||
| message(STATUS "Build spdlog: ${SPDLOG_VERSION}") | ||||
| 
 | ||||
| include(GNUInstallDirs) | ||||
| 
 | ||||
| # --------------------------------------------------------------------------------------- | ||||
| # Set default build to release | ||||
| # --------------------------------------------------------------------------------------- | ||||
| if(NOT CMAKE_BUILD_TYPE) | ||||
|     set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Choose Release or Debug" FORCE) | ||||
| endif() | ||||
| 
 | ||||
| # --------------------------------------------------------------------------------------- | ||||
| # Compiler config | ||||
| # --------------------------------------------------------------------------------------- | ||||
| if(NOT CMAKE_CXX_STANDARD) | ||||
|     set(CMAKE_CXX_STANDARD 11) | ||||
|     set(CMAKE_CXX_STANDARD_REQUIRED ON) | ||||
| endif() | ||||
| 
 | ||||
| # make sure __cplusplus is defined when using msvc and enable parallel build | ||||
| if(MSVC) | ||||
|     string(APPEND CMAKE_CXX_FLAGS " /Zc:__cplusplus /MP") | ||||
| endif() | ||||
| 
 | ||||
| set(CMAKE_CXX_EXTENSIONS OFF) | ||||
| 
 | ||||
| if(CMAKE_SYSTEM_NAME MATCHES "CYGWIN" OR CMAKE_SYSTEM_NAME MATCHES "MSYS") | ||||
|     set(CMAKE_CXX_EXTENSIONS ON) | ||||
| endif() | ||||
| 
 | ||||
| # --------------------------------------------------------------------------------------- | ||||
| # Set SPDLOG_MASTER_PROJECT to ON if we are building spdlog | ||||
| # --------------------------------------------------------------------------------------- | ||||
| # Check if spdlog is being used directly or via add_subdirectory, but allow overriding | ||||
| if(NOT DEFINED SPDLOG_MASTER_PROJECT) | ||||
|     if(CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR) | ||||
|         set(SPDLOG_MASTER_PROJECT ON) | ||||
|     else() | ||||
|         set(SPDLOG_MASTER_PROJECT OFF) | ||||
|     endif() | ||||
| endif() | ||||
| 
 | ||||
| option(SPDLOG_BUILD_ALL "Build all artifacts" OFF) | ||||
| 
 | ||||
| # build shared option | ||||
| option(SPDLOG_BUILD_SHARED "Build shared library" OFF) | ||||
| 
 | ||||
| # precompiled headers option | ||||
| option(SPDLOG_ENABLE_PCH "Build static or shared library using precompiled header to speed up compilation time" OFF) | ||||
| 
 | ||||
| # example options | ||||
| option(SPDLOG_BUILD_EXAMPLE "Build example" ${SPDLOG_MASTER_PROJECT}) | ||||
| option(SPDLOG_BUILD_EXAMPLE_HO "Build header only example" OFF) | ||||
| 
 | ||||
| # testing options | ||||
| option(SPDLOG_BUILD_TESTS "Build tests" OFF) | ||||
| 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) | ||||
| 
 | ||||
| # warning options | ||||
| option(SPDLOG_BUILD_WARNINGS "Enable compiler warnings" OFF) | ||||
| 
 | ||||
| # install options | ||||
| option(SPDLOG_INSTALL "Generate the install target" ${SPDLOG_MASTER_PROJECT}) | ||||
| option(SPDLOG_USE_STD_FORMAT "Use std::format instead of fmt library. No compile-time format string checking." OFF) | ||||
| option(SPDLOG_FMT_EXTERNAL "Use external fmt library instead of bundled" OFF) | ||||
| option(SPDLOG_FMT_EXTERNAL_HO "Use external fmt header-only library instead of bundled" OFF) | ||||
| option(SPDLOG_NO_EXCEPTIONS "Compile with -fno-exceptions. Call abort() on any spdlog exceptions" OFF) | ||||
| 
 | ||||
| if(SPDLOG_FMT_EXTERNAL AND SPDLOG_FMT_EXTERNAL_HO) | ||||
|     message(FATAL_ERROR "SPDLOG_FMT_EXTERNAL and SPDLOG_FMT_EXTERNAL_HO are mutually exclusive") | ||||
| endif() | ||||
| 
 | ||||
| if(SPDLOG_USE_STD_FORMAT AND SPDLOG_FMT_EXTERNAL_HO) | ||||
|     message(FATAL_ERROR "SPDLOG_USE_STD_FORMAT and SPDLOG_FMT_EXTERNAL_HO are mutually exclusive") | ||||
| endif() | ||||
| 
 | ||||
| if(SPDLOG_USE_STD_FORMAT AND SPDLOG_FMT_EXTERNAL) | ||||
|     message(FATAL_ERROR "SPDLOG_USE_STD_FORMAT and SPDLOG_FMT_EXTERNAL are mutually exclusive") | ||||
| endif() | ||||
| 
 | ||||
| # misc tweakme options | ||||
| if(WIN32) | ||||
|     option(SPDLOG_WCHAR_SUPPORT "Support wchar api" OFF) | ||||
|     option(SPDLOG_WCHAR_FILENAMES "Support wchar filenames" OFF) | ||||
| else() | ||||
|     set(SPDLOG_WCHAR_SUPPORT OFF CACHE BOOL "non supported option" FORCE) | ||||
|     set(SPDLOG_WCHAR_FILENAMES OFF CACHE BOOL "non supported option" FORCE) | ||||
| endif() | ||||
| 
 | ||||
| if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux") | ||||
|     option(SPDLOG_CLOCK_COARSE "Use CLOCK_REALTIME_COARSE instead of the regular clock," OFF) | ||||
| else() | ||||
|     set(SPDLOG_CLOCK_COARSE OFF CACHE BOOL "non supported option" FORCE) | ||||
| endif() | ||||
| 
 | ||||
| option(SPDLOG_PREVENT_CHILD_FD "Prevent from child processes to inherit log file descriptors" OFF) | ||||
| option(SPDLOG_NO_THREAD_ID "prevent spdlog from querying the thread id on each log call if thread id is not needed" OFF) | ||||
| option(SPDLOG_NO_TLS "prevent spdlog from using thread local storage" OFF) | ||||
| option( | ||||
|     SPDLOG_NO_ATOMIC_LEVELS | ||||
|     "prevent spdlog from using of std::atomic log levels (use only if your code never modifies log levels concurrently" | ||||
|     OFF) | ||||
| option(SPDLOG_DISABLE_DEFAULT_LOGGER "Disable default logger creation" OFF) | ||||
| 
 | ||||
| # clang-tidy | ||||
| if(${CMAKE_VERSION} VERSION_GREATER "3.5") | ||||
|     option(SPDLOG_TIDY "run clang-tidy" OFF) | ||||
| endif() | ||||
| 
 | ||||
| if(SPDLOG_TIDY) | ||||
|     set(CMAKE_CXX_CLANG_TIDY "clang-tidy") | ||||
|     set(CMAKE_EXPORT_COMPILE_COMMANDS ON) | ||||
|     message(STATUS "Enabled clang-tidy") | ||||
| endif() | ||||
| 
 | ||||
| find_package(Threads REQUIRED) | ||||
| 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/color_sinks.cpp src/file_sinks.cpp src/async.cpp src/cfg.cpp) | ||||
| 
 | ||||
| if(NOT SPDLOG_USE_STD_FORMAT AND NOT SPDLOG_FMT_EXTERNAL AND NOT SPDLOG_FMT_EXTERNAL_HO) | ||||
|     list(APPEND SPDLOG_SRCS src/fmt.cpp) | ||||
| endif() | ||||
| 
 | ||||
| if(SPDLOG_BUILD_SHARED OR BUILD_SHARED_LIBS) | ||||
|     if(WIN32) | ||||
|         configure_file(${CMAKE_CURRENT_SOURCE_DIR}/cmake/version.rc.in ${CMAKE_CURRENT_BINARY_DIR}/version.rc @ONLY) | ||||
|         list(APPEND SPDLOG_SRCS ${CMAKE_CURRENT_BINARY_DIR}/version.rc) | ||||
|     endif() | ||||
|     add_library(spdlog SHARED ${SPDLOG_SRCS} ${SPDLOG_ALL_HEADERS}) | ||||
|     target_compile_definitions(spdlog PUBLIC SPDLOG_SHARED_LIB) | ||||
|     if(MSVC) | ||||
|         target_compile_options(spdlog PUBLIC $<$<AND:$<CXX_COMPILER_ID:MSVC>,$<NOT:$<COMPILE_LANGUAGE:CUDA>>>:/wd4251 | ||||
|                                              /wd4275>) | ||||
|     endif() | ||||
|     if(NOT SPDLOG_USE_STD_FORMAT AND NOT SPDLOG_FMT_EXTERNAL AND NOT SPDLOG_FMT_EXTERNAL_HO) | ||||
|         target_compile_definitions(spdlog PRIVATE FMT_EXPORT PUBLIC FMT_SHARED) | ||||
|     endif() | ||||
| else() | ||||
|     add_library(spdlog STATIC ${SPDLOG_SRCS} ${SPDLOG_ALL_HEADERS}) | ||||
| endif() | ||||
| 
 | ||||
| add_library(spdlog::spdlog ALIAS spdlog) | ||||
| 
 | ||||
| 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) | ||||
| 
 | ||||
| if(COMMAND target_precompile_headers AND SPDLOG_ENABLE_PCH) | ||||
|     configure_file(${CMAKE_CURRENT_SOURCE_DIR}/cmake/pch.h.in ${PROJECT_BINARY_DIR}/spdlog_pch.h @ONLY) | ||||
|     target_precompile_headers(spdlog PRIVATE ${PROJECT_BINARY_DIR}/spdlog_pch.h) | ||||
| endif() | ||||
| 
 | ||||
| # --------------------------------------------------------------------------------------- | ||||
| # 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 external fmt | ||||
| # --------------------------------------------------------------------------------------- | ||||
| if(SPDLOG_FMT_EXTERNAL OR SPDLOG_FMT_EXTERNAL_HO) | ||||
|     if(NOT TARGET fmt::fmt) | ||||
|         find_package(fmt CONFIG REQUIRED) | ||||
|     endif() | ||||
|     target_compile_definitions(spdlog PUBLIC SPDLOG_FMT_EXTERNAL) | ||||
|     target_compile_definitions(spdlog_header_only INTERFACE SPDLOG_FMT_EXTERNAL) | ||||
| 
 | ||||
|     # use external fmt-header-nly | ||||
|     if(SPDLOG_FMT_EXTERNAL_HO) | ||||
|         target_link_libraries(spdlog PUBLIC fmt::fmt-header-only) | ||||
|         target_link_libraries(spdlog_header_only INTERFACE fmt::fmt-header-only) | ||||
|     else() # use external compile fmt | ||||
|         target_link_libraries(spdlog PUBLIC fmt::fmt) | ||||
|         target_link_libraries(spdlog_header_only INTERFACE fmt::fmt) | ||||
|     endif() | ||||
| 
 | ||||
|     set(PKG_CONFIG_REQUIRES fmt) # add dependency to pkg-config | ||||
| endif() | ||||
| 
 | ||||
| # --------------------------------------------------------------------------------------- | ||||
| # Add required libraries for Android CMake build | ||||
| # --------------------------------------------------------------------------------------- | ||||
| if(ANDROID) | ||||
|     target_link_libraries(spdlog PUBLIC log) | ||||
|     target_link_libraries(spdlog_header_only INTERFACE log) | ||||
| endif() | ||||
| 
 | ||||
| # --------------------------------------------------------------------------------------- | ||||
| # Misc definitions according to tweak options | ||||
| # --------------------------------------------------------------------------------------- | ||||
| set(SPDLOG_WCHAR_TO_UTF8_SUPPORT ${SPDLOG_WCHAR_SUPPORT}) | ||||
| foreach( | ||||
|     SPDLOG_OPTION | ||||
|     SPDLOG_WCHAR_TO_UTF8_SUPPORT | ||||
|     SPDLOG_WCHAR_FILENAMES | ||||
|     SPDLOG_NO_EXCEPTIONS | ||||
|     SPDLOG_CLOCK_COARSE | ||||
|     SPDLOG_PREVENT_CHILD_FD | ||||
|     SPDLOG_NO_THREAD_ID | ||||
|     SPDLOG_NO_TLS | ||||
|     SPDLOG_NO_ATOMIC_LEVELS | ||||
|     SPDLOG_DISABLE_DEFAULT_LOGGER | ||||
|     SPDLOG_USE_STD_FORMAT) | ||||
|     if(${SPDLOG_OPTION}) | ||||
|         target_compile_definitions(spdlog PUBLIC ${SPDLOG_OPTION}) | ||||
|         target_compile_definitions(spdlog_header_only INTERFACE ${SPDLOG_OPTION}) | ||||
|     endif() | ||||
| endforeach() | ||||
| 
 | ||||
| if(SPDLOG_NO_EXCEPTIONS AND NOT MSVC) | ||||
|     target_compile_options(spdlog PRIVATE -fno-exceptions) | ||||
| endif() | ||||
| 
 | ||||
| # --------------------------------------------------------------------------------------- | ||||
| # Build binaries | ||||
| # --------------------------------------------------------------------------------------- | ||||
| if(SPDLOG_BUILD_EXAMPLE OR SPDLOG_BUILD_EXAMPLE_HO OR SPDLOG_BUILD_ALL) | ||||
|     message(STATUS "Generating example(s)") | ||||
|     add_subdirectory(example) | ||||
|     spdlog_enable_warnings(example) | ||||
|     if(SPDLOG_BUILD_EXAMPLE_HO) | ||||
|         spdlog_enable_warnings(example_header_only) | ||||
|     endif() | ||||
| endif() | ||||
| 
 | ||||
| if(SPDLOG_BUILD_TESTS OR SPDLOG_BUILD_TESTS_HO OR SPDLOG_BUILD_ALL) | ||||
|     message(STATUS "Generating tests") | ||||
|     enable_testing() | ||||
|     add_subdirectory(tests) | ||||
| endif() | ||||
| 
 | ||||
| if(SPDLOG_BUILD_BENCH OR SPDLOG_BUILD_ALL) | ||||
|     message(STATUS "Generating benchmarks") | ||||
|     add_subdirectory(bench) | ||||
| endif() | ||||
| 
 | ||||
| # --------------------------------------------------------------------------------------- | ||||
| # Install | ||||
| # --------------------------------------------------------------------------------------- | ||||
| if(SPDLOG_INSTALL) | ||||
|     message(STATUS "Generating install") | ||||
|     set(project_config_in "${CMAKE_CURRENT_LIST_DIR}/cmake/spdlogConfig.cmake.in") | ||||
|     set(project_config_out "${CMAKE_CURRENT_BINARY_DIR}/spdlogConfig.cmake") | ||||
|     set(config_targets_file "spdlogConfigTargets.cmake") | ||||
|     set(version_config_file "${CMAKE_CURRENT_BINARY_DIR}/spdlogConfigVersion.cmake") | ||||
|     set(export_dest_dir "${CMAKE_INSTALL_LIBDIR}/cmake/spdlog") | ||||
|     set(pkgconfig_install_dir "${CMAKE_INSTALL_LIBDIR}/pkgconfig") | ||||
|     set(pkg_config "${CMAKE_BINARY_DIR}/${PROJECT_NAME}.pc") | ||||
| 
 | ||||
|     # --------------------------------------------------------------------------------------- | ||||
|     # Include files | ||||
|     # --------------------------------------------------------------------------------------- | ||||
|     install(DIRECTORY include/ DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}" PATTERN "fmt/bundled" EXCLUDE) | ||||
|     install( | ||||
|         TARGETS spdlog spdlog_header_only | ||||
|         EXPORT spdlog | ||||
|         LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} | ||||
|         ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} | ||||
|         RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) | ||||
| 
 | ||||
|     if(NOT SPDLOG_USE_STD_FORMAT AND NOT SPDLOG_FMT_EXTERNAL AND NOT SPDLOG_FMT_EXTERNAL_HO) | ||||
|         install(DIRECTORY include/${PROJECT_NAME}/fmt/bundled/ | ||||
|                 DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME}/fmt/bundled/") | ||||
|     endif() | ||||
| 
 | ||||
|     # --------------------------------------------------------------------------------------- | ||||
|     # Install pkg-config file | ||||
|     # --------------------------------------------------------------------------------------- | ||||
|     get_target_property(PKG_CONFIG_DEFINES spdlog INTERFACE_COMPILE_DEFINITIONS) | ||||
|     string(REPLACE ";" " -D" PKG_CONFIG_DEFINES "${PKG_CONFIG_DEFINES}") | ||||
|     string(CONCAT PKG_CONFIG_DEFINES "-D" "${PKG_CONFIG_DEFINES}") | ||||
|     configure_file("cmake/${PROJECT_NAME}.pc.in" "${pkg_config}" @ONLY) | ||||
|     install(FILES "${pkg_config}" DESTINATION "${pkgconfig_install_dir}") | ||||
| 
 | ||||
|     # --------------------------------------------------------------------------------------- | ||||
|     # Install CMake config files | ||||
|     # --------------------------------------------------------------------------------------- | ||||
|     install(EXPORT spdlog DESTINATION ${export_dest_dir} NAMESPACE spdlog:: FILE ${config_targets_file}) | ||||
| 
 | ||||
|     include(CMakePackageConfigHelpers) | ||||
|     configure_package_config_file("${project_config_in}" "${project_config_out}" | ||||
|         INSTALL_DESTINATION ${export_dest_dir}) | ||||
| 
 | ||||
|     write_basic_package_version_file("${version_config_file}" COMPATIBILITY SameMajorVersion) | ||||
|     install(FILES "${project_config_out}" "${version_config_file}" DESTINATION "${export_dest_dir}") | ||||
| 
 | ||||
|     # --------------------------------------------------------------------------------------- | ||||
|     # Support creation of installable packages | ||||
|     # --------------------------------------------------------------------------------------- | ||||
|     include(cmake/spdlogCPack.cmake) | ||||
| endif() | ||||
							
								
								
									
										24
									
								
								Dependencies/spdlog/INSTALL
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										24
									
								
								Dependencies/spdlog/INSTALL
									
										
									
									
										vendored
									
									
								
							|  | @ -1,24 +0,0 @@ | |||
| Header only version: | ||||
| ================================================================== | ||||
| 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: | ||||
| gcc 4.8.1 and above | ||||
| clang 3.5 | ||||
| Visual Studio 2013 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
							
								
								
									
										26
									
								
								Dependencies/spdlog/LICENSE
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										26
									
								
								Dependencies/spdlog/LICENSE
									
										
									
									
										vendored
									
									
								
							|  | @ -1,26 +0,0 @@ | |||
| The MIT License (MIT) | ||||
| 
 | ||||
| Copyright (c) 2016 Gabi Melman.                                        | ||||
| 
 | ||||
| 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. | ||||
| 
 | ||||
| -- NOTE: Third party dependency used by this software -- | ||||
| This software depends on the fmt lib (MIT License), | ||||
| and users must comply to its license: https://github.com/fmtlib/fmt/blob/master/LICENSE.rst | ||||
| 
 | ||||
							
								
								
									
										466
									
								
								Dependencies/spdlog/README.md
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										466
									
								
								Dependencies/spdlog/README.md
									
										
									
									
										vendored
									
									
								
							|  | @ -1,466 +0,0 @@ | |||
| # spdlog | ||||
| 
 | ||||
| Very fast, header-only/compiled, C++ logging library. [](https://app.travis-ci.com/gabime/spdlog)  [](https://ci.appveyor.com/project/gabime/spdlog) [](https://github.com/gabime/spdlog/releases/latest) | ||||
| 
 | ||||
| ## Install  | ||||
| #### Header only version | ||||
| Copy the include [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 | ||||
| $ git clone https://github.com/gabime/spdlog.git | ||||
| $ cd spdlog && mkdir build && cd build | ||||
| $ cmake .. && make -j | ||||
| ``` | ||||
|        | ||||
|    see example [CMakeLists.txt](https://github.com/gabime/spdlog/blob/v1.x/example/CMakeLists.txt) on how to use. | ||||
| 
 | ||||
| ## Platforms | ||||
|  * Linux, FreeBSD, OpenBSD, Solaris, AIX | ||||
|  * Windows (msvc 2013+, cygwin) | ||||
|  * macOS (clang 3.5+) | ||||
|  * Android | ||||
| 
 | ||||
| ## Package managers: | ||||
| * Debian: `sudo apt install libspdlog-dev` | ||||
| * Homebrew: `brew install spdlog` | ||||
| * MacPorts: `sudo port install spdlog` | ||||
| * FreeBSD:  `pkg install spdlog` | ||||
| * Fedora: `dnf install spdlog` | ||||
| * Gentoo: `emerge dev-libs/spdlog` | ||||
| * Arch Linux: `pacman -S spdlog` | ||||
| * vcpkg: `vcpkg install spdlog` | ||||
| * conan: `spdlog/[>=1.4.1]` | ||||
| * conda: `conda install -c conda-forge spdlog` | ||||
| * build2: ```depends: spdlog ^1.8.2``` | ||||
| 
 | ||||
| 
 | ||||
| ## Features | ||||
| * Very fast (see [benchmarks](#benchmarks) below). | ||||
| * Headers only or compiled | ||||
| * Feature rich formatting, using the excellent [fmt](https://github.com/fmtlib/fmt) library. | ||||
| * Asynchronous mode (optional) | ||||
| * [Custom](https://github.com/gabime/spdlog/wiki/3.-Custom-formatting) formatting. | ||||
| * Multi/Single threaded loggers. | ||||
| * Various log targets: | ||||
|     * Rotating log files. | ||||
|     * Daily log files. | ||||
|     * Console logging (colors supported). | ||||
|     * syslog. | ||||
|     * Windows event log. | ||||
|     * Windows debugger (```OutputDebugString(..)```). | ||||
|     * Easily [extendable](https://github.com/gabime/spdlog/wiki/4.-Sinks#implementing-your-own-sink) with custom log targets. | ||||
| * Log filtering - log levels can be modified in runtime as well as in compile time. | ||||
| * Support for loading log levels from argv or from environment var. | ||||
| * [Backtrace](#backtrace-support) support - store debug messages in a ring buffer and display later on demand. | ||||
|   | ||||
| ## Usage samples | ||||
| 
 | ||||
| #### Basic usage | ||||
| ```c++ | ||||
| #include "spdlog/spdlog.h" | ||||
| 
 | ||||
| int main()  | ||||
| { | ||||
|     spdlog::info("Welcome to spdlog!"); | ||||
|     spdlog::error("Some error message with arg: {}", 1); | ||||
|      | ||||
|     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::info("Support for floats {:03.2f}", 1.23456); | ||||
|     spdlog::info("Positional args are {1} {0}..", "too", "supported"); | ||||
|     spdlog::info("{:<30}", "left aligned"); | ||||
|      | ||||
|     spdlog::set_level(spdlog::level::debug); // Set global log level to debug | ||||
|     spdlog::debug("This message should be displayed..");     | ||||
|      | ||||
|     // change log pattern | ||||
|     spdlog::set_pattern("[%H:%M:%S %z] [%n] [%^---%L---%$] [thread %t] %v"); | ||||
|      | ||||
|     // Compile time log levels | ||||
|     // define SPDLOG_ACTIVE_LEVEL to desired level | ||||
|     SPDLOG_TRACE("Some trace message with param {}", 42); | ||||
|     SPDLOG_DEBUG("Some debug message"); | ||||
| } | ||||
| 
 | ||||
| ``` | ||||
| --- | ||||
| #### Create stdout/stderr logger object | ||||
| ```c++ | ||||
| #include "spdlog/spdlog.h" | ||||
| #include "spdlog/sinks/stdout_color_sinks.h" | ||||
| void stdout_example() | ||||
| { | ||||
|     // create color multi threaded logger | ||||
|     auto console = spdlog::stdout_color_mt("console");     | ||||
|     auto err_logger = spdlog::stderr_color_mt("stderr");     | ||||
|     spdlog::get("console")->info("loggers can be retrieved from a global registry using the spdlog::get(logger_name)"); | ||||
| } | ||||
| ``` | ||||
| 
 | ||||
| --- | ||||
| #### Basic file logger | ||||
| ```c++ | ||||
| #include "spdlog/sinks/basic_file_sink.h" | ||||
| void basic_logfile_example() | ||||
| { | ||||
|     try  | ||||
|     { | ||||
|         auto logger = spdlog::basic_logger_mt("basic_logger", "logs/basic-log.txt"); | ||||
|     } | ||||
|     catch (const spdlog::spdlog_ex &ex) | ||||
|     { | ||||
|         std::cout << "Log init failed: " << ex.what() << std::endl; | ||||
|     } | ||||
| } | ||||
| ``` | ||||
| --- | ||||
| #### Rotating files | ||||
| ```c++ | ||||
| #include "spdlog/sinks/rotating_file_sink.h" | ||||
| void rotating_example() | ||||
| { | ||||
|     // Create a file rotating logger with 5mb size max and 3 rotated files | ||||
|     auto max_size = 1048576 * 5; | ||||
|     auto max_files = 3; | ||||
|     auto logger = spdlog::rotating_logger_mt("some_logger_name", "logs/rotating.txt", max_size, max_files); | ||||
| } | ||||
| ``` | ||||
| 
 | ||||
| --- | ||||
| #### Daily files | ||||
| ```c++ | ||||
| 
 | ||||
| #include "spdlog/sinks/daily_file_sink.h" | ||||
| void daily_example() | ||||
| { | ||||
|     // Create a daily logger - a new file is created every day on 2:30am | ||||
|     auto logger = spdlog::daily_logger_mt("daily_logger", "logs/daily.txt", 2, 30); | ||||
| } | ||||
| 
 | ||||
| ``` | ||||
| 
 | ||||
| --- | ||||
| #### Backtrace support | ||||
| ```c++ | ||||
| // Debug messages can be stored in a ring buffer instead of being logged immediately. | ||||
| // This is useful in order to display debug logs only when really needed (e.g. when error happens). | ||||
| // When needed, call dump_backtrace() to see them. | ||||
| 
 | ||||
| spdlog::enable_backtrace(32); // Store the latest 32 messages in a buffer. Older messages will be dropped. | ||||
| // or my_logger->enable_backtrace(32).. | ||||
| for(int i = 0; i < 100; i++) | ||||
| { | ||||
|   spdlog::debug("Backtrace message {}", i); // not logged yet.. | ||||
| } | ||||
| // e.g. if some error happened: | ||||
| spdlog::dump_backtrace(); // log them now! show the last 32 messages | ||||
| 
 | ||||
| // or my_logger->dump_backtrace(32).. | ||||
| ``` | ||||
| 
 | ||||
| --- | ||||
| #### Periodic flush | ||||
| ```c++ | ||||
| // periodically flush all *registered* loggers every 3 seconds: | ||||
| // warning: only use if all your loggers are thread safe ("_mt" loggers) | ||||
| spdlog::flush_every(std::chrono::seconds(3)); | ||||
| 
 | ||||
| ``` | ||||
| 
 | ||||
| --- | ||||
| #### Stopwatch | ||||
| ```c++ | ||||
| // Stopwatch support for spdlog | ||||
| #include "spdlog/stopwatch.h" | ||||
| void stopwatch_example() | ||||
| { | ||||
|     spdlog::stopwatch sw;     | ||||
|     spdlog::debug("Elapsed {}", sw); | ||||
|     spdlog::debug("Elapsed {:.3}", sw);        | ||||
| } | ||||
| 
 | ||||
| ``` | ||||
| 
 | ||||
| --- | ||||
| #### Log binary data in hex | ||||
| ```c++ | ||||
| // many types of std::container<char> types can be used. | ||||
| // ranges are supported too. | ||||
| // format flags: | ||||
| // {:X} - print in uppercase. | ||||
| // {:s} - don't separate each byte with space. | ||||
| // {:p} - don't print the position on each line start. | ||||
| // {:n} - don't split the output to lines. | ||||
| // {:a} - show ASCII if :n is not set. | ||||
| 
 | ||||
| #include "spdlog/fmt/bin_to_hex.h" | ||||
| 
 | ||||
| void binary_example() | ||||
| { | ||||
|     auto console = spdlog::get("console"); | ||||
|     std::array<char, 80> buf; | ||||
|     console->info("Binary example: {}", spdlog::to_hex(buf)); | ||||
|     console->info("Another binary example:{:n}", spdlog::to_hex(std::begin(buf), std::begin(buf) + 10)); | ||||
|     // more examples: | ||||
|     // logger->info("uppercase: {:X}", spdlog::to_hex(buf)); | ||||
|     // logger->info("uppercase, no delimiters: {:Xs}", spdlog::to_hex(buf)); | ||||
|     // logger->info("uppercase, no delimiters, no position info: {:Xsp}", spdlog::to_hex(buf)); | ||||
| } | ||||
| 
 | ||||
| ``` | ||||
| 
 | ||||
| --- | ||||
| #### Logger with multi sinks - each with different format and log level | ||||
| ```c++ | ||||
| 
 | ||||
| // create logger with 2 targets with different log levels and formats. | ||||
| // the console will show only warnings or errors, while the file will log all. | ||||
| void multi_sink_example() | ||||
| { | ||||
|     auto console_sink = std::make_shared<spdlog::sinks::stdout_color_sink_mt>(); | ||||
|     console_sink->set_level(spdlog::level::warn); | ||||
|     console_sink->set_pattern("[multi_sink_example] [%^%l%$] %v"); | ||||
| 
 | ||||
|     auto file_sink = std::make_shared<spdlog::sinks::basic_file_sink_mt>("logs/multisink.txt", true); | ||||
|     file_sink->set_level(spdlog::level::trace); | ||||
| 
 | ||||
|     spdlog::logger logger("multi_sink", {console_sink, file_sink}); | ||||
|     logger.set_level(spdlog::level::debug); | ||||
|     logger.warn("this should appear in both console and file"); | ||||
|     logger.info("this message should not appear in the console, only in the file"); | ||||
| } | ||||
| ``` | ||||
| 
 | ||||
| --- | ||||
| #### Asynchronous logging | ||||
| ```c++ | ||||
| #include "spdlog/async.h" | ||||
| #include "spdlog/sinks/basic_file_sink.h" | ||||
| void async_example() | ||||
| { | ||||
|     // default thread pool settings can be modified *before* creating the async logger: | ||||
|     // spdlog::init_thread_pool(8192, 1); // queue with 8k items and 1 backing thread. | ||||
|     auto async_file = spdlog::basic_logger_mt<spdlog::async_factory>("async_file_logger", "logs/async_log.txt"); | ||||
|     // alternatively: | ||||
|     // auto async_file = spdlog::create_async<spdlog::sinks::basic_file_sink_mt>("async_file_logger", "logs/async_log.txt");    | ||||
| } | ||||
| 
 | ||||
| ``` | ||||
| 
 | ||||
| --- | ||||
| #### Asynchronous logger with multi sinks   | ||||
| ```c++ | ||||
| #include "spdlog/sinks/stdout_color_sinks.h" | ||||
| #include "spdlog/sinks/rotating_file_sink.h" | ||||
| 
 | ||||
| void multi_sink_example2() | ||||
| { | ||||
|     spdlog::init_thread_pool(8192, 1); | ||||
|     auto stdout_sink = std::make_shared<spdlog::sinks::stdout_color_sink_mt >(); | ||||
|     auto rotating_sink = std::make_shared<spdlog::sinks::rotating_file_sink_mt>("mylog.txt", 1024*1024*10, 3); | ||||
|     std::vector<spdlog::sink_ptr> sinks {stdout_sink, rotating_sink}; | ||||
|     auto logger = std::make_shared<spdlog::async_logger>("loggername", sinks.begin(), sinks.end(), spdlog::thread_pool(), spdlog::async_overflow_policy::block); | ||||
|     spdlog::register_logger(logger); | ||||
| } | ||||
| ``` | ||||
|   | ||||
| --- | ||||
| #### User defined types | ||||
| ```c++ | ||||
| // user defined types logging by implementing operator<< | ||||
| #include "spdlog/fmt/ostr.h" // must be included | ||||
| struct my_type | ||||
| { | ||||
|     int i; | ||||
|     template<typename OStream> | ||||
|     friend OStream &operator<<(OStream &os, const my_type &c) | ||||
|     { | ||||
|         return os << "[my_type i=" << c.i << "]"; | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| void user_defined_example() | ||||
| { | ||||
|     spdlog::get("console")->info("user defined type: {}", my_type{14}); | ||||
| } | ||||
| 
 | ||||
| ``` | ||||
| 
 | ||||
| --- | ||||
| #### User defined flags in the log pattern | ||||
| ```c++  | ||||
| // Log patterns can contain custom flags. | ||||
| // the following example will add new flag '%*' - which will be bound to a <my_formatter_flag> instance. | ||||
| #include "spdlog/pattern_formatter.h" | ||||
| class my_formatter_flag : public spdlog::custom_flag_formatter | ||||
| { | ||||
| public: | ||||
|     void format(const spdlog::details::log_msg &, const std::tm &, spdlog::memory_buf_t &dest) override | ||||
|     { | ||||
|         std::string some_txt = "custom-flag"; | ||||
|         dest.append(some_txt.data(), some_txt.data() + some_txt.size()); | ||||
|     } | ||||
| 
 | ||||
|     std::unique_ptr<custom_flag_formatter> clone() const override | ||||
|     { | ||||
|         return spdlog::details::make_unique<my_formatter_flag>(); | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| void custom_flags_example() | ||||
| {     | ||||
|     auto formatter = std::make_unique<spdlog::pattern_formatter>(); | ||||
|     formatter->add_flag<my_formatter_flag>('*').set_pattern("[%n] [%*] [%^%l%$] %v"); | ||||
|     spdlog::set_formatter(std::move(formatter)); | ||||
| } | ||||
| 
 | ||||
| ``` | ||||
| 
 | ||||
| --- | ||||
| #### Custom error handler | ||||
| ```c++ | ||||
| void err_handler_example() | ||||
| { | ||||
|     // can be set globally or per logger(logger->set_error_handler(..)) | ||||
|     spdlog::set_error_handler([](const std::string &msg) { spdlog::get("console")->error("*** LOGGER ERROR ***: {}", msg); }); | ||||
|     spdlog::get("console")->info("some invalid message to trigger an error {}{}{}{}", 3); | ||||
| } | ||||
| 
 | ||||
| ``` | ||||
| 
 | ||||
| --- | ||||
| #### syslog  | ||||
| ```c++ | ||||
| #include "spdlog/sinks/syslog_sink.h" | ||||
| void syslog_example() | ||||
| { | ||||
|     std::string ident = "spdlog-example"; | ||||
|     auto syslog_logger = spdlog::syslog_logger_mt("syslog", ident, LOG_PID); | ||||
|     syslog_logger->warn("This is warning that will end up in syslog."); | ||||
| } | ||||
| ``` | ||||
| --- | ||||
| #### Android example  | ||||
| ```c++ | ||||
| #include "spdlog/sinks/android_sink.h" | ||||
| void android_example() | ||||
| { | ||||
|     std::string tag = "spdlog-android"; | ||||
|     auto android_logger = spdlog::android_logger_mt("android", tag); | ||||
|     android_logger->critical("Use \"adb shell logcat\" to view this message."); | ||||
| } | ||||
| ``` | ||||
| 
 | ||||
| --- | ||||
| #### Load log levels from env variable or from argv | ||||
| 
 | ||||
| ```c++ | ||||
| #include "spdlog/cfg/env.h" | ||||
| int main (int argc, char *argv[]) | ||||
| { | ||||
|     spdlog::cfg::load_env_levels(); | ||||
|     // or from command line: | ||||
|     // ./example SPDLOG_LEVEL=info,mylogger=trace | ||||
|     // #include "spdlog/cfg/argv.h" // for loading levels from argv | ||||
|     // spdlog::cfg::load_argv_levels(argc, argv); | ||||
| } | ||||
| ``` | ||||
| So then you can: | ||||
| 
 | ||||
| ```console | ||||
| $ export SPDLOG_LEVEL=info,mylogger=trace | ||||
| $ ./example | ||||
| ``` | ||||
| 
 | ||||
| 
 | ||||
| --- | ||||
| #### Log file open/close event handlers | ||||
| ```c++ | ||||
| // You can get callbacks from spdlog before/after log file has been opened or closed.  | ||||
| // This is useful for cleanup procedures or for adding someting the start/end of the log files. | ||||
| void file_events_example() | ||||
| { | ||||
|     // pass the spdlog::file_event_handlers to file sinks for open/close log file notifications | ||||
|     spdlog::file_event_handlers handlers; | ||||
|     handlers.before_open = [](spdlog::filename_t filename) { spdlog::info("Before opening {}", filename); }; | ||||
|     handlers.after_open = [](spdlog::filename_t filename, std::FILE *fstream) { fputs("After opening\n", fstream); }; | ||||
|     handlers.before_close = [](spdlog::filename_t filename, std::FILE *fstream) { fputs("Before closing\n", fstream); }; | ||||
|     handlers.after_close = [](spdlog::filename_t filename) { spdlog::info("After closing {}", filename); }; | ||||
|     auto my_logger = spdlog::basic_logger_st("some_logger", "logs/events-sample.txt", true, handlers);         | ||||
| } | ||||
| ``` | ||||
| 
 | ||||
| --- | ||||
| #### Replace the Default Logger | ||||
| ```c++ | ||||
| void replace_default_logger_example() | ||||
| { | ||||
|     auto new_logger = spdlog::basic_logger_mt("new_default_logger", "logs/new-default-log.txt", true); | ||||
|     spdlog::set_default_logger(new_logger); | ||||
|     spdlog::info("new logger log 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, competing over the same logger object, 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] ------------------------------------------------- | ||||
| [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 can be found in the [wiki](https://github.com/gabime/spdlog/wiki/1.-QuickStart) pages. | ||||
| 
 | ||||
| --- | ||||
| 
 | ||||
| Thanks to [JetBrains](https://www.jetbrains.com/?from=spdlog) for donating product licenses to help develop **spdlog** <a href="https://www.jetbrains.com/?from=spdlog"><img src="logos/jetbrains-variant-4.svg" width="94" align="center" /></a> | ||||
| 
 | ||||
| 
 | ||||
							
								
								
									
										114
									
								
								Dependencies/spdlog/appveyor.yml
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										114
									
								
								Dependencies/spdlog/appveyor.yml
									
										
									
									
										vendored
									
									
								
							|  | @ -1,114 +0,0 @@ | |||
| version: 1.0.{build} | ||||
| image: Visual Studio 2017 | ||||
| environment: | ||||
|   matrix: | ||||
|     - GENERATOR: '"Visual Studio 14 2015"' | ||||
|       BUILD_TYPE: Debug | ||||
|       BUILD_SHARED: 'OFF' | ||||
|       WCHAR: 'OFF' | ||||
|       WCHAR_FILES: 'OFF' | ||||
|       BUILD_EXAMPLE: 'ON' | ||||
|       USE_STD_FORMAT: 'OFF' | ||||
|       CXX_STANDARD: 11 | ||||
|     - GENERATOR: '"Visual Studio 14 2015"' | ||||
|       BUILD_TYPE: Release | ||||
|       BUILD_SHARED: 'OFF' | ||||
|       WCHAR: 'ON' | ||||
|       WCHAR_FILES: 'OFF' | ||||
|       BUILD_EXAMPLE: 'ON' | ||||
|       USE_STD_FORMAT: 'OFF' | ||||
|       CXX_STANDARD: 11 | ||||
|     - GENERATOR: '"Visual Studio 14 2015 Win64"' | ||||
|       BUILD_TYPE: Debug | ||||
|       BUILD_SHARED: 'OFF' | ||||
|       WCHAR: 'ON' | ||||
|       WCHAR_FILES: 'OFF' | ||||
|       BUILD_EXAMPLE: 'ON' | ||||
|       USE_STD_FORMAT: 'OFF' | ||||
|       CXX_STANDARD: 11 | ||||
|     - GENERATOR: '"Visual Studio 14 2015 Win64"' | ||||
|       BUILD_TYPE: Release | ||||
|       BUILD_SHARED: 'OFF' | ||||
|       WCHAR: 'ON' | ||||
|       WCHAR_FILES: 'OFF' | ||||
|       BUILD_EXAMPLE: 'ON' | ||||
|       USE_STD_FORMAT: 'OFF' | ||||
|       CXX_STANDARD: 11 | ||||
|     - GENERATOR: '"Visual Studio 15 2017 Win64"' | ||||
|       BUILD_TYPE: Debug | ||||
|       BUILD_SHARED: 'OFF' | ||||
|       WCHAR: 'ON' | ||||
|       WCHAR_FILES: 'OFF' | ||||
|       BUILD_EXAMPLE: 'ON' | ||||
|       USE_STD_FORMAT: 'OFF' | ||||
|       CXX_STANDARD: 11 | ||||
|     - GENERATOR: '"Visual Studio 15 2017 Win64"' | ||||
|       BUILD_TYPE: Release | ||||
|       BUILD_SHARED: 'OFF' | ||||
|       WCHAR: 'OFF' | ||||
|       WCHAR_FILES: 'OFF' | ||||
|       BUILD_EXAMPLE: 'ON' | ||||
|       USE_STD_FORMAT: 'OFF' | ||||
|       CXX_STANDARD: 11 | ||||
|     - GENERATOR: '"Visual Studio 15 2017 Win64"' | ||||
|       BUILD_TYPE: Release | ||||
|       BUILD_SHARED: 'ON' | ||||
|       WCHAR: 'OFF' | ||||
|       WCHAR_FILES: 'OFF' | ||||
|       BUILD_EXAMPLE: 'ON' | ||||
|       USE_STD_FORMAT: 'OFF' | ||||
|       CXX_STANDARD: 11 | ||||
|     - GENERATOR: '"Visual Studio 15 2017 Win64"' | ||||
|       BUILD_TYPE: Release | ||||
|       BUILD_SHARED: 'ON' | ||||
|       WCHAR: 'ON' | ||||
|       WCHAR_FILES: 'ON' | ||||
|       BUILD_EXAMPLE: 'OFF' | ||||
|       USE_STD_FORMAT: 'OFF' | ||||
|       CXX_STANDARD: 11 | ||||
|     - GENERATOR: '"Visual Studio 16 2019" -A x64' | ||||
|       BUILD_TYPE: Release | ||||
|       BUILD_SHARED: 'ON' | ||||
|       WCHAR: 'OFF' | ||||
|       WCHAR_FILES: 'OFF' | ||||
|       BUILD_EXAMPLE: 'OFF' | ||||
|       USE_STD_FORMAT: 'OFF' | ||||
|       CXX_STANDARD: 17 | ||||
|       APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 | ||||
|     - GENERATOR: '"Visual Studio 17 2022" -A x64' | ||||
|       BUILD_TYPE: Release | ||||
|       BUILD_SHARED: 'ON' | ||||
|       WCHAR: 'OFF' | ||||
|       WCHAR_FILES: 'OFF' | ||||
|       BUILD_EXAMPLE: 'OFF' | ||||
|       USE_STD_FORMAT: 'ON' | ||||
|       CXX_STANDARD: 23 # std::format is only available with /std:c++latest at the moment. | ||||
|       APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2022 | ||||
|     - GENERATOR: '"Visual Studio 17 2022" -A x64' | ||||
|       BUILD_TYPE: Release | ||||
|       BUILD_SHARED: 'ON' | ||||
|       WCHAR: 'ON' | ||||
|       WCHAR_FILES: 'ON' | ||||
|       BUILD_EXAMPLE: 'OFF' | ||||
|       USE_STD_FORMAT: 'ON' | ||||
|       CXX_STANDARD: 23 # std::format is only available with /std:c++latest at the moment. | ||||
|       APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2022 | ||||
| build_script: | ||||
|   - cmd: >- | ||||
|       set | ||||
| 
 | ||||
|       mkdir build | ||||
| 
 | ||||
|       cd build | ||||
| 
 | ||||
|       set PATH=%PATH%;C:\Program Files\Git\usr\bin | ||||
| 
 | ||||
|       cmake -G %GENERATOR% -D CMAKE_BUILD_TYPE=%BUILD_TYPE% -D BUILD_SHARED_LIBS=%BUILD_SHARED% -D SPDLOG_WCHAR_SUPPORT=%WCHAR% -D SPDLOG_WCHAR_FILENAMES=%WCHAR_FILES% -D SPDLOG_BUILD_EXAMPLE=%BUILD_EXAMPLE% -D SPDLOG_BUILD_EXAMPLE_HO=%BUILD_EXAMPLE% -D SPDLOG_BUILD_TESTS=ON -D SPDLOG_BUILD_TESTS_HO=OFF -D SPDLOG_BUILD_WARNINGS=ON -D SPDLOG_USE_STD_FORMAT=%USE_STD_FORMAT% -D CMAKE_CXX_STANDARD=%CXX_STANDARD% .. | ||||
| 
 | ||||
|       cmake --build . --config %BUILD_TYPE% | ||||
| 
 | ||||
| before_test: | ||||
|   - set PATH=%PATH%;C:\projects\spdlog\build\%BUILD_TYPE% | ||||
|    | ||||
| test_script: | ||||
|   - C:\projects\spdlog\build\tests\%BUILD_TYPE%\spdlog-utests.exe | ||||
							
								
								
									
										41
									
								
								Dependencies/spdlog/bench/CMakeLists.txt
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										41
									
								
								Dependencies/spdlog/bench/CMakeLists.txt
									
										
									
									
										vendored
									
									
								
							|  | @ -1,41 +0,0 @@ | |||
| # Copyright(c) 2019 spdlog authors Distributed under the MIT License (http://opensource.org/licenses/MIT) | ||||
| 
 | ||||
| cmake_minimum_required(VERSION 3.10) | ||||
| project(spdlog_bench CXX) | ||||
| 
 | ||||
| if(NOT TARGET spdlog) | ||||
|     # Stand-alone build | ||||
|     find_package(spdlog CONFIG REQUIRED) | ||||
| endif() | ||||
| 
 | ||||
| find_package(Threads REQUIRED) | ||||
| find_package(benchmark CONFIG) | ||||
| if(NOT benchmark_FOUND) | ||||
|     message(STATUS "Using CMake Version ${CMAKE_VERSION}") | ||||
|     if(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.11.0") | ||||
|         # User can fetch googlebenchmark | ||||
|         message(STATUS "Downloading GoogleBenchmark") | ||||
|         include(FetchContent) | ||||
| 
 | ||||
|         # disable tests   | ||||
|         set(BENCHMARK_ENABLE_TESTING OFF CACHE INTERNAL "")         | ||||
|         # Do not build and run googlebenchmark tests | ||||
|         FetchContent_Declare(googlebenchmark GIT_REPOSITORY https://github.com/google/benchmark.git GIT_TAG v1.6.0) | ||||
|         FetchContent_MakeAvailable(googlebenchmark) | ||||
|     else() | ||||
|         message(FATAL_ERROR "GoogleBenchmark is missing. Use CMake >= 3.11 or download it") | ||||
|     endif() | ||||
| endif() | ||||
| 
 | ||||
| add_executable(bench bench.cpp) | ||||
| spdlog_enable_warnings(bench) | ||||
| target_link_libraries(bench PRIVATE spdlog::spdlog) | ||||
| 
 | ||||
| add_executable(async_bench async_bench.cpp) | ||||
| target_link_libraries(async_bench PRIVATE spdlog::spdlog) | ||||
| 
 | ||||
| add_executable(latency latency.cpp) | ||||
| target_link_libraries(latency PRIVATE benchmark::benchmark spdlog::spdlog) | ||||
| 
 | ||||
| add_executable(formatter-bench formatter-bench.cpp) | ||||
| target_link_libraries(formatter-bench PRIVATE benchmark::benchmark spdlog::spdlog) | ||||
							
								
								
									
										186
									
								
								Dependencies/spdlog/bench/async_bench.cpp
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										186
									
								
								Dependencies/spdlog/bench/async_bench.cpp
									
										
									
									
										vendored
									
									
								
							|  | @ -1,186 +0,0 @@ | |||
| //
 | ||||
| // Copyright(c) 2015 Gabi Melman.
 | ||||
| // Distributed under the MIT License (http://opensource.org/licenses/MIT)
 | ||||
| //
 | ||||
| 
 | ||||
| //
 | ||||
| // bench.cpp : spdlog benchmarks
 | ||||
| //
 | ||||
| #include "spdlog/spdlog.h" | ||||
| #include "spdlog/async.h" | ||||
| #include "spdlog/sinks/basic_file_sink.h" | ||||
| 
 | ||||
| #if defined(SPDLOG_USE_STD_FORMAT) | ||||
| #    include <format> | ||||
| #elif defined(SPDLOG_FMT_EXTERNAL) | ||||
| #    include <fmt/format.h> | ||||
| #else | ||||
| #    include "spdlog/fmt/bundled/format.h" | ||||
| #endif | ||||
| 
 | ||||
| #include "utils.h" | ||||
| #include <atomic> | ||||
| #include <iostream> | ||||
| #include <memory> | ||||
| #include <string> | ||||
| #include <thread> | ||||
| 
 | ||||
| using namespace std; | ||||
| using namespace std::chrono; | ||||
| using namespace spdlog; | ||||
| using namespace spdlog::sinks; | ||||
| using namespace utils; | ||||
| 
 | ||||
| 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 counter = 0; | ||||
|     auto *infile = fopen(filename, "r"); | ||||
|     int ch; | ||||
|     while (EOF != (ch = getc(infile))) | ||||
|     { | ||||
|         if ('\n' == ch) | ||||
|             counter++; | ||||
|     } | ||||
|     fclose(infile); | ||||
| 
 | ||||
|     return counter; | ||||
| } | ||||
| 
 | ||||
| void verify_file(const char *filename, int expected_count) | ||||
| { | ||||
|     spdlog::info("Verifying {} to contain {} line..", filename, expected_count); | ||||
|     auto count = count_lines(filename); | ||||
|     if (count != expected_count) | ||||
|     { | ||||
|         spdlog::error("Test failed. {} has {} lines instead of {}", filename, count, expected_count); | ||||
|         exit(1); | ||||
|     } | ||||
|     spdlog::info("Line count OK ({})\n", count); | ||||
| } | ||||
| 
 | ||||
| #ifdef _MSC_VER | ||||
| #    pragma warning(pop) | ||||
| #endif | ||||
| 
 | ||||
| int main(int argc, char *argv[]) | ||||
| { | ||||
| 
 | ||||
|     int howmany = 1000000; | ||||
|     int queue_size = std::min(howmany + 2, 8192); | ||||
|     int threads = 10; | ||||
|     int iters = 3; | ||||
| 
 | ||||
|     try | ||||
|     { | ||||
|         spdlog::set_pattern("[%^%l%$] %v"); | ||||
|         if (argc == 1) | ||||
|         { | ||||
|             spdlog::info("Usage: {} <message_count> <threads> <q_size> <iterations>", argv[0]); | ||||
|             return 0; | ||||
|         } | ||||
| 
 | ||||
|         if (argc > 1) | ||||
|             howmany = atoi(argv[1]); | ||||
|         if (argc > 2) | ||||
|             threads = atoi(argv[2]); | ||||
|         if (argc > 3) | ||||
|         { | ||||
|             queue_size = atoi(argv[3]); | ||||
|             if (queue_size > 500000) | ||||
|             { | ||||
|                 spdlog::error("Max queue size allowed: 500,000"); | ||||
|                 exit(1); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         if (argc > 4) | ||||
|             iters = atoi(argv[4]); | ||||
| 
 | ||||
|         auto slot_size = sizeof(spdlog::details::async_msg); | ||||
|         spdlog::info("-------------------------------------------------"); | ||||
|         spdlog::info("Messages     : {:L}", howmany); | ||||
|         spdlog::info("Threads      : {:L}", threads); | ||||
|         spdlog::info("Queue        : {:L} slots", queue_size); | ||||
|         spdlog::info("Queue memory : {:L} x {:L} = {:L} KB ", queue_size, slot_size, (queue_size * slot_size) / 1024); | ||||
|         spdlog::info("Total iters  : {:L}", iters); | ||||
|         spdlog::info("-------------------------------------------------"); | ||||
| 
 | ||||
|         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++) | ||||
|         { | ||||
|             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::block); | ||||
|             bench_mt(howmany, std::move(logger), threads); | ||||
|             // verify_file(filename, howmany);
 | ||||
|         } | ||||
| 
 | ||||
|         spdlog::info(""); | ||||
|         spdlog::info("*********************************"); | ||||
|         spdlog::info("Queue Overflow Policy: overrun"); | ||||
|         spdlog::info("*********************************"); | ||||
|         // do same test but discard oldest if queue is full instead of blocking
 | ||||
|         filename = "logs/basic_async-overrun.log"; | ||||
|         for (int i = 0; i < iters; i++) | ||||
|         { | ||||
|             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(); | ||||
|     } | ||||
|     catch (std::exception &ex) | ||||
|     { | ||||
|         std::cerr << "Error: " << ex.what() << std::endl; | ||||
|         perror("Last error"); | ||||
|         return 1; | ||||
|     } | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
| void thread_fun(std::shared_ptr<spdlog::logger> logger, int howmany) | ||||
| { | ||||
|     for (int i = 0; i < howmany; i++) | ||||
|     { | ||||
|         logger->info("Hello logger: msg number {}", i); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void bench_mt(int howmany, std::shared_ptr<spdlog::logger> logger, int thread_count) | ||||
| { | ||||
|     using std::chrono::high_resolution_clock; | ||||
|     vector<std::thread> threads; | ||||
|     auto start = high_resolution_clock::now(); | ||||
| 
 | ||||
|     int msgs_per_thread = howmany / thread_count; | ||||
|     int msgs_per_thread_mod = howmany % thread_count; | ||||
|     for (int t = 0; t < thread_count; ++t) | ||||
|     { | ||||
|         if (t == 0 && msgs_per_thread_mod) | ||||
|             threads.push_back(std::thread(thread_fun, logger, msgs_per_thread + msgs_per_thread_mod)); | ||||
|         else | ||||
|             threads.push_back(std::thread(thread_fun, logger, msgs_per_thread)); | ||||
|     } | ||||
| 
 | ||||
|     for (auto &t : threads) | ||||
|     { | ||||
|         t.join(); | ||||
|     }; | ||||
| 
 | ||||
|     auto delta = high_resolution_clock::now() - start; | ||||
|     auto delta_d = duration_cast<duration<double>>(delta).count(); | ||||
|     spdlog::info("Elapsed: {} secs\t {:L}/sec", delta_d, int(howmany / delta_d)); | ||||
| } | ||||
							
								
								
									
										248
									
								
								Dependencies/spdlog/bench/bench.cpp
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										248
									
								
								Dependencies/spdlog/bench/bench.cpp
									
										
									
									
										vendored
									
									
								
							|  | @ -1,248 +0,0 @@ | |||
| //
 | ||||
| // Copyright(c) 2015 Gabi Melman.
 | ||||
| // Distributed under the MIT License (http://opensource.org/licenses/MIT)
 | ||||
| //
 | ||||
| 
 | ||||
| //
 | ||||
| // bench.cpp : spdlog benchmarks
 | ||||
| //
 | ||||
| #include "spdlog/spdlog.h" | ||||
| #include "spdlog/sinks/basic_file_sink.h" | ||||
| #include "spdlog/sinks/daily_file_sink.h" | ||||
| #include "spdlog/sinks/null_sink.h" | ||||
| #include "spdlog/sinks/rotating_file_sink.h" | ||||
| 
 | ||||
| #if defined(SPDLOG_USE_STD_FORMAT) | ||||
| #    include <format> | ||||
| #elif defined(SPDLOG_FMT_EXTERNAL) | ||||
| #    include <fmt/locale.h> | ||||
| #else | ||||
| #    include "spdlog/fmt/bundled/format.h" | ||||
| #endif | ||||
| 
 | ||||
| #include "utils.h" | ||||
| #include <atomic> | ||||
| #include <cstdlib> // EXIT_FAILURE
 | ||||
| #include <memory> | ||||
| #include <string> | ||||
| #include <thread> | ||||
| 
 | ||||
| void bench(int howmany, std::shared_ptr<spdlog::logger> log); | ||||
| void bench_mt(int howmany, std::shared_ptr<spdlog::logger> log, size_t thread_count); | ||||
| 
 | ||||
| // void bench_default_api(int howmany, std::shared_ptr<spdlog::logger> log);
 | ||||
| // void bench_c_string(int howmany, std::shared_ptr<spdlog::logger> log);
 | ||||
| 
 | ||||
| static const size_t file_size = 30 * 1024 * 1024; | ||||
| static const size_t rotating_files = 5; | ||||
| static const int max_threads = 1000; | ||||
| 
 | ||||
| void bench_threaded_logging(size_t threads, int iters) | ||||
| { | ||||
|     spdlog::info("**************************************************************"); | ||||
|     spdlog::info(spdlog::fmt_lib::format(std::locale("en_US.UTF-8"), "Multi threaded: {:L} threads, {:L} 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(spdlog::fmt_lib::format(std::locale("en_US.UTF-8"), "Single threaded: {} 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[]) | ||||
| { | ||||
|     spdlog::set_automatic_registration(false); | ||||
|     spdlog::default_logger()->set_pattern("[%^%l%$] %v"); | ||||
|     int iters = 250000; | ||||
|     size_t threads = 4; | ||||
|     try | ||||
|     { | ||||
| 
 | ||||
|         if (argc > 1) | ||||
|         { | ||||
|             iters = std::stoi(argv[1]); | ||||
|         } | ||||
|         if (argc > 2) | ||||
|         { | ||||
|             threads = std::stoul(argv[2]); | ||||
|         } | ||||
| 
 | ||||
|         if (threads > max_threads) | ||||
|         { | ||||
|             throw std::runtime_error(spdlog::fmt_lib::format("Number of threads exceeds maximum({})", max_threads)); | ||||
|         } | ||||
| 
 | ||||
|         bench_single_threaded(iters); | ||||
|         bench_threaded_logging(1, iters); | ||||
|         bench_threaded_logging(threads, iters); | ||||
|     } | ||||
|     catch (std::exception &ex) | ||||
|     { | ||||
|         spdlog::error(ex.what()); | ||||
|         return EXIT_FAILURE; | ||||
|     } | ||||
|     return EXIT_SUCCESS; | ||||
| } | ||||
| 
 | ||||
| void bench(int howmany, std::shared_ptr<spdlog::logger> log) | ||||
| { | ||||
|     using std::chrono::duration; | ||||
|     using std::chrono::duration_cast; | ||||
|     using std::chrono::high_resolution_clock; | ||||
| 
 | ||||
|     auto start = high_resolution_clock::now(); | ||||
|     for (auto i = 0; i < howmany; ++i) | ||||
|     { | ||||
|         log->info("Hello logger: msg number {}", i); | ||||
|     } | ||||
| 
 | ||||
|     auto delta = high_resolution_clock::now() - start; | ||||
|     auto delta_d = duration_cast<duration<double>>(delta).count(); | ||||
| 
 | ||||
|     spdlog::info(spdlog::fmt_lib::format( | ||||
|         std::locale("en_US.UTF-8"), "{:<30} Elapsed: {:0.2f} secs {:>16L}/sec", log->name(), delta_d, int(howmany / delta_d))); | ||||
|     spdlog::drop(log->name()); | ||||
| } | ||||
| 
 | ||||
| void bench_mt(int howmany, std::shared_ptr<spdlog::logger> log, size_t thread_count) | ||||
| { | ||||
|     using std::chrono::duration; | ||||
|     using std::chrono::duration_cast; | ||||
|     using std::chrono::high_resolution_clock; | ||||
| 
 | ||||
|     std::vector<std::thread> threads; | ||||
|     threads.reserve(thread_count); | ||||
|     auto start = high_resolution_clock::now(); | ||||
|     for (size_t t = 0; t < thread_count; ++t) | ||||
|     { | ||||
|         threads.emplace_back([&]() { | ||||
|             for (int j = 0; j < howmany / static_cast<int>(thread_count); j++) | ||||
|             { | ||||
|                 log->info("Hello logger: msg number {}", j); | ||||
|             } | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     for (auto &t : threads) | ||||
|     { | ||||
|         t.join(); | ||||
|     }; | ||||
| 
 | ||||
|     auto delta = high_resolution_clock::now() - start; | ||||
|     auto delta_d = duration_cast<duration<double>>(delta).count(); | ||||
|     spdlog::info(spdlog::fmt_lib::format( | ||||
|         std::locale("en_US.UTF-8"), "{:<30} Elapsed: {:0.2f} secs {:>16L}/sec", log->name(), delta_d, int(howmany / delta_d))); | ||||
|     spdlog::drop(log->name()); | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
| void bench_default_api(int howmany, std::shared_ptr<spdlog::logger> log) | ||||
| { | ||||
|     using std::chrono::high_resolution_clock; | ||||
|     using std::chrono::duration; | ||||
|     using std::chrono::duration_cast; | ||||
| 
 | ||||
|     auto orig_default = spdlog::default_logger(); | ||||
|     spdlog::set_default_logger(log); | ||||
|     auto start = high_resolution_clock::now(); | ||||
|     for (auto i = 0; i < howmany; ++i) | ||||
|     { | ||||
|         spdlog::info("Hello logger: msg number {}", i); | ||||
|     } | ||||
| 
 | ||||
|     auto delta = high_resolution_clock::now() - start; | ||||
|     auto delta_d = duration_cast<duration<double>>(delta).count(); | ||||
|     spdlog::drop(log->name()); | ||||
|     spdlog::set_default_logger(std::move(orig_default)); | ||||
|     spdlog::info("{:<30} Elapsed: {:0.2f} secs {:>16}/sec", log->name(), delta_d, int(howmany / delta_d)); | ||||
| } | ||||
| 
 | ||||
| void bench_c_string(int howmany, std::shared_ptr<spdlog::logger> log) | ||||
| { | ||||
|     using std::chrono::high_resolution_clock; | ||||
|     using std::chrono::duration; | ||||
|     using std::chrono::duration_cast; | ||||
| 
 | ||||
|     const char *msg = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum pharetra metus cursus " | ||||
|                       "lacus placerat congue. Nulla egestas, mauris a tincidunt tempus, enim lectus volutpat mi, eu consequat sem " | ||||
|                       "libero nec massa. In dapibus ipsum a diam rhoncus gravida. Etiam non dapibus eros. Donec fringilla dui sed " | ||||
|                       "augue pretium, nec scelerisque est maximus. Nullam convallis, sem nec blandit maximus, nisi turpis ornare " | ||||
|                       "nisl, sit amet volutpat neque massa eu odio. Maecenas malesuada quam ex, posuere congue nibh turpis duis."; | ||||
| 
 | ||||
|     auto orig_default = spdlog::default_logger(); | ||||
|     spdlog::set_default_logger(log); | ||||
|     auto start = high_resolution_clock::now(); | ||||
|     for (auto i = 0; i < howmany; ++i) | ||||
|     { | ||||
|         spdlog::log(spdlog::level::info, msg); | ||||
|     } | ||||
| 
 | ||||
|     auto delta = high_resolution_clock::now() - start; | ||||
|     auto delta_d = duration_cast<duration<double>>(delta).count(); | ||||
|     spdlog::drop(log->name()); | ||||
|     spdlog::set_default_logger(std::move(orig_default)); | ||||
|     spdlog::info("{:<30} Elapsed: {:0.2f} secs {:>16}/sec", log->name(), delta_d, int(howmany / delta_d)); | ||||
| } | ||||
| 
 | ||||
| */ | ||||
							
								
								
									
										80
									
								
								Dependencies/spdlog/bench/formatter-bench.cpp
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										80
									
								
								Dependencies/spdlog/bench/formatter-bench.cpp
									
										
									
									
										vendored
									
									
								
							|  | @ -1,80 +0,0 @@ | |||
| //
 | ||||
| // Copyright(c) 2018 Gabi Melman.
 | ||||
| // Distributed under the MIT License (http://opensource.org/licenses/MIT)
 | ||||
| //
 | ||||
| 
 | ||||
| #include "benchmark/benchmark.h" | ||||
| 
 | ||||
| #include "spdlog/spdlog.h" | ||||
| #include "spdlog/pattern_formatter.h" | ||||
| 
 | ||||
| void bench_formatter(benchmark::State &state, std::string pattern) | ||||
| { | ||||
|     auto formatter = spdlog::details::make_unique<spdlog::pattern_formatter>(pattern); | ||||
|     spdlog::memory_buf_t dest; | ||||
|     std::string logger_name = "logger-name"; | ||||
|     const char *text = "Hello. This is some message with length of 80                                   "; | ||||
| 
 | ||||
|     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) | ||||
|     { | ||||
|         dest.clear(); | ||||
|         formatter->format(msg, dest); | ||||
|         benchmark::DoNotOptimize(dest); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void bench_formatters() | ||||
| { | ||||
|     // basic patterns(single flag)
 | ||||
|     std::string all_flags = "+vtPnlLaAbBcCYDmdHIMSefFprRTXzEisg@luioO%"; | ||||
|     std::vector<std::string> basic_patterns; | ||||
|     for (auto &flag : all_flags) | ||||
|     { | ||||
|         auto pattern = std::string("%") + flag; | ||||
|         benchmark::RegisterBenchmark(pattern.c_str(), &bench_formatter, pattern); | ||||
| 
 | ||||
|         //        pattern = std::string("%16") + flag;
 | ||||
|         //        benchmark::RegisterBenchmark(pattern.c_str(), &bench_formatter, pattern);
 | ||||
|         //
 | ||||
|         //        // bench center padding
 | ||||
|         //        pattern = std::string("%=16") + flag;
 | ||||
|         //        benchmark::RegisterBenchmark(pattern.c_str(), &bench_formatter, pattern);
 | ||||
|     } | ||||
| 
 | ||||
|     // complex patterns
 | ||||
|     std::vector<std::string> patterns = { | ||||
|         "[%D %X] [%l] [%n] %v", | ||||
|         "[%Y-%m-%d %H:%M:%S.%e] [%l] [%n] %v", | ||||
|         "[%Y-%m-%d %H:%M:%S.%e] [%l] [%n] [%t] %v", | ||||
|     }; | ||||
|     for (auto &pattern : patterns) | ||||
|     { | ||||
|         benchmark::RegisterBenchmark(pattern.c_str(), &bench_formatter, pattern)->Iterations(2500000); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| int main(int argc, char *argv[]) | ||||
| { | ||||
| 
 | ||||
|     spdlog::set_pattern("[%^%l%$] %v"); | ||||
|     if (argc != 2) | ||||
|     { | ||||
|         spdlog::error("Usage: {} <pattern> (or \"all\" to bench all)", argv[0]); | ||||
|         exit(1); | ||||
|     } | ||||
| 
 | ||||
|     std::string pattern = argv[1]; | ||||
|     if (pattern == "all") | ||||
|     { | ||||
|         bench_formatters(); | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         benchmark::RegisterBenchmark(pattern.c_str(), &bench_formatter, pattern); | ||||
|     } | ||||
|     benchmark::Initialize(&argc, argv); | ||||
|     benchmark::RunSpecifiedBenchmarks(); | ||||
| } | ||||
							
								
								
									
										177
									
								
								Dependencies/spdlog/bench/latency.cpp
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										177
									
								
								Dependencies/spdlog/bench/latency.cpp
									
										
									
									
										vendored
									
									
								
							|  | @ -1,177 +0,0 @@ | |||
| //
 | ||||
| // Copyright(c) 2018 Gabi Melman.
 | ||||
| // Distributed under the MIT License (http://opensource.org/licenses/MIT)
 | ||||
| //
 | ||||
| 
 | ||||
| //
 | ||||
| // latency.cpp : spdlog latency benchmarks
 | ||||
| //
 | ||||
| 
 | ||||
| #include "benchmark/benchmark.h" | ||||
| 
 | ||||
| #include "spdlog/spdlog.h" | ||||
| #include "spdlog/async.h" | ||||
| #include "spdlog/sinks/basic_file_sink.h" | ||||
| #include "spdlog/sinks/daily_file_sink.h" | ||||
| #include "spdlog/sinks/null_sink.h" | ||||
| #include "spdlog/sinks/rotating_file_sink.h" | ||||
| 
 | ||||
| void bench_c_string(benchmark::State &state, std::shared_ptr<spdlog::logger> logger) | ||||
| { | ||||
|     const char *msg = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum pharetra metus cursus " | ||||
|                       "lacus placerat congue. Nulla egestas, mauris a tincidunt tempus, enim lectus volutpat mi, eu consequat sem " | ||||
|                       "libero nec massa. In dapibus ipsum a diam rhoncus gravida. Etiam non dapibus eros. Donec fringilla dui sed " | ||||
|                       "augue pretium, nec scelerisque est maximus. Nullam convallis, sem nec blandit maximus, nisi turpis ornare " | ||||
|                       "nisl, sit amet volutpat neque massa eu odio. Maecenas malesuada quam ex, posuere congue nibh turpis duis."; | ||||
| 
 | ||||
|     for (auto _ : state) | ||||
|     { | ||||
|         logger->info(msg); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void bench_logger(benchmark::State &state, std::shared_ptr<spdlog::logger> logger) | ||||
| { | ||||
|     int i = 0; | ||||
|     for (auto _ : state) | ||||
|     { | ||||
|         logger->info("Hello logger: msg number {}...............", ++i); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void bench_logger_fmt_string(benchmark::State &state, std::shared_ptr<spdlog::logger> logger) | ||||
| { | ||||
|     int i = 0; | ||||
|     for (auto _ : state) | ||||
|     { | ||||
|         logger->info(FMT_STRING("Hello logger: msg number {}..............."), ++i); | ||||
|         ; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void bench_disabled_macro(benchmark::State &state, std::shared_ptr<spdlog::logger> logger) | ||||
| { | ||||
|     int i = 0; | ||||
|     benchmark::DoNotOptimize(i);      // prevent unused warnings
 | ||||
|     benchmark::DoNotOptimize(logger); // prevent unused warnings
 | ||||
|     for (auto _ : state) | ||||
|     { | ||||
|         SPDLOG_LOGGER_DEBUG(logger, "Hello logger: msg number {}...............", i++); | ||||
|         SPDLOG_DEBUG("Hello logger: msg number {}...............", i++); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #ifdef __linux__ | ||||
| void bench_dev_null() | ||||
| { | ||||
|     auto dev_null_st = spdlog::basic_logger_st("/dev/null_st", "/dev/null"); | ||||
|     benchmark::RegisterBenchmark("/dev/null_st", bench_logger, std::move(dev_null_st))->UseRealTime(); | ||||
|     spdlog::drop("/dev/null_st"); | ||||
| 
 | ||||
|     auto dev_null_mt = spdlog::basic_logger_mt("/dev/null_mt", "/dev/null"); | ||||
|     benchmark::RegisterBenchmark("/dev/null_mt", bench_logger, std::move(dev_null_mt))->UseRealTime(); | ||||
|     spdlog::drop("/dev/null_mt"); | ||||
| } | ||||
| #endif // __linux__
 | ||||
| 
 | ||||
| int main(int argc, char *argv[]) | ||||
| { | ||||
|     using spdlog::sinks::null_sink_mt; | ||||
|     using spdlog::sinks::null_sink_st; | ||||
| 
 | ||||
|     size_t file_size = 30 * 1024 * 1024; | ||||
|     size_t rotating_files = 5; | ||||
|     int n_threads = benchmark::CPUInfo::Get().num_cpus; | ||||
| 
 | ||||
|     auto full_bench = argc > 1 && std::string(argv[1]) == "full"; | ||||
| 
 | ||||
|     // disabled loggers
 | ||||
|     auto disabled_logger = std::make_shared<spdlog::logger>("bench", std::make_shared<null_sink_mt>()); | ||||
|     disabled_logger->set_level(spdlog::level::off); | ||||
|     benchmark::RegisterBenchmark("disabled-at-compile-time", bench_disabled_macro, 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>()); | ||||
|     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_fmt_string", bench_logger_fmt_string, 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); | ||||
| 
 | ||||
| #ifdef __linux | ||||
|     bench_dev_null(); | ||||
| #endif // __linux__
 | ||||
| 
 | ||||
|     if (full_bench) | ||||
|     { | ||||
|         // basic_st
 | ||||
|         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(); | ||||
|         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
 | ||||
|         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(); | ||||
|         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
 | ||||
|         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(); | ||||
|         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
 | ||||
|         //
 | ||||
|         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(); | ||||
| 
 | ||||
|         // basic_mt
 | ||||
|         auto basic_mt = spdlog::basic_logger_mt("basic_mt", "latency_logs/basic_mt.log", true); | ||||
|         benchmark::RegisterBenchmark("basic_mt", bench_logger, std::move(basic_mt))->Threads(n_threads)->UseRealTime(); | ||||
|         spdlog::drop("basic_mt"); | ||||
| 
 | ||||
|         // rotating mt
 | ||||
|         auto rotating_mt = spdlog::rotating_logger_mt("rotating_mt", "latency_logs/rotating_mt.log", file_size, rotating_files); | ||||
|         benchmark::RegisterBenchmark("rotating_mt", bench_logger, std::move(rotating_mt))->Threads(n_threads)->UseRealTime(); | ||||
|         spdlog::drop("rotating_mt"); | ||||
| 
 | ||||
|         // daily mt
 | ||||
|         auto daily_mt = spdlog::daily_logger_mt("daily_mt", "latency_logs/daily_mt.log"); | ||||
|         benchmark::RegisterBenchmark("daily_mt", bench_logger, std::move(daily_mt))->Threads(n_threads)->UseRealTime(); | ||||
|         spdlog::drop("daily_mt"); | ||||
|     } | ||||
| 
 | ||||
|     // async
 | ||||
|     auto queue_size = 1024 * 1024 * 3; | ||||
|     auto tp = std::make_shared<spdlog::details::thread_pool>(queue_size, 1); | ||||
|     auto async_logger = std::make_shared<spdlog::async_logger>( | ||||
|         "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(); | ||||
| 
 | ||||
|     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::RunSpecifiedBenchmarks(); | ||||
| } | ||||
							
								
								
									
										34
									
								
								Dependencies/spdlog/bench/utils.h
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										34
									
								
								Dependencies/spdlog/bench/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
 | ||||
							
								
								
									
										18
									
								
								Dependencies/spdlog/cmake/ide.cmake
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										18
									
								
								Dependencies/spdlog/cmake/ide.cmake
									
										
									
									
										vendored
									
									
								
							|  | @ -1,18 +0,0 @@ | |||
| # --------------------------------------------------------------------------------------- | ||||
| # 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}) | ||||
							
								
								
									
										258
									
								
								Dependencies/spdlog/cmake/pch.h.in
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										258
									
								
								Dependencies/spdlog/cmake/pch.h.in
									
										
									
									
										vendored
									
									
								
							|  | @ -1,258 +0,0 @@ | |||
| // Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
 | ||||
| // Distributed under the MIT License (http://opensource.org/licenses/MIT)
 | ||||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| // details/pattern_formatter-inl.h
 | ||||
| // fmt/bin_to_hex.h
 | ||||
| // fmt/bundled/format-inl.h
 | ||||
| #include <cctype> | ||||
| 
 | ||||
| // details/file_helper-inl.h
 | ||||
| // details/os-inl.h
 | ||||
| // fmt/bundled/core.h
 | ||||
| // fmt/bundled/posix.h
 | ||||
| // logger-inl.h
 | ||||
| // sinks/daily_file_sink.h
 | ||||
| // sinks/stdout_sinks.h
 | ||||
| #include <cstdio> | ||||
| 
 | ||||
| // details/os-inl.h
 | ||||
| // fmt/bundled/posix.h
 | ||||
| #include <cstdlib> | ||||
| 
 | ||||
| // details/os-inl.h
 | ||||
| // details/pattern_formatter-inl.h
 | ||||
| // fmt/bundled/core.h
 | ||||
| // fmt/bundled/format-inl.h
 | ||||
| #include <cstring> | ||||
| 
 | ||||
| // details/os-inl.h
 | ||||
| // details/os.h
 | ||||
| // details/pattern_formatter-inl.h
 | ||||
| // details/pattern_formatter.h
 | ||||
| // fmt/bundled/chrono.h
 | ||||
| // sinks/daily_file_sink.h
 | ||||
| // sinks/rotating_file_sink-inl.h
 | ||||
| #include <ctime> | ||||
| 
 | ||||
| // fmt/bundled/format-inl.h
 | ||||
| #include <climits> | ||||
| 
 | ||||
| // fmt/bundled/format-inl.h
 | ||||
| #include <cwchar> | ||||
| 
 | ||||
| // fmt/bundled/format-inl.h
 | ||||
| // fmt/bundled/format.h
 | ||||
| #include <cmath> | ||||
| 
 | ||||
| // fmt/bundled/format-inl.h
 | ||||
| #include <cstdarg> | ||||
| 
 | ||||
| // details/file_helper-inl.h
 | ||||
| // fmt/bundled/format.h
 | ||||
| // fmt/bundled/posix.h
 | ||||
| // sinks/rotating_file_sink-inl.h
 | ||||
| #include <cerrno> | ||||
| 
 | ||||
| // details/circular_q.h
 | ||||
| // details/thread_pool-inl.h
 | ||||
| // fmt/bundled/format-inl.h
 | ||||
| #include <cassert> | ||||
| 
 | ||||
| // async_logger-inl.h
 | ||||
| // cfg/helpers-inl.h
 | ||||
| // log_levels.h
 | ||||
| // common.h
 | ||||
| // details/file_helper-inl.h
 | ||||
| // details/log_msg.h
 | ||||
| // details/os-inl.h
 | ||||
| // details/pattern_formatter-inl.h
 | ||||
| // details/pattern_formatter.h
 | ||||
| // details/registry-inl.h
 | ||||
| // details/registry.h
 | ||||
| // details/tcp_client-windows.h
 | ||||
| // details/tcp_client.h
 | ||||
| // fmt/bundled/core.h
 | ||||
| // sinks/android_sink.h
 | ||||
| // sinks/ansicolor_sink.h
 | ||||
| // sinks/basic_file_sink.h
 | ||||
| // sinks/daily_file_sink.h
 | ||||
| // sinks/dup_filter_sink.h
 | ||||
| // sinks/msvc_sink.h
 | ||||
| // sinks/ringbuffer_sink.h
 | ||||
| // sinks/rotating_file_sink-inl.h
 | ||||
| // sinks/rotating_file_sink.h
 | ||||
| // sinks/syslog_sink.h
 | ||||
| // sinks/tcp_sink.h
 | ||||
| // sinks/win_eventlog_sink.h
 | ||||
| // sinks/wincolor_sink.h
 | ||||
| // spdlog.h:
 | ||||
| #include <string> | ||||
| 
 | ||||
| // cfg/helpers-inl.h
 | ||||
| // fmt/bundled/chrono.h
 | ||||
| #include <sstream> | ||||
| 
 | ||||
| // fmt/bundled/ostream.h
 | ||||
| // sinks/ostream_sink.h
 | ||||
| #include <ostream> | ||||
| 
 | ||||
| // cfg/log_levels.h
 | ||||
| // details/registry-inl.h
 | ||||
| // details/registry.h
 | ||||
| #include <unordered_map> | ||||
| 
 | ||||
| // details/circular_q.h
 | ||||
| // details/pattern_formatter-inl.h
 | ||||
| // details/pattern_formatter.h
 | ||||
| // details/thread_pool.h
 | ||||
| // fmt/bundled/compile.h
 | ||||
| // logger.h
 | ||||
| // sinks/dist_sink.h
 | ||||
| // sinks/ringbuffer_sink.h
 | ||||
| // sinks/win_eventlog_sink.h
 | ||||
| #include <vector> | ||||
| 
 | ||||
| // details/os-inl.h
 | ||||
| // details/pattern_formatter-inl.h
 | ||||
| // sinks/ansicolor_sink.h
 | ||||
| // sinks/syslog_sink.h
 | ||||
| // sinks/systemd_sink.h
 | ||||
| // sinks/wincolor_sink.h
 | ||||
| #include <array> | ||||
| 
 | ||||
| // details/file_helper-inl.h
 | ||||
| // details/file_helper.h
 | ||||
| // sinks/rotating_file_sink-inl.h
 | ||||
| #include <tuple> | ||||
| 
 | ||||
| // details/os-inl.h
 | ||||
| // fmt/bundled/format.h
 | ||||
| // fmt/bundled/printf.h
 | ||||
| #include <limits> | ||||
| 
 | ||||
| // common.h
 | ||||
| // details/backtracer.h
 | ||||
| // details/null_mutex.h
 | ||||
| #include <atomic> | ||||
| 
 | ||||
| // common.h
 | ||||
| // details/backtracer.h
 | ||||
| // details/null_mutex.h
 | ||||
| #include <locale> | ||||
| 
 | ||||
| // common.h
 | ||||
| #include <initializer_list> | ||||
| 
 | ||||
| // common.h
 | ||||
| #include <exception> | ||||
| 
 | ||||
| // common.h
 | ||||
| // details/fmt_helper.h
 | ||||
| // fmt/bundled/core.h
 | ||||
| // fmt/bundled/ranges.h
 | ||||
| #include <type_traits> | ||||
| 
 | ||||
| // cfg/helpers-inl.h
 | ||||
| // details/null_mutex.h
 | ||||
| // details/pattern_formatter-inl.h
 | ||||
| #include <utility> | ||||
| 
 | ||||
| // async.h
 | ||||
| // async_logger-inl.h
 | ||||
| // common.h
 | ||||
| // details/pattern_formatter-inl.h
 | ||||
| // details/pattern_formatter.h
 | ||||
| // details/registry-inl.h
 | ||||
| // details/registry.h
 | ||||
| // details/thread_pool.h
 | ||||
| // fmt/bundled/format.h
 | ||||
| // sinks/ansicolor_sink.h
 | ||||
| // sinks/base_sink-inl.h
 | ||||
| // sinks/dist_sink.h
 | ||||
| // sinks/stdout_sinks-inl.h
 | ||||
| // sinks/wincolor_sink.h
 | ||||
| // spdlog.h
 | ||||
| #include <memory> | ||||
| 
 | ||||
| // async.h
 | ||||
| // common.h
 | ||||
| // details/backtracer.h
 | ||||
| // details/periodic_worker.h
 | ||||
| // details/registry-inl.h
 | ||||
| // details/registry.h
 | ||||
| // details/thread_pool.h
 | ||||
| // sinks/tcp_sink.h
 | ||||
| // spdlog.h
 | ||||
| #include <functional> | ||||
| 
 | ||||
| // details/mpmc_blocking_q.h
 | ||||
| // details/periodic_worker.h
 | ||||
| #include <condition_variable> | ||||
| 
 | ||||
| // details/os-inl.h
 | ||||
| // fmt/bundled/format.h
 | ||||
| // fmt/bundled/printf.h
 | ||||
| // sinks/dist_sink.h
 | ||||
| #include <algorithm> | ||||
| 
 | ||||
| // common.h
 | ||||
| // details/file_helper-inl.h
 | ||||
| // details/fmt_helper.h
 | ||||
| // details/os-inl.h
 | ||||
| // details/pattern_formatter-inl.h
 | ||||
| // details/pattern_formatter.h
 | ||||
| // details/periodic_worker.h
 | ||||
| // details/registry-inl.h
 | ||||
| // details/registry.h
 | ||||
| // details/thread_pool.h
 | ||||
| // fmt/bundled/chrono.h
 | ||||
| // sinks/android_sink.h
 | ||||
| // sinks/daily_file_sink.h
 | ||||
| // sinks/dup_filter_sink.h
 | ||||
| // sinks/rotating_file_sink-inl.h
 | ||||
| // sinks/rotating_file_sink.h
 | ||||
| // sinks/tcp_sink.h
 | ||||
| // spdlog.h
 | ||||
| #include <chrono> | ||||
| 
 | ||||
| // details/file_helper-inl.h
 | ||||
| // details/os-inl.h
 | ||||
| // details/pattern_formatter-inl.h
 | ||||
| // details/periodic_worker.h
 | ||||
| // details/thread_pool.h
 | ||||
| // sinks/android_sink.h
 | ||||
| #include <thread> | ||||
| 
 | ||||
| // async.h
 | ||||
| // details/backtracer.h
 | ||||
| // details/console_globals.h
 | ||||
| // details/mpmc_blocking_q.h
 | ||||
| // details/pattern_formatter-inl.h
 | ||||
| // details/periodic_worker.h
 | ||||
| // details/registry.h
 | ||||
| // sinks/android_sink.h
 | ||||
| // sinks/ansicolor_sink.h
 | ||||
| // sinks/basic_file_sink.h
 | ||||
| // sinks/daily_file_sink.h
 | ||||
| // sinks/dist_sink.h
 | ||||
| // sinks/dup_filter_sink.h
 | ||||
| // sinks/msvc_sink.h
 | ||||
| // sinks/null_sink.h
 | ||||
| // sinks/ostream_sink.h
 | ||||
| // sinks/ringbuffer_sink.h
 | ||||
| // sinks/rotating_file_sink-inl.h
 | ||||
| // sinks/rotating_file_sink.h
 | ||||
| // sinks/tcp_sink.h
 | ||||
| // sinks/win_eventlog_sink.h
 | ||||
| // sinks/wincolor_sink.h
 | ||||
| //
 | ||||
| // color_sinks.cpp
 | ||||
| // file_sinks.cpp
 | ||||
| // spdlog.cpp
 | ||||
| // stdout_sinks.cpp
 | ||||
| #include <mutex> | ||||
| 
 | ||||
| // spdlog
 | ||||
| #include <spdlog/common.h> | ||||
							
								
								
									
										13
									
								
								Dependencies/spdlog/cmake/spdlog.pc.in
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										13
									
								
								Dependencies/spdlog/cmake/spdlog.pc.in
									
										
									
									
										vendored
									
									
								
							|  | @ -1,13 +0,0 @@ | |||
| prefix=@CMAKE_INSTALL_PREFIX@ | ||||
| exec_prefix=${prefix} | ||||
| includedir=${prefix}/include | ||||
| libdir=${exec_prefix}/@CMAKE_INSTALL_LIBDIR@ | ||||
| 
 | ||||
| Name: lib@PROJECT_NAME@ | ||||
| Description: Fast C++ logging library. | ||||
| URL: https://github.com/gabime/@PROJECT_NAME@ | ||||
| Version: @SPDLOG_VERSION@ | ||||
| CFlags: -I${includedir} @PKG_CONFIG_DEFINES@ | ||||
| Libs: -L${libdir} -lspdlog -pthread | ||||
| Requires: @PKG_CONFIG_REQUIRES@ | ||||
| 
 | ||||
							
								
								
									
										60
									
								
								Dependencies/spdlog/cmake/spdlogCPack.cmake
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										60
									
								
								Dependencies/spdlog/cmake/spdlogCPack.cmake
									
										
									
									
										vendored
									
									
								
							|  | @ -1,60 +0,0 @@ | |||
| set(CPACK_GENERATOR "TGZ;ZIP" CACHE STRING "Semicolon separated list of generators") | ||||
| 
 | ||||
| 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 CACHE BOOL "Build relocatable package") | ||||
| 
 | ||||
| set(CPACK_RPM_PACKAGE_LICENSE "MIT") | ||||
| set(CPACK_RPM_PACKAGE_GROUP "Development/Libraries") | ||||
| set(CPACK_DEBIAN_PACKAGE_SECTION "libs") | ||||
| set(CPACK_RPM_PACKAGE_URL ${CPACK_PROJECT_URL}) | ||||
| set(CPACK_DEBIAN_PACKAGE_HOMEPAGE ${CPACK_PROJECT_URL}) | ||||
| set(CPACK_RPM_PACKAGE_DESCRIPTION "Very fast, header-only/compiled, C++ logging library.") | ||||
| set(CPACK_DEBIAN_PACKAGE_DESCRIPTION "Very fast, header-only/compiled, C++ logging library.") | ||||
| 
 | ||||
| if(CPACK_PACKAGE_NAME) | ||||
|     set(CPACK_RPM_FILE_NAME "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}") | ||||
|     set(CPACK_DEBIAN_FILE_NAME "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}") | ||||
| else() | ||||
|     set(CPACK_RPM_FILE_NAME "${PROJECT_NAME}-${CPACK_PACKAGE_VERSION}") | ||||
|     set(CPACK_DEBIAN_FILE_NAME "${PROJECT_NAME}-${CPACK_PACKAGE_VERSION}") | ||||
|     set(CPACK_RPM_PACKAGE_NAME "${PROJECT_NAME}") | ||||
|     set(CPACK_DEBIAN_PACKAGE_NAME "${PROJECT_NAME}") | ||||
| endif() | ||||
| 
 | ||||
| if(CPACK_RPM_PACKAGE_RELEASE) | ||||
|     set(CPACK_RPM_FILE_NAME "${CPACK_RPM_FILE_NAME}-${CPACK_RPM_PACKAGE_RELEASE}") | ||||
| endif() | ||||
| if(CPACK_DEBIAN_PACKAGE_RELEASE) | ||||
|     set(CPACK_DEBIAN_FILE_NAME "${CPACK_DEBIAN_FILE_NAME}-${CPACK_DEBIAN_PACKAGE_RELEASE}") | ||||
| endif() | ||||
| 
 | ||||
| if(CPACK_RPM_PACKAGE_ARCHITECTURE) | ||||
|     set(CPACK_RPM_FILE_NAME "${CPACK_RPM_FILE_NAME}.${CPACK_RPM_PACKAGE_ARCHITECTURE}") | ||||
| endif() | ||||
| if(CPACK_DEBIAN_PACKAGE_ARCHITECTURE) | ||||
|     set(CPACK_DEBIAN_FILE_NAME "${CPACK_DEBIAN_FILE_NAME}.${CPACK_DEBIAN_PACKAGE_ARCHITECTURE}") | ||||
| endif() | ||||
| set(CPACK_RPM_FILE_NAME "${CPACK_RPM_FILE_NAME}.rpm") | ||||
| set(CPACK_DEBIAN_FILE_NAME "${CPACK_DEBIAN_FILE_NAME}.deb") | ||||
| 
 | ||||
| if(NOT CPACK_PACKAGE_RELOCATABLE) | ||||
|     # Depend on pkgconfig rpm to create the system pkgconfig folder | ||||
|     set(CPACK_RPM_PACKAGE_REQUIRES pkgconfig) | ||||
|     set(CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST_ADDITION | ||||
|         "${CPACK_PACKAGING_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}/pkgconfig") | ||||
| endif() | ||||
| 
 | ||||
| include(CPack) | ||||
							
								
								
									
										20
									
								
								Dependencies/spdlog/cmake/spdlogConfig.cmake.in
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										20
									
								
								Dependencies/spdlog/cmake/spdlogConfig.cmake.in
									
										
									
									
										vendored
									
									
								
							|  | @ -1,20 +0,0 @@ | |||
| # Copyright(c) 2019 spdlog authors | ||||
| # Distributed under the MIT License (http://opensource.org/licenses/MIT) | ||||
| 
 | ||||
| @PACKAGE_INIT@ | ||||
| 
 | ||||
| find_package(Threads REQUIRED) | ||||
| 
 | ||||
| set(SPDLOG_FMT_EXTERNAL @SPDLOG_FMT_EXTERNAL@) | ||||
| set(SPDLOG_FMT_EXTERNAL_HO @SPDLOG_FMT_EXTERNAL_HO@) | ||||
| set(config_targets_file @config_targets_file@) | ||||
| 
 | ||||
| if(SPDLOG_FMT_EXTERNAL OR SPDLOG_FMT_EXTERNAL_HO) | ||||
|     include(CMakeFindDependencyMacro) | ||||
|     find_dependency(fmt CONFIG) | ||||
| endif() | ||||
| 
 | ||||
| 
 | ||||
| include("${CMAKE_CURRENT_LIST_DIR}/${config_targets_file}") | ||||
| 
 | ||||
| check_required_components(spdlog) | ||||
							
								
								
									
										62
									
								
								Dependencies/spdlog/cmake/utils.cmake
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										62
									
								
								Dependencies/spdlog/cmake/utils.cmake
									
										
									
									
										vendored
									
									
								
							|  | @ -1,62 +0,0 @@ | |||
| # 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_MINOR ${ver_minor} PARENT_SCOPE) | ||||
|     set(SPDLOG_VERSION_PATCH ${ver_patch} 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) | ||||
|     if(SPDLOG_BUILD_WARNINGS) | ||||
|         if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") | ||||
|             list(APPEND MSVC_OPTIONS "/W3") | ||||
|             if(MSVC_VERSION GREATER 1900) # Allow non fatal security warnings for msvc 2015 | ||||
|                 list(APPEND MSVC_OPTIONS "/WX") | ||||
|             endif() | ||||
|         endif() | ||||
| 
 | ||||
|         target_compile_options( | ||||
|             ${target_name} | ||||
|             PRIVATE $<$<OR:$<CXX_COMPILER_ID:Clang>,$<CXX_COMPILER_ID:AppleClang>,$<CXX_COMPILER_ID:GNU>>: | ||||
|                     -Wall | ||||
|                     -Wextra | ||||
|                     -Wconversion | ||||
|                     -pedantic | ||||
|                     -Werror | ||||
|                     -Wfatal-errors> | ||||
|                     $<$<CXX_COMPILER_ID:MSVC>:${MSVC_OPTIONS}>) | ||||
|     endif() | ||||
| 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() | ||||
							
								
								
									
										42
									
								
								Dependencies/spdlog/cmake/version.rc.in
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										42
									
								
								Dependencies/spdlog/cmake/version.rc.in
									
										
									
									
										vendored
									
									
								
							|  | @ -1,42 +0,0 @@ | |||
| #define APSTUDIO_READONLY_SYMBOLS | ||||
| #include <windows.h> | ||||
| #undef APSTUDIO_READONLY_SYMBOLS | ||||
| 
 | ||||
| LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US | ||||
| 
 | ||||
| 
 | ||||
| VS_VERSION_INFO VERSIONINFO | ||||
|  FILEVERSION @SPDLOG_VERSION_MAJOR@,@SPDLOG_VERSION_MINOR@,@SPDLOG_VERSION_PATCH@,0 | ||||
|  PRODUCTVERSION @SPDLOG_VERSION_MAJOR@,@SPDLOG_VERSION_MINOR@,@SPDLOG_VERSION_PATCH@,0 | ||||
|  FILEFLAGSMASK 0x3fL | ||||
| #ifdef _DEBUG | ||||
|  FILEFLAGS 0x1L | ||||
| #else | ||||
|  FILEFLAGS 0x0L | ||||
| #endif | ||||
|  FILEOS 0x40004L | ||||
|  FILETYPE 0x2L | ||||
|  FILESUBTYPE 0x0L | ||||
| BEGIN | ||||
|     BLOCK "StringFileInfo" | ||||
|     BEGIN | ||||
|         BLOCK "040904b0" | ||||
|         BEGIN | ||||
|             VALUE "FileDescription", "spdlog dll\0" | ||||
|             VALUE "FileVersion", "@SPDLOG_VERSION@.0\0" | ||||
|             VALUE "InternalName", "spdlog.dll\0" | ||||
|             VALUE "LegalCopyright", "Copyright (C) spdlog\0" | ||||
|             VALUE "ProductName", "spdlog\0" | ||||
|             VALUE "ProductVersion", "@SPDLOG_VERSION@.0\0" | ||||
|         END | ||||
|     END | ||||
|     BLOCK "VarFileInfo" | ||||
|     BEGIN | ||||
|         VALUE "Translation", 0x409, 1200 | ||||
|     END | ||||
| END | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
							
								
								
									
										23
									
								
								Dependencies/spdlog/example/CMakeLists.txt
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										23
									
								
								Dependencies/spdlog/example/CMakeLists.txt
									
										
									
									
										vendored
									
									
								
							|  | @ -1,23 +0,0 @@ | |||
| # Copyright(c) 2019 spdlog authors Distributed under the MIT License (http://opensource.org/licenses/MIT) | ||||
| 
 | ||||
| cmake_minimum_required(VERSION 3.10) | ||||
| project(spdlog_examples CXX) | ||||
| 
 | ||||
| if(NOT TARGET spdlog) | ||||
|     # Stand-alone build | ||||
|     find_package(spdlog REQUIRED) | ||||
| endif() | ||||
| 
 | ||||
| # --------------------------------------------------------------------------------------- | ||||
| # Example of using pre-compiled library | ||||
| # --------------------------------------------------------------------------------------- | ||||
| add_executable(example example.cpp) | ||||
| target_link_libraries(example PRIVATE spdlog::spdlog) | ||||
| 
 | ||||
| # --------------------------------------------------------------------------------------- | ||||
| # Example of using header-only library | ||||
| # --------------------------------------------------------------------------------------- | ||||
| if(SPDLOG_BUILD_EXAMPLE_HO) | ||||
|     add_executable(example_header_only example.cpp) | ||||
|     target_link_libraries(example_header_only PRIVATE spdlog::spdlog_header_only) | ||||
| endif() | ||||
							
								
								
									
										369
									
								
								Dependencies/spdlog/example/example.cpp
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										369
									
								
								Dependencies/spdlog/example/example.cpp
									
										
									
									
										vendored
									
									
								
							|  | @ -1,369 +0,0 @@ | |||
| //
 | ||||
| // Copyright(c) 2015 Gabi Melman.
 | ||||
| // Distributed under the MIT License (http://opensource.org/licenses/MIT)
 | ||||
| 
 | ||||
| // spdlog usage example
 | ||||
| 
 | ||||
| #include <cstdio> | ||||
| #include <chrono> | ||||
| 
 | ||||
| void load_levels_example(); | ||||
| void stdout_logger_example(); | ||||
| void basic_example(); | ||||
| void rotating_example(); | ||||
| void daily_example(); | ||||
| void async_example(); | ||||
| void binary_example(); | ||||
| void vector_example(); | ||||
| void stopwatch_example(); | ||||
| void trace_example(); | ||||
| void multi_sink_example(); | ||||
| void user_defined_example(); | ||||
| void err_handler_example(); | ||||
| void syslog_example(); | ||||
| void udp_example(); | ||||
| void custom_flags_example(); | ||||
| void file_events_example(); | ||||
| void replace_default_logger_example(); | ||||
| 
 | ||||
| #include "spdlog/spdlog.h" | ||||
| #include "spdlog/cfg/env.h"  // support for loading levels from the environment variable
 | ||||
| #include "spdlog/fmt/ostr.h" // support for user defined types
 | ||||
| 
 | ||||
| int main(int, char *[]) | ||||
| { | ||||
|     // Log levels can be loaded from argv/env using "SPDLOG_LEVEL"
 | ||||
|     load_levels_example(); | ||||
| 
 | ||||
|     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::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("Positional args are {1} {0}..", "too", "supported"); | ||||
|     spdlog::info("{:>8} aligned, {:<8} aligned", "right", "left"); | ||||
| 
 | ||||
|     // Runtime log levels
 | ||||
|     spdlog::set_level(spdlog::level::info); // Set global log level to info
 | ||||
|     spdlog::debug("This message should not be displayed!"); | ||||
|     spdlog::set_level(spdlog::level::trace); // Set specific logger's log level
 | ||||
|     spdlog::debug("This message should be displayed.."); | ||||
| 
 | ||||
|     // Customize msg format for all loggers
 | ||||
|     spdlog::set_pattern("[%H:%M:%S %z] [%^%L%$] [thread %t] %v"); | ||||
|     spdlog::info("This an info message with custom 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 | ||||
|     { | ||||
|         stdout_logger_example(); | ||||
|         basic_example(); | ||||
|         rotating_example(); | ||||
|         daily_example(); | ||||
|         async_example(); | ||||
|         binary_example(); | ||||
|         vector_example(); | ||||
|         multi_sink_example(); | ||||
|         user_defined_example(); | ||||
|         err_handler_example(); | ||||
|         trace_example(); | ||||
|         stopwatch_example(); | ||||
|         udp_example(); | ||||
|         custom_flags_example(); | ||||
|         file_events_example(); | ||||
|         replace_default_logger_example(); | ||||
| 
 | ||||
|         // Flush all *registered* loggers using a worker thread every 3 seconds.
 | ||||
|         // note: registered loggers *must* be thread safe for this to work correctly!
 | ||||
|         spdlog::flush_every(std::chrono::seconds(3)); | ||||
| 
 | ||||
|         // Apply some function on all registered loggers
 | ||||
|         spdlog::apply_all([&](std::shared_ptr<spdlog::logger> l) { l->info("End of example."); }); | ||||
| 
 | ||||
|         // Release all spdlog resources, and drop all loggers in the registry.
 | ||||
|         // This is optional (only mandatory if using windows + async log).
 | ||||
|         spdlog::shutdown(); | ||||
|     } | ||||
| 
 | ||||
|     // Exceptions will only be thrown upon failed logger or sink construction (not during logging).
 | ||||
|     catch (const spdlog::spdlog_ex &ex) | ||||
|     { | ||||
|         std::printf("Log initialization failed: %s\n", ex.what()); | ||||
|         return 1; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #include "spdlog/sinks/stdout_color_sinks.h" | ||||
| // or #include "spdlog/sinks/stdout_sinks.h" if no colors needed.
 | ||||
| void stdout_logger_example() | ||||
| { | ||||
|     // Create color multi threaded logger.
 | ||||
|     auto console = spdlog::stdout_color_mt("console"); | ||||
|     // or for stderr:
 | ||||
|     // auto console = spdlog::stderr_color_mt("error-logger");
 | ||||
| } | ||||
| 
 | ||||
| #include "spdlog/sinks/basic_file_sink.h" | ||||
| void basic_example() | ||||
| { | ||||
|     // Create basic file logger (not rotated).
 | ||||
|     auto my_logger = spdlog::basic_logger_mt("file_logger", "logs/basic-log.txt", true); | ||||
| } | ||||
| 
 | ||||
| #include "spdlog/sinks/rotating_file_sink.h" | ||||
| void rotating_example() | ||||
| { | ||||
|     // Create a file rotating logger with 5mb size max and 3 rotated files.
 | ||||
|     auto rotating_logger = spdlog::rotating_logger_mt("some_logger_name", "logs/rotating.txt", 1048576 * 5, 3); | ||||
| } | ||||
| 
 | ||||
| #include "spdlog/sinks/daily_file_sink.h" | ||||
| void daily_example() | ||||
| { | ||||
|     // Create a daily logger - a new file is created every day on 2:30am.
 | ||||
|     auto daily_logger = spdlog::daily_logger_mt("daily_logger", "logs/daily.txt", 2, 30); | ||||
| } | ||||
| 
 | ||||
| #include "spdlog/cfg/env.h" | ||||
| void load_levels_example() | ||||
| { | ||||
|     // Set the log level to "info" and mylogger to "trace":
 | ||||
|     // SPDLOG_LEVEL=info,mylogger=trace && ./example
 | ||||
|     spdlog::cfg::load_env_levels(); | ||||
|     // or from command line:
 | ||||
|     // ./example SPDLOG_LEVEL=info,mylogger=trace
 | ||||
|     // #include "spdlog/cfg/argv.h" // for loading levels from argv
 | ||||
|     // spdlog::cfg::load_argv_levels(args, argv);
 | ||||
| } | ||||
| 
 | ||||
| #include "spdlog/async.h" | ||||
| void async_example() | ||||
| { | ||||
|     // Default thread pool settings can be modified *before* creating the async logger:
 | ||||
|     // spdlog::init_thread_pool(32768, 1); // queue with max 32k items 1 backing thread.
 | ||||
|     auto async_file = spdlog::basic_logger_mt<spdlog::async_factory>("async_file_logger", "logs/async_log.txt"); | ||||
|     // alternatively:
 | ||||
|     // auto async_file = spdlog::create_async<spdlog::sinks::basic_file_sink_mt>("async_file_logger", "logs/async_log.txt");
 | ||||
| 
 | ||||
|     for (int i = 1; i < 101; ++i) | ||||
|     { | ||||
|         async_file->info("Async message #{}", i); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| // Log binary data as hex.
 | ||||
| // Many types of std::container<char> types can be used.
 | ||||
| // Iterator ranges are supported too.
 | ||||
| // Format flags:
 | ||||
| // {:X} - print in uppercase.
 | ||||
| // {:s} - don't separate each byte with space.
 | ||||
| // {:p} - don't print the position on each line start.
 | ||||
| // {:n} - don't split the output to lines.
 | ||||
| 
 | ||||
| #include "spdlog/fmt/bin_to_hex.h" | ||||
| void binary_example() | ||||
| { | ||||
|     std::vector<char> buf(80); | ||||
|     for (int i = 0; i < 80; i++) | ||||
|     { | ||||
|         buf.push_back(static_cast<char>(i & 0xff)); | ||||
|     } | ||||
|     spdlog::info("Binary example: {}", spdlog::to_hex(buf)); | ||||
|     spdlog::info("Another binary example:{:n}", spdlog::to_hex(std::begin(buf), std::begin(buf) + 10)); | ||||
|     // more examples:
 | ||||
|     // logger->info("uppercase: {:X}", spdlog::to_hex(buf));
 | ||||
|     // logger->info("uppercase, no delimiters: {:Xs}", spdlog::to_hex(buf));
 | ||||
|     // logger->info("uppercase, no delimiters, no position info: {:Xsp}", spdlog::to_hex(buf));
 | ||||
|     // logger->info("hexdump style: {:a}", spdlog::to_hex(buf));
 | ||||
|     // logger->info("hexdump style, 20 chars per line {:a}", spdlog::to_hex(buf, 20));
 | ||||
| } | ||||
| 
 | ||||
| // Log a vector of numbers
 | ||||
| #ifndef SPDLOG_USE_STD_FORMAT | ||||
| #    include "spdlog/fmt/ranges.h" | ||||
| void vector_example() | ||||
| { | ||||
|     std::vector<int> vec = {1, 2, 3}; | ||||
|     spdlog::info("Vector example: {}", vec); | ||||
| } | ||||
| 
 | ||||
| #else | ||||
| void vector_example() {} | ||||
| #endif | ||||
| 
 | ||||
| // ! DSPDLOG_USE_STD_FORMAT
 | ||||
| 
 | ||||
| // Compile time log levels.
 | ||||
| // define SPDLOG_ACTIVE_LEVEL to required level (e.g. SPDLOG_LEVEL_TRACE)
 | ||||
| void trace_example() | ||||
| { | ||||
|     // trace from default logger
 | ||||
|     SPDLOG_TRACE("Some trace message.. {} ,{}", 1, 3.23); | ||||
|     // debug from default logger
 | ||||
|     SPDLOG_DEBUG("Some debug message.. {} ,{}", 1, 3.23); | ||||
| 
 | ||||
|     // trace from logger object
 | ||||
|     auto logger = spdlog::get("file_logger"); | ||||
|     SPDLOG_LOGGER_TRACE(logger, "another trace message"); | ||||
| } | ||||
| 
 | ||||
| // stopwatch example
 | ||||
| #include "spdlog/stopwatch.h" | ||||
| #include <thread> | ||||
| void stopwatch_example() | ||||
| { | ||||
|     spdlog::stopwatch sw; | ||||
|     std::this_thread::sleep_for(std::chrono::milliseconds(123)); | ||||
|     spdlog::info("Stopwatch: {} seconds", sw); | ||||
| } | ||||
| 
 | ||||
| #include "spdlog/sinks/udp_sink.h" | ||||
| void udp_example() | ||||
| { | ||||
|     spdlog::sinks::udp_sink_config cfg("127.0.0.1", 11091); | ||||
|     auto my_logger = spdlog::udp_logger_mt("udplog", cfg); | ||||
|     my_logger->set_level(spdlog::level::debug); | ||||
|     my_logger->info("hello world"); | ||||
| } | ||||
| 
 | ||||
| // A logger with multiple sinks (stdout and file) - each with a different format and log level.
 | ||||
| void multi_sink_example() | ||||
| { | ||||
|     auto console_sink = std::make_shared<spdlog::sinks::stdout_color_sink_mt>(); | ||||
|     console_sink->set_level(spdlog::level::warn); | ||||
|     console_sink->set_pattern("[multi_sink_example] [%^%l%$] %v"); | ||||
| 
 | ||||
|     auto file_sink = std::make_shared<spdlog::sinks::basic_file_sink_mt>("logs/multisink.txt", true); | ||||
|     file_sink->set_level(spdlog::level::trace); | ||||
| 
 | ||||
|     spdlog::logger logger("multi_sink", {console_sink, file_sink}); | ||||
|     logger.set_level(spdlog::level::debug); | ||||
|     logger.warn("this should appear in both console and file"); | ||||
|     logger.info("this message should not appear in the console, only in the file"); | ||||
| } | ||||
| 
 | ||||
| // User defined types logging
 | ||||
| struct my_type | ||||
| { | ||||
|     int i = 0; | ||||
|     explicit my_type(int i) | ||||
|         : i(i){}; | ||||
| }; | ||||
| 
 | ||||
| namespace fmt_lib = spdlog::fmt_lib; | ||||
| template<> | ||||
| struct fmt_lib::formatter<my_type> : fmt_lib::formatter<std::string> | ||||
| { | ||||
|     auto format(my_type my, format_context &ctx) -> decltype(ctx.out()) | ||||
|     { | ||||
|         return fmt_lib::format_to(ctx.out(), "[my_type i={}]", my.i); | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| void user_defined_example() | ||||
| { | ||||
|     spdlog::info("user defined type: {}", my_type(14)); | ||||
| } | ||||
| 
 | ||||
| // Custom error handler. Will be triggered on log failure.
 | ||||
| void err_handler_example() | ||||
| { | ||||
|     // can be set globally or per logger(logger->set_error_handler(..))
 | ||||
|     spdlog::set_error_handler([](const std::string &msg) { printf("*** Custom log error handler: %s ***\n", msg.c_str()); }); | ||||
| } | ||||
| 
 | ||||
| // syslog example (linux/osx/freebsd)
 | ||||
| #ifndef _WIN32 | ||||
| #    include "spdlog/sinks/syslog_sink.h" | ||||
| void syslog_example() | ||||
| { | ||||
|     std::string ident = "spdlog-example"; | ||||
|     auto syslog_logger = spdlog::syslog_logger_mt("syslog", ident, LOG_PID); | ||||
|     syslog_logger->warn("This is warning that will end up in syslog."); | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| // Android example.
 | ||||
| #if defined(__ANDROID__) | ||||
| #    include "spdlog/sinks/android_sink.h" | ||||
| void android_example() | ||||
| { | ||||
|     std::string tag = "spdlog-android"; | ||||
|     auto android_logger = spdlog::android_logger_mt("android", tag); | ||||
|     android_logger->critical("Use \"adb shell logcat\" to view this message."); | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| // Log patterns can contain custom flags.
 | ||||
| // this will add custom flag '%*' which will be bound to a <my_formatter_flag> instance
 | ||||
| #include "spdlog/pattern_formatter.h" | ||||
| class my_formatter_flag : public spdlog::custom_flag_formatter | ||||
| { | ||||
| public: | ||||
|     void format(const spdlog::details::log_msg &, const std::tm &, spdlog::memory_buf_t &dest) override | ||||
|     { | ||||
|         std::string some_txt = "custom-flag"; | ||||
|         dest.append(some_txt.data(), some_txt.data() + some_txt.size()); | ||||
|     } | ||||
| 
 | ||||
|     std::unique_ptr<custom_flag_formatter> clone() const override | ||||
|     { | ||||
|         return spdlog::details::make_unique<my_formatter_flag>(); | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| void custom_flags_example() | ||||
| { | ||||
| 
 | ||||
|     using spdlog::details::make_unique; // for pre c++14
 | ||||
|     auto formatter = make_unique<spdlog::pattern_formatter>(); | ||||
|     formatter->add_flag<my_formatter_flag>('*').set_pattern("[%n] [%*] [%^%l%$] %v"); | ||||
|     // set the new formatter using spdlog::set_formatter(formatter) or logger->set_formatter(formatter)
 | ||||
|     // spdlog::set_formatter(std::move(formatter));
 | ||||
| } | ||||
| 
 | ||||
| void file_events_example() | ||||
| { | ||||
|     // pass the spdlog::file_event_handlers to file sinks for open/close log file notifications
 | ||||
|     spdlog::file_event_handlers handlers; | ||||
|     handlers.before_open = [](spdlog::filename_t filename) { spdlog::info("Before opening {}", filename); }; | ||||
|     handlers.after_open = [](spdlog::filename_t filename, std::FILE *fstream) { | ||||
|         spdlog::info("After opening {}", filename); | ||||
|         fputs("After opening\n", fstream); | ||||
|     }; | ||||
|     handlers.before_close = [](spdlog::filename_t filename, std::FILE *fstream) { | ||||
|         spdlog::info("Before closing {}", filename); | ||||
|         fputs("Before closing\n", fstream); | ||||
|     }; | ||||
|     handlers.after_close = [](spdlog::filename_t filename) { spdlog::info("After closing {}", filename); }; | ||||
|     auto file_sink = std::make_shared<spdlog::sinks::basic_file_sink_mt>("logs/events-sample.txt", true, handlers); | ||||
|     spdlog::logger my_logger("some_logger", file_sink); | ||||
|     my_logger.info("Some log line"); | ||||
| } | ||||
| 
 | ||||
| void replace_default_logger_example() | ||||
| { | ||||
|     // store the old logger so we don't break other examples.
 | ||||
|     auto old_logger = spdlog::default_logger(); | ||||
| 
 | ||||
|     auto new_logger = spdlog::basic_logger_mt("new_default_logger", "logs/new-default-log.txt", true); | ||||
|     spdlog::set_default_logger(new_logger); | ||||
|     spdlog::set_level(spdlog::level::info); | ||||
|     spdlog::debug("This message should not be displayed!"); | ||||
|     spdlog::set_level(spdlog::level::trace); | ||||
|     spdlog::debug("This message should be displayed.."); | ||||
| 
 | ||||
|     spdlog::set_default_logger(old_logger); | ||||
| } | ||||
							
								
								
									
										99
									
								
								Dependencies/spdlog/include/spdlog/async.h
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										99
									
								
								Dependencies/spdlog/include/spdlog/async.h
									
										
									
									
										vendored
									
									
								
							|  | @ -1,99 +0,0 @@ | |||
| // Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
 | ||||
| // Distributed under the MIT License (http://opensource.org/licenses/MIT)
 | ||||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| //
 | ||||
| // Async logging using global thread pool
 | ||||
| // All loggers created here share same global thread pool.
 | ||||
| // Each log message is pushed to a queue along with a shared pointer to the
 | ||||
| // logger.
 | ||||
| // If a logger deleted while having pending messages in the queue, it's actual
 | ||||
| // destruction will defer
 | ||||
| // until all its messages are processed by the thread pool.
 | ||||
| // This is because each message in the queue holds a shared_ptr to the
 | ||||
| // originating logger.
 | ||||
| 
 | ||||
| #include <spdlog/async_logger.h> | ||||
| #include <spdlog/details/registry.h> | ||||
| #include <spdlog/details/thread_pool.h> | ||||
| 
 | ||||
| #include <memory> | ||||
| #include <mutex> | ||||
| #include <functional> | ||||
| 
 | ||||
| namespace spdlog { | ||||
| 
 | ||||
| namespace details { | ||||
| static const size_t default_async_q_size = 8192; | ||||
| } | ||||
| 
 | ||||
| // async logger factory - creates async loggers backed with thread pool.
 | ||||
| // if a global thread pool doesn't already exist, create it with default queue
 | ||||
| // size of 8192 items and single thread.
 | ||||
| template<async_overflow_policy OverflowPolicy = async_overflow_policy::block> | ||||
| struct async_factory_impl | ||||
| { | ||||
|     template<typename Sink, typename... SinkArgs> | ||||
|     static std::shared_ptr<async_logger> create(std::string logger_name, SinkArgs &&... args) | ||||
|     { | ||||
|         auto ®istry_inst = details::registry::instance(); | ||||
| 
 | ||||
|         // create global thread pool if not already exists..
 | ||||
| 
 | ||||
|         auto &mutex = registry_inst.tp_mutex(); | ||||
|         std::lock_guard<std::recursive_mutex> tp_lock(mutex); | ||||
|         auto tp = registry_inst.get_tp(); | ||||
|         if (tp == nullptr) | ||||
|         { | ||||
|             tp = std::make_shared<details::thread_pool>(details::default_async_q_size, 1U); | ||||
|             registry_inst.set_tp(tp); | ||||
|         } | ||||
| 
 | ||||
|         auto sink = std::make_shared<Sink>(std::forward<SinkArgs>(args)...); | ||||
|         auto new_logger = std::make_shared<async_logger>(std::move(logger_name), std::move(sink), std::move(tp), OverflowPolicy); | ||||
|         registry_inst.initialize_logger(new_logger); | ||||
|         return new_logger; | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| using async_factory = async_factory_impl<async_overflow_policy::block>; | ||||
| using async_factory_nonblock = async_factory_impl<async_overflow_policy::overrun_oldest>; | ||||
| 
 | ||||
| template<typename Sink, typename... SinkArgs> | ||||
| inline std::shared_ptr<spdlog::logger> create_async(std::string logger_name, SinkArgs &&... sink_args) | ||||
| { | ||||
|     return async_factory::create<Sink>(std::move(logger_name), std::forward<SinkArgs>(sink_args)...); | ||||
| } | ||||
| 
 | ||||
| template<typename Sink, typename... SinkArgs> | ||||
| inline std::shared_ptr<spdlog::logger> create_async_nb(std::string logger_name, 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, std::function<void()> on_thread_stop) | ||||
| { | ||||
|     auto tp = std::make_shared<details::thread_pool>(q_size, thread_count, on_thread_start, on_thread_stop); | ||||
|     details::registry::instance().set_tp(std::move(tp)); | ||||
| } | ||||
| 
 | ||||
| inline void init_thread_pool(size_t q_size, size_t thread_count, std::function<void()> on_thread_start) | ||||
| { | ||||
|     init_thread_pool(q_size, thread_count, on_thread_start, [] {}); | ||||
| } | ||||
| 
 | ||||
| inline void init_thread_pool(size_t q_size, size_t thread_count) | ||||
| { | ||||
|     init_thread_pool( | ||||
|         q_size, thread_count, [] {}, [] {}); | ||||
| } | ||||
| 
 | ||||
| // get the global thread pool.
 | ||||
| inline std::shared_ptr<spdlog::details::thread_pool> thread_pool() | ||||
| { | ||||
|     return details::registry::instance().get_tp(); | ||||
| } | ||||
| } // namespace spdlog
 | ||||
|  | @ -1,92 +0,0 @@ | |||
| // 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 | ||||
|     { | ||||
|         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 | ||||
|     { | ||||
|         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(msg.source) | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     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(source_loc()) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| 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; | ||||
| } | ||||
|  | @ -1,68 +0,0 @@ | |||
| // Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
 | ||||
| // Distributed under the MIT License (http://opensource.org/licenses/MIT)
 | ||||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| // Fast asynchronous logger.
 | ||||
| // Uses pre allocated queue.
 | ||||
| // Creates a single back thread to pop messages from the queue and log them.
 | ||||
| //
 | ||||
| // Upon each log write the logger:
 | ||||
| //    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
 | ||||
| //    space is available in the queue)
 | ||||
| // Upon destruction, logs all remaining messages in the queue before
 | ||||
| // destructing..
 | ||||
| 
 | ||||
| #include <spdlog/logger.h> | ||||
| 
 | ||||
| namespace spdlog { | ||||
| 
 | ||||
| // Async overflow policy - block by default.
 | ||||
| enum class async_overflow_policy | ||||
| { | ||||
|     block,         // Block until message can be enqueued
 | ||||
|     overrun_oldest // Discard oldest message in the queue if full when trying to
 | ||||
|                    // add new item.
 | ||||
| }; | ||||
| 
 | ||||
| namespace details { | ||||
| class thread_pool; | ||||
| } | ||||
| 
 | ||||
| class SPDLOG_API async_logger final : public std::enable_shared_from_this<async_logger>, public logger | ||||
| { | ||||
|     friend class details::thread_pool; | ||||
| 
 | ||||
| public: | ||||
|     template<typename It> | ||||
|     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) | ||||
|         : 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_overflow_policy overflow_policy = async_overflow_policy::block); | ||||
| 
 | ||||
|     async_logger(std::string logger_name, sink_ptr single_sink, std::weak_ptr<details::thread_pool> tp, | ||||
|         async_overflow_policy overflow_policy = async_overflow_policy::block); | ||||
| 
 | ||||
|     std::shared_ptr<logger> clone(std::string new_name) override; | ||||
| 
 | ||||
| protected: | ||||
|     void sink_it_(const details::log_msg &msg) override; | ||||
|     void flush_() override; | ||||
|     void backend_sink_it_(const details::log_msg &incoming_log_msg); | ||||
|     void backend_flush_(); | ||||
| 
 | ||||
| private: | ||||
|     std::weak_ptr<details::thread_pool> thread_pool_; | ||||
|     async_overflow_policy overflow_policy_; | ||||
| }; | ||||
| } // namespace spdlog
 | ||||
| 
 | ||||
| #ifdef SPDLOG_HEADER_ONLY | ||||
| #    include "async_logger-inl.h" | ||||
| #endif | ||||
							
								
								
									
										44
									
								
								Dependencies/spdlog/include/spdlog/cfg/argv.h
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										44
									
								
								Dependencies/spdlog/include/spdlog/cfg/argv.h
									
										
									
									
										vendored
									
									
								
							|  | @ -1,44 +0,0 @@ | |||
| // Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
 | ||||
| // Distributed under the MIT License (http://opensource.org/licenses/MIT)
 | ||||
| 
 | ||||
| #pragma once | ||||
| #include <spdlog/cfg/helpers.h> | ||||
| #include <spdlog/details/registry.h> | ||||
| 
 | ||||
| //
 | ||||
| // Init log levels using each argv entry that starts with "SPDLOG_LEVEL="
 | ||||
| //
 | ||||
| // set all loggers to debug level:
 | ||||
| // example.exe "SPDLOG_LEVEL=debug"
 | ||||
| 
 | ||||
| // set logger1 to trace level
 | ||||
| // example.exe "SPDLOG_LEVEL=logger1=trace"
 | ||||
| 
 | ||||
| // turn off all logging except for logger1 and logger2:
 | ||||
| // example.exe "SPDLOG_LEVEL=off,logger1=debug,logger2=info"
 | ||||
| 
 | ||||
| namespace spdlog { | ||||
| namespace cfg { | ||||
| 
 | ||||
| // search for SPDLOG_LEVEL= in the args and use it to init the levels
 | ||||
| inline void load_argv_levels(int argc, const char **argv) | ||||
| { | ||||
|     const std::string spdlog_level_prefix = "SPDLOG_LEVEL="; | ||||
|     for (int i = 1; i < argc; i++) | ||||
|     { | ||||
|         std::string arg = argv[i]; | ||||
|         if (arg.find(spdlog_level_prefix) == 0) | ||||
|         { | ||||
|             auto levels_string = arg.substr(spdlog_level_prefix.size()); | ||||
|             helpers::load_levels(levels_string); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| inline void load_argv_levels(int argc, char **argv) | ||||
| { | ||||
|     load_argv_levels(argc, const_cast<const char **>(argv)); | ||||
| } | ||||
| 
 | ||||
| } // namespace cfg
 | ||||
| } // namespace spdlog
 | ||||
							
								
								
									
										38
									
								
								Dependencies/spdlog/include/spdlog/cfg/env.h
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										38
									
								
								Dependencies/spdlog/include/spdlog/cfg/env.h
									
										
									
									
										vendored
									
									
								
							|  | @ -1,38 +0,0 @@ | |||
| // Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
 | ||||
| // Distributed under the MIT License (http://opensource.org/licenses/MIT)
 | ||||
| 
 | ||||
| #pragma once | ||||
| #include <spdlog/cfg/helpers.h> | ||||
| #include <spdlog/details/registry.h> | ||||
| #include <spdlog/details/os.h> | ||||
| 
 | ||||
| //
 | ||||
| // Init levels and patterns from env variables SPDLOG_LEVEL
 | ||||
| // Inspired from Rust's "env_logger" crate (https://crates.io/crates/env_logger).
 | ||||
| // Note - fallback to "info" level on unrecognized levels
 | ||||
| //
 | ||||
| // Examples:
 | ||||
| //
 | ||||
| // set global level to debug:
 | ||||
| // export SPDLOG_LEVEL=debug
 | ||||
| //
 | ||||
| // turn off all logging except for logger1:
 | ||||
| // export SPDLOG_LEVEL="*=off,logger1=debug"
 | ||||
| //
 | ||||
| 
 | ||||
| // turn off all logging except for logger1 and logger2:
 | ||||
| // export SPDLOG_LEVEL="off,logger1=debug,logger2=info"
 | ||||
| 
 | ||||
| namespace spdlog { | ||||
| namespace cfg { | ||||
| inline void load_env_levels() | ||||
| { | ||||
|     auto env_val = details::os::getenv("SPDLOG_LEVEL"); | ||||
|     if (!env_val.empty()) | ||||
|     { | ||||
|         helpers::load_levels(env_val); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| } // namespace cfg
 | ||||
| } // namespace spdlog
 | ||||
							
								
								
									
										120
									
								
								Dependencies/spdlog/include/spdlog/cfg/helpers-inl.h
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										120
									
								
								Dependencies/spdlog/include/spdlog/cfg/helpers-inl.h
									
										
									
									
										vendored
									
									
								
							|  | @ -1,120 +0,0 @@ | |||
| // 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/cfg/helpers.h> | ||||
| #endif | ||||
| 
 | ||||
| #include <spdlog/spdlog.h> | ||||
| #include <spdlog/details/os.h> | ||||
| #include <spdlog/details/registry.h> | ||||
| 
 | ||||
| #include <algorithm> | ||||
| #include <string> | ||||
| #include <utility> | ||||
| #include <sstream> | ||||
| 
 | ||||
| namespace spdlog { | ||||
| namespace cfg { | ||||
| namespace helpers { | ||||
| 
 | ||||
| // inplace convert to lowercase
 | ||||
| inline std::string &to_lower_(std::string &str) | ||||
| { | ||||
|     std::transform( | ||||
|         str.begin(), str.end(), str.begin(), [](char ch) { return static_cast<char>((ch >= 'A' && ch <= 'Z') ? ch + ('a' - 'A') : ch); }); | ||||
|     return str; | ||||
| } | ||||
| 
 | ||||
| // inplace trim spaces
 | ||||
| inline std::string &trim_(std::string &str) | ||||
| { | ||||
|     const char *spaces = " \n\r\t"; | ||||
|     str.erase(str.find_last_not_of(spaces) + 1); | ||||
|     str.erase(0, str.find_first_not_of(spaces)); | ||||
|     return str; | ||||
| } | ||||
| 
 | ||||
| // return (name,value) trimmed pair from given "name=value" string.
 | ||||
| // return empty string on missing parts
 | ||||
| // "key=val" => ("key", "val")
 | ||||
| // " key  =  val " => ("key", "val")
 | ||||
| // "key=" => ("key", "")
 | ||||
| // "val" => ("", "val")
 | ||||
| 
 | ||||
| inline std::pair<std::string, std::string> extract_kv_(char sep, const std::string &str) | ||||
| { | ||||
|     auto n = str.find(sep); | ||||
|     std::string k, v; | ||||
|     if (n == std::string::npos) | ||||
|     { | ||||
|         v = str; | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         k = str.substr(0, n); | ||||
|         v = str.substr(n + 1); | ||||
|     } | ||||
|     return std::make_pair(trim_(k), trim_(v)); | ||||
| } | ||||
| 
 | ||||
| // return vector of key/value pairs from sequence of "K1=V1,K2=V2,.."
 | ||||
| // "a=AAA,b=BBB,c=CCC,.." => {("a","AAA"),("b","BBB"),("c", "CCC"),...}
 | ||||
| inline std::unordered_map<std::string, std::string> extract_key_vals_(const std::string &str) | ||||
| { | ||||
|     std::string token; | ||||
|     std::istringstream token_stream(str); | ||||
|     std::unordered_map<std::string, std::string> rv{}; | ||||
|     while (std::getline(token_stream, token, ',')) | ||||
|     { | ||||
|         if (token.empty()) | ||||
|         { | ||||
|             continue; | ||||
|         } | ||||
|         auto kv = extract_kv_('=', token); | ||||
|         rv[kv.first] = kv.second; | ||||
|     } | ||||
|     return rv; | ||||
| } | ||||
| 
 | ||||
| SPDLOG_INLINE void load_levels(const std::string &input) | ||||
| { | ||||
|     if (input.empty() || input.size() > 512) | ||||
|     { | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     auto key_vals = extract_key_vals_(input); | ||||
|     std::unordered_map<std::string, level::level_enum> levels; | ||||
|     level::level_enum global_level = level::info; | ||||
|     bool global_level_found = false; | ||||
| 
 | ||||
|     for (auto &name_level : key_vals) | ||||
|     { | ||||
|         auto &logger_name = name_level.first; | ||||
|         auto level_name = to_lower_(name_level.second); | ||||
|         auto level = level::from_str(level_name); | ||||
|         // ignore unrecognized level names
 | ||||
|         if (level == level::off && level_name != "off") | ||||
|         { | ||||
|             continue; | ||||
|         } | ||||
|         if (logger_name.empty()) // no logger name indicate global level
 | ||||
|         { | ||||
|             global_level_found = true; | ||||
|             global_level = level; | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             levels[logger_name] = level; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     details::registry::instance().set_levels(std::move(levels), global_level_found ? &global_level : nullptr); | ||||
| } | ||||
| 
 | ||||
| } // namespace helpers
 | ||||
| } // namespace cfg
 | ||||
| } // namespace spdlog
 | ||||
							
								
								
									
										29
									
								
								Dependencies/spdlog/include/spdlog/cfg/helpers.h
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										29
									
								
								Dependencies/spdlog/include/spdlog/cfg/helpers.h
									
										
									
									
										vendored
									
									
								
							|  | @ -1,29 +0,0 @@ | |||
| // Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
 | ||||
| // Distributed under the MIT License (http://opensource.org/licenses/MIT)
 | ||||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| #include <spdlog/common.h> | ||||
| #include <unordered_map> | ||||
| 
 | ||||
| namespace spdlog { | ||||
| namespace cfg { | ||||
| namespace helpers { | ||||
| //
 | ||||
| // Init levels from given string
 | ||||
| //
 | ||||
| // Examples:
 | ||||
| //
 | ||||
| // set global level to debug: "debug"
 | ||||
| // turn off all logging except for logger1: "off,logger1=debug"
 | ||||
| // turn off all logging except for logger1 and logger2: "off,logger1=debug,logger2=info"
 | ||||
| //
 | ||||
| SPDLOG_API void load_levels(const std::string &txt); | ||||
| } // namespace helpers
 | ||||
| 
 | ||||
| } // namespace cfg
 | ||||
| } // namespace spdlog
 | ||||
| 
 | ||||
| #ifdef SPDLOG_HEADER_ONLY | ||||
| #    include "helpers-inl.h" | ||||
| #endif // SPDLOG_HEADER_ONLY
 | ||||
							
								
								
									
										82
									
								
								Dependencies/spdlog/include/spdlog/common-inl.h
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										82
									
								
								Dependencies/spdlog/include/spdlog/common-inl.h
									
										
									
									
										vendored
									
									
								
							|  | @ -1,82 +0,0 @@ | |||
| // 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 | ||||
| 
 | ||||
| #include <algorithm> | ||||
| #include <iterator> | ||||
| 
 | ||||
| namespace spdlog { | ||||
| namespace level { | ||||
| 
 | ||||
| #if __cplusplus >= 201703L | ||||
| constexpr | ||||
| #endif | ||||
|     static string_view_t level_string_views[] SPDLOG_LEVEL_NAMES; | ||||
| 
 | ||||
| static const char *short_level_names[] SPDLOG_SHORT_LEVEL_NAMES; | ||||
| 
 | ||||
| SPDLOG_INLINE const 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 | ||||
| { | ||||
|     auto it = std::find(std::begin(level_string_views), std::end(level_string_views), name); | ||||
|     if (it != std::end(level_string_views)) | ||||
|         return static_cast<level::level_enum>(it - std::begin(level_string_views)); | ||||
| 
 | ||||
|     // check also for "warn" and "err" before giving up..
 | ||||
|     if (name == "warn") | ||||
|     { | ||||
|         return level::warn; | ||||
|     } | ||||
|     if (name == "err") | ||||
|     { | ||||
|         return level::err; | ||||
|     } | ||||
|     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) | ||||
| { | ||||
| #ifdef SPDLOG_USE_STD_FORMAT | ||||
|     msg_ = std::system_error(std::error_code(last_errno, std::generic_category()), msg).what(); | ||||
| #else | ||||
|     memory_buf_t outbuf; | ||||
|     fmt::format_system_error(outbuf, last_errno, msg.c_str()); | ||||
|     msg_ = fmt::to_string(outbuf); | ||||
| #endif | ||||
| } | ||||
| 
 | ||||
| SPDLOG_INLINE const char *spdlog_ex::what() const SPDLOG_NOEXCEPT | ||||
| { | ||||
|     return msg_.c_str(); | ||||
| } | ||||
| 
 | ||||
| SPDLOG_INLINE void throw_spdlog_ex(const std::string &msg, int last_errno) | ||||
| { | ||||
|     SPDLOG_THROW(spdlog_ex(msg, last_errno)); | ||||
| } | ||||
| 
 | ||||
| SPDLOG_INLINE void throw_spdlog_ex(std::string msg) | ||||
| { | ||||
|     SPDLOG_THROW(spdlog_ex(std::move(msg))); | ||||
| } | ||||
| 
 | ||||
| } // namespace spdlog
 | ||||
							
								
								
									
										359
									
								
								Dependencies/spdlog/include/spdlog/common.h
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										359
									
								
								Dependencies/spdlog/include/spdlog/common.h
									
										
									
									
										vendored
									
									
								
							|  | @ -1,359 +0,0 @@ | |||
| // Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
 | ||||
| // Distributed under the MIT License (http://opensource.org/licenses/MIT)
 | ||||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| #include <spdlog/tweakme.h> | ||||
| #include <spdlog/details/null_mutex.h> | ||||
| 
 | ||||
| #include <atomic> | ||||
| #include <chrono> | ||||
| #include <initializer_list> | ||||
| #include <memory> | ||||
| #include <exception> | ||||
| #include <string> | ||||
| #include <type_traits> | ||||
| #include <functional> | ||||
| #include <cstdio> | ||||
| 
 | ||||
| #ifdef SPDLOG_USE_STD_FORMAT | ||||
| #    include <string_view> | ||||
| #endif | ||||
| 
 | ||||
| #ifdef SPDLOG_COMPILED_LIB | ||||
| #    undef SPDLOG_HEADER_ONLY | ||||
| #    if defined(SPDLOG_SHARED_LIB) | ||||
| #        if defined(_WIN32) | ||||
| #            ifdef spdlog_EXPORTS | ||||
| #                define SPDLOG_API __declspec(dllexport) | ||||
| #            else // !spdlog_EXPORTS
 | ||||
| #                define SPDLOG_API __declspec(dllimport) | ||||
| #            endif | ||||
| #        else // !defined(_WIN32)
 | ||||
| #            define SPDLOG_API __attribute__((visibility("default"))) | ||||
| #        endif | ||||
| #    else // !defined(SPDLOG_SHARED_LIB)
 | ||||
| #        define SPDLOG_API | ||||
| #    endif | ||||
| #    define SPDLOG_INLINE | ||||
| #else // !defined(SPDLOG_COMPILED_LIB)
 | ||||
| #    define SPDLOG_API | ||||
| #    define SPDLOG_HEADER_ONLY | ||||
| #    define SPDLOG_INLINE inline | ||||
| #endif // #ifdef SPDLOG_COMPILED_LIB
 | ||||
| 
 | ||||
| #include <spdlog/fmt/fmt.h> | ||||
| 
 | ||||
| #ifndef SPDLOG_USE_STD_FORMAT | ||||
| #    if FMT_VERSION >= 80000 // backward compatibility with fmt versions older than 8
 | ||||
| #        define SPDLOG_FMT_RUNTIME(format_string) fmt::runtime(format_string) | ||||
| #        if defined(SPDLOG_WCHAR_FILENAMES) || defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) | ||||
| #            include <spdlog/fmt/xchar.h> | ||||
| #        endif | ||||
| #    else | ||||
| #        define SPDLOG_FMT_RUNTIME(format_string) format_string | ||||
| #    endif | ||||
| #endif | ||||
| 
 | ||||
| // visual studio up to 2013 does not support noexcept nor constexpr
 | ||||
| #if defined(_MSC_VER) && (_MSC_VER < 1900) | ||||
| #    define SPDLOG_NOEXCEPT _NOEXCEPT | ||||
| #    define SPDLOG_CONSTEXPR | ||||
| #    define SPDLOG_CONSTEXPR_FUNC | ||||
| #else | ||||
| #    define SPDLOG_NOEXCEPT noexcept | ||||
| #    define SPDLOG_CONSTEXPR constexpr | ||||
| #    if __cplusplus >= 201402L | ||||
| #        define SPDLOG_CONSTEXPR_FUNC constexpr | ||||
| #    else | ||||
| #        define SPDLOG_CONSTEXPR_FUNC | ||||
| #    endif | ||||
| #endif | ||||
| 
 | ||||
| #if defined(__GNUC__) || defined(__clang__) | ||||
| #    define SPDLOG_DEPRECATED __attribute__((deprecated)) | ||||
| #elif defined(_MSC_VER) | ||||
| #    define SPDLOG_DEPRECATED __declspec(deprecated) | ||||
| #else | ||||
| #    define SPDLOG_DEPRECATED | ||||
| #endif | ||||
| 
 | ||||
| // disable thread local on msvc 2013
 | ||||
| #ifndef SPDLOG_NO_TLS | ||||
| #    if (defined(_MSC_VER) && (_MSC_VER < 1900)) || defined(__cplusplus_winrt) | ||||
| #        define SPDLOG_NO_TLS 1 | ||||
| #    endif | ||||
| #endif | ||||
| 
 | ||||
| #ifndef SPDLOG_FUNCTION | ||||
| #    define SPDLOG_FUNCTION static_cast<const char *>(__FUNCTION__) | ||||
| #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_STD | ||||
| #else | ||||
| #    define SPDLOG_TRY try | ||||
| #    define SPDLOG_THROW(ex) throw(ex) | ||||
| #    define SPDLOG_CATCH_STD                                                                                                               \ | ||||
|         catch (const std::exception &) {} | ||||
| #endif | ||||
| 
 | ||||
| namespace spdlog { | ||||
| 
 | ||||
| class formatter; | ||||
| 
 | ||||
| namespace sinks { | ||||
| class sink; | ||||
| } | ||||
| 
 | ||||
| #if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES) | ||||
| using filename_t = std::wstring; | ||||
| // allow macro expansion to occur in SPDLOG_FILENAME_T
 | ||||
| #    define SPDLOG_FILENAME_T_INNER(s) L##s | ||||
| #    define SPDLOG_FILENAME_T(s) SPDLOG_FILENAME_T_INNER(s) | ||||
| #else | ||||
| using filename_t = std::string; | ||||
| #    define SPDLOG_FILENAME_T(s) s | ||||
| #endif | ||||
| 
 | ||||
| using log_clock = std::chrono::system_clock; | ||||
| using sink_ptr = std::shared_ptr<sinks::sink>; | ||||
| using sinks_init_list = std::initializer_list<sink_ptr>; | ||||
| using err_handler = std::function<void(const std::string &err_msg)>; | ||||
| #ifdef SPDLOG_USE_STD_FORMAT | ||||
| namespace fmt_lib = std; | ||||
| 
 | ||||
| using string_view_t = std::string_view; | ||||
| using memory_buf_t = std::string; | ||||
| 
 | ||||
| template<typename... Args> | ||||
| using format_string_t = std::string_view; | ||||
| 
 | ||||
| template<class T, class Char = char> | ||||
| struct is_convertible_to_basic_format_string : std::integral_constant<bool, std::is_convertible<T, std::basic_string_view<Char>>::value> | ||||
| {}; | ||||
| 
 | ||||
| #    if defined(SPDLOG_WCHAR_FILENAMES) || defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) | ||||
| using wstring_view_t = std::wstring_view; | ||||
| using wmemory_buf_t = std::wstring; | ||||
| 
 | ||||
| template<typename... Args> | ||||
| using wformat_string_t = std::wstring_view; | ||||
| #    endif | ||||
| 
 | ||||
| #else // use fmt lib instead of std::format
 | ||||
| namespace fmt_lib = fmt; | ||||
| 
 | ||||
| using string_view_t = fmt::basic_string_view<char>; | ||||
| using memory_buf_t = fmt::basic_memory_buffer<char, 250>; | ||||
| 
 | ||||
| template<typename... Args> | ||||
| using format_string_t = fmt::format_string<Args...>; | ||||
| 
 | ||||
| template<class T> | ||||
| using remove_cvref_t = typename std::remove_cv<typename std::remove_reference<T>::type>::type; | ||||
| 
 | ||||
| // clang doesn't like SFINAE disabled constructor in std::is_convertible<> so have to repeat the condition from basic_format_string here,
 | ||||
| // in addition, fmt::basic_runtime<Char> is only convertible to basic_format_string<Char> but not basic_string_view<Char>
 | ||||
| template<class T, class Char = char> | ||||
| struct is_convertible_to_basic_format_string | ||||
|     : std::integral_constant<bool, | ||||
|           std::is_convertible<T, fmt::basic_string_view<Char>>::value || std::is_same<remove_cvref_t<T>, fmt::basic_runtime<Char>>::value> | ||||
| {}; | ||||
| 
 | ||||
| #    if defined(SPDLOG_WCHAR_FILENAMES) || defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) | ||||
| using wstring_view_t = fmt::basic_string_view<wchar_t>; | ||||
| using wmemory_buf_t = fmt::basic_memory_buffer<wchar_t, 250>; | ||||
| 
 | ||||
| template<typename... Args> | ||||
| using wformat_string_t = fmt::wformat_string<Args...>; | ||||
| #    endif | ||||
| #endif | ||||
| 
 | ||||
| #ifdef SPDLOG_WCHAR_TO_UTF8_SUPPORT | ||||
| #    ifndef _WIN32 | ||||
| #        error SPDLOG_WCHAR_TO_UTF8_SUPPORT only supported on windows | ||||
| #    endif // _WIN32
 | ||||
| #endif     // SPDLOG_WCHAR_TO_UTF8_SUPPORT
 | ||||
| 
 | ||||
| template<class T> | ||||
| struct is_convertible_to_any_format_string : std::integral_constant<bool, is_convertible_to_basic_format_string<T, char>::value || | ||||
|                                                                               is_convertible_to_basic_format_string<T, wchar_t>::value> | ||||
| {}; | ||||
| 
 | ||||
| #if defined(SPDLOG_NO_ATOMIC_LEVELS) | ||||
| using level_t = details::null_atomic_int; | ||||
| #else | ||||
| using level_t = std::atomic<int>; | ||||
| #endif | ||||
| 
 | ||||
| #define SPDLOG_LEVEL_TRACE 0 | ||||
| #define SPDLOG_LEVEL_DEBUG 1 | ||||
| #define SPDLOG_LEVEL_INFO 2 | ||||
| #define SPDLOG_LEVEL_WARN 3 | ||||
| #define SPDLOG_LEVEL_ERROR 4 | ||||
| #define SPDLOG_LEVEL_CRITICAL 5 | ||||
| #define SPDLOG_LEVEL_OFF 6 | ||||
| 
 | ||||
| #if !defined(SPDLOG_ACTIVE_LEVEL) | ||||
| #    define SPDLOG_ACTIVE_LEVEL SPDLOG_LEVEL_INFO | ||||
| #endif | ||||
| 
 | ||||
| // Log level enum
 | ||||
| namespace level { | ||||
| enum level_enum : int | ||||
| { | ||||
|     trace = SPDLOG_LEVEL_TRACE, | ||||
|     debug = SPDLOG_LEVEL_DEBUG, | ||||
|     info = SPDLOG_LEVEL_INFO, | ||||
|     warn = SPDLOG_LEVEL_WARN, | ||||
|     err = SPDLOG_LEVEL_ERROR, | ||||
|     critical = SPDLOG_LEVEL_CRITICAL, | ||||
|     off = SPDLOG_LEVEL_OFF, | ||||
|     n_levels | ||||
| }; | ||||
| 
 | ||||
| #define SPDLOG_LEVEL_NAME_TRACE spdlog::string_view_t("trace", 5) | ||||
| #define SPDLOG_LEVEL_NAME_DEBUG spdlog::string_view_t("debug", 5) | ||||
| #define SPDLOG_LEVEL_NAME_INFO spdlog::string_view_t("info", 4) | ||||
| #define SPDLOG_LEVEL_NAME_WARNING spdlog::string_view_t("warning", 7) | ||||
| #define SPDLOG_LEVEL_NAME_ERROR spdlog::string_view_t("error", 5) | ||||
| #define SPDLOG_LEVEL_NAME_CRITICAL spdlog::string_view_t("critical", 8) | ||||
| #define SPDLOG_LEVEL_NAME_OFF spdlog::string_view_t("off", 3) | ||||
| 
 | ||||
| #if !defined(SPDLOG_LEVEL_NAMES) | ||||
| #    define SPDLOG_LEVEL_NAMES                                                                                                             \ | ||||
|         {                                                                                                                                  \ | ||||
|             SPDLOG_LEVEL_NAME_TRACE, SPDLOG_LEVEL_NAME_DEBUG, SPDLOG_LEVEL_NAME_INFO, SPDLOG_LEVEL_NAME_WARNING, SPDLOG_LEVEL_NAME_ERROR,  \ | ||||
|                 SPDLOG_LEVEL_NAME_CRITICAL, SPDLOG_LEVEL_NAME_OFF                                                                          \ | ||||
|         } | ||||
| #endif | ||||
| 
 | ||||
| #if !defined(SPDLOG_SHORT_LEVEL_NAMES) | ||||
| 
 | ||||
| #    define SPDLOG_SHORT_LEVEL_NAMES                                                                                                       \ | ||||
|         {                                                                                                                                  \ | ||||
|             "T", "D", "I", "W", "E", "C", "O"                                                                                              \ | ||||
|         } | ||||
| #endif | ||||
| 
 | ||||
| SPDLOG_API const string_view_t &to_string_view(spdlog::level::level_enum l) SPDLOG_NOEXCEPT; | ||||
| SPDLOG_API const char *to_short_c_str(spdlog::level::level_enum l) SPDLOG_NOEXCEPT; | ||||
| SPDLOG_API spdlog::level::level_enum from_str(const std::string &name) SPDLOG_NOEXCEPT; | ||||
| 
 | ||||
| } // 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.
 | ||||
| // local time by default
 | ||||
| //
 | ||||
| enum class pattern_time_type | ||||
| { | ||||
|     local, // log localtime
 | ||||
|     utc    // log utc
 | ||||
| }; | ||||
| 
 | ||||
| //
 | ||||
| // Log exception
 | ||||
| //
 | ||||
| class SPDLOG_API spdlog_ex : public std::exception | ||||
| { | ||||
| public: | ||||
|     explicit spdlog_ex(std::string msg); | ||||
|     spdlog_ex(const std::string &msg, int last_errno); | ||||
|     const char *what() const SPDLOG_NOEXCEPT override; | ||||
| 
 | ||||
| private: | ||||
|     std::string msg_; | ||||
| }; | ||||
| 
 | ||||
| [[noreturn]] SPDLOG_API void throw_spdlog_ex(const std::string &msg, int last_errno); | ||||
| [[noreturn]] SPDLOG_API void throw_spdlog_ex(std::string msg); | ||||
| 
 | ||||
| struct source_loc | ||||
| { | ||||
|     SPDLOG_CONSTEXPR source_loc() = default; | ||||
|     SPDLOG_CONSTEXPR source_loc(const char *filename_in, int line_in, const char *funcname_in) | ||||
|         : filename{filename_in} | ||||
|         , line{line_in} | ||||
|         , funcname{funcname_in} | ||||
|     {} | ||||
| 
 | ||||
|     SPDLOG_CONSTEXPR bool empty() const SPDLOG_NOEXCEPT | ||||
|     { | ||||
|         return line == 0; | ||||
|     } | ||||
|     const char *filename{nullptr}; | ||||
|     int line{0}; | ||||
|     const char *funcname{nullptr}; | ||||
| }; | ||||
| 
 | ||||
| struct file_event_handlers | ||||
| { | ||||
|     std::function<void(const filename_t &filename)> before_open; | ||||
|     std::function<void(const filename_t &filename, std::FILE *file_stream)> after_open; | ||||
|     std::function<void(const filename_t &filename, std::FILE *file_stream)> before_close; | ||||
|     std::function<void(const filename_t &filename)> after_close; | ||||
|     file_event_handlers() | ||||
|         : before_open{nullptr} | ||||
|         , after_open{nullptr} | ||||
|         , before_close{nullptr} | ||||
|         , after_close{nullptr} | ||||
|     {} | ||||
| }; | ||||
| 
 | ||||
| namespace details { | ||||
| 
 | ||||
| // make_unique support for pre c++14
 | ||||
| 
 | ||||
| #if __cplusplus >= 201402L // C++14 and beyond
 | ||||
| using std::enable_if_t; | ||||
| using std::make_unique; | ||||
| #else | ||||
| template<bool B, class T = void> | ||||
| using enable_if_t = typename std::enable_if<B, T>::type; | ||||
| 
 | ||||
| template<typename T, typename... Args> | ||||
| std::unique_ptr<T> make_unique(Args &&... args) | ||||
| { | ||||
|     static_assert(!std::is_array<T>::value, "arrays not supported"); | ||||
|     return std::unique_ptr<T>(new T(std::forward<Args>(args)...)); | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| // to avoid useless casts (see https://github.com/nlohmann/json/issues/2893#issuecomment-889152324)
 | ||||
| template<typename T, typename U, enable_if_t<!std::is_same<T, U>::value, int> = 0> | ||||
| constexpr T conditional_static_cast(U value) | ||||
| { | ||||
|     return static_cast<T>(value); | ||||
| } | ||||
| 
 | ||||
| template<typename T, typename U, enable_if_t<std::is_same<T, U>::value, int> = 0> | ||||
| constexpr T conditional_static_cast(U value) | ||||
| { | ||||
|     return value; | ||||
| } | ||||
| 
 | ||||
| } // namespace details
 | ||||
| } // namespace spdlog
 | ||||
| 
 | ||||
| #ifdef SPDLOG_HEADER_ONLY | ||||
| #    include "common-inl.h" | ||||
| #endif | ||||
|  | @ -1,69 +0,0 @@ | |||
| // 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_ = std::move(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 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
 | ||||
|  | @ -1,45 +0,0 @@ | |||
| // 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 SPDLOG_API 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; | ||||
|     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,141 +0,0 @@ | |||
| // Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
 | ||||
| // Distributed under the MIT License (http://opensource.org/licenses/MIT)
 | ||||
| 
 | ||||
| // circular q view of std::vector.
 | ||||
| #pragma once | ||||
| 
 | ||||
| #include <vector> | ||||
| #include <cassert> | ||||
| 
 | ||||
| namespace spdlog { | ||||
| namespace details { | ||||
| template<typename T> | ||||
| 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: | ||||
|     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) | ||||
|         : max_items_(max_items + 1) // one item is reserved as marker for full q
 | ||||
|         , 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
 | ||||
|     void push_back(T &&item) | ||||
|     { | ||||
|         if (max_items_ > 0) | ||||
|         { | ||||
|             v_[tail_] = std::move(item); | ||||
|             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_]; | ||||
|     } | ||||
| 
 | ||||
|     // Return number of elements actually stored
 | ||||
|     size_t size() const | ||||
|     { | ||||
|         if (tail_ >= head_) | ||||
|         { | ||||
|             return tail_ - head_; | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             return max_items_ - (head_ - tail_); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     // Return const reference to item by index.
 | ||||
|     // If index is out of range 0…size()-1, the behavior is undefined.
 | ||||
|     const T &at(size_t i) const | ||||
|     { | ||||
|         assert(i < size()); | ||||
|         return v_[(head_ + i) % max_items_]; | ||||
|     } | ||||
| 
 | ||||
|     // Pop item from front.
 | ||||
|     // If there are no elements in the container, the behavior is undefined.
 | ||||
|     void pop_front() | ||||
|     { | ||||
|         head_ = (head_ + 1) % max_items_; | ||||
|     } | ||||
| 
 | ||||
|     bool empty() const | ||||
|     { | ||||
|         return tail_ == head_; | ||||
|     } | ||||
| 
 | ||||
|     bool full() const | ||||
|     { | ||||
|         // head is ahead of the tail by 1
 | ||||
|         if (max_items_ > 0) | ||||
|         { | ||||
|             return ((tail_ + 1) % max_items_) == head_; | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     size_t overrun_counter() const | ||||
|     { | ||||
|         return overrun_counter_; | ||||
|     } | ||||
| 
 | ||||
| private: | ||||
|     // copy from other&& and reset it to disabled state
 | ||||
|     void copy_moveable(circular_q &&other) SPDLOG_NOEXCEPT | ||||
|     { | ||||
|         max_items_ = other.max_items_; | ||||
|         head_ = other.head_; | ||||
|         tail_ = other.tail_; | ||||
|         overrun_counter_ = other.overrun_counter_; | ||||
|         v_ = std::move(other.v_); | ||||
| 
 | ||||
|         // put &&other in disabled, but valid state
 | ||||
|         other.max_items_ = 0; | ||||
|         other.head_ = other.tail_ = 0; | ||||
|         other.overrun_counter_ = 0; | ||||
|     } | ||||
| }; | ||||
| } // namespace details
 | ||||
| } // namespace spdlog
 | ||||
|  | @ -1,32 +0,0 @@ | |||
| // Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
 | ||||
| // Distributed under the MIT License (http://opensource.org/licenses/MIT)
 | ||||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| #include <spdlog/details/null_mutex.h> | ||||
| #include <mutex> | ||||
| 
 | ||||
| namespace spdlog { | ||||
| namespace details { | ||||
| 
 | ||||
| struct console_mutex | ||||
| { | ||||
|     using mutex_t = std::mutex; | ||||
|     static mutex_t &mutex() | ||||
|     { | ||||
|         static mutex_t s_mutex; | ||||
|         return s_mutex; | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| struct console_nullmutex | ||||
| { | ||||
|     using mutex_t = null_mutex; | ||||
|     static mutex_t &mutex() | ||||
|     { | ||||
|         static mutex_t s_mutex; | ||||
|         return s_mutex; | ||||
|     } | ||||
| }; | ||||
| } // namespace details
 | ||||
| } // namespace spdlog
 | ||||
|  | @ -1,172 +0,0 @@ | |||
| // 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(const file_event_handlers &event_handlers) | ||||
|     : event_handlers_(event_handlers) | ||||
| {} | ||||
| 
 | ||||
| SPDLOG_INLINE file_helper::~file_helper() | ||||
| { | ||||
|     close(); | ||||
| } | ||||
| 
 | ||||
| SPDLOG_INLINE void file_helper::open(const filename_t &fname, bool truncate) | ||||
| { | ||||
|     close(); | ||||
|     filename_ = fname; | ||||
| 
 | ||||
|     auto *mode = SPDLOG_FILENAME_T("ab"); | ||||
|     auto *trunc_mode = SPDLOG_FILENAME_T("wb"); | ||||
| 
 | ||||
|     if (event_handlers_.before_open) | ||||
|     { | ||||
|         event_handlers_.before_open(filename_); | ||||
|     } | ||||
|     for (int tries = 0; tries < open_tries_; ++tries) | ||||
|     { | ||||
|         // create containing folder if not exists already.
 | ||||
|         os::create_dir(os::dir_name(fname)); | ||||
|         if (truncate) | ||||
|         { | ||||
|             // Truncate by opening-and-closing a tmp file in "wb" mode, always
 | ||||
|             // opening the actual log-we-write-to in "ab" mode, since that
 | ||||
|             // interacts more politely with eternal processes that might
 | ||||
|             // rotate/truncate the file underneath us.
 | ||||
|             std::FILE *tmp; | ||||
|             if (os::fopen_s(&tmp, fname, trunc_mode)) | ||||
|             { | ||||
|                 continue; | ||||
|             } | ||||
|             std::fclose(tmp); | ||||
|         } | ||||
|         if (!os::fopen_s(&fd_, fname, mode)) | ||||
|         { | ||||
|             if (event_handlers_.after_open) | ||||
|             { | ||||
|                 event_handlers_.after_open(filename_, fd_); | ||||
|             } | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         details::os::sleep_for_millis(open_interval_); | ||||
|     } | ||||
| 
 | ||||
|     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()) | ||||
|     { | ||||
|         throw_spdlog_ex("Failed re opening file - was not opened before"); | ||||
|     } | ||||
|     this->open(filename_, truncate); | ||||
| } | ||||
| 
 | ||||
| SPDLOG_INLINE void file_helper::flush() | ||||
| { | ||||
|     if (std::fflush(fd_) != 0) | ||||
|     { | ||||
|         throw_spdlog_ex("Failed flush to file " + os::filename_to_str(filename_), errno); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| SPDLOG_INLINE void file_helper::close() | ||||
| { | ||||
|     if (fd_ != nullptr) | ||||
|     { | ||||
|         if (event_handlers_.before_close) | ||||
|         { | ||||
|             event_handlers_.before_close(filename_, fd_); | ||||
|         } | ||||
| 
 | ||||
|         std::fclose(fd_); | ||||
|         fd_ = nullptr; | ||||
| 
 | ||||
|         if (event_handlers_.after_close) | ||||
|         { | ||||
|             event_handlers_.after_close(filename_); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| 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) | ||||
|     { | ||||
|         throw_spdlog_ex("Failed writing to file " + os::filename_to_str(filename_), errno); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| SPDLOG_INLINE size_t file_helper::size() const | ||||
| { | ||||
|     if (fd_ == nullptr) | ||||
|     { | ||||
|         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_; | ||||
| } | ||||
| 
 | ||||
| //
 | ||||
| // 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 cases like "/etc/rc.d/somelogfile or "/abc/.hiddenfile"
 | ||||
|     auto folder_index = fname.find_last_of(details::os::folder_seps_filename); | ||||
|     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,61 +0,0 @@ | |||
| // Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
 | ||||
| // Distributed under the MIT License (http://opensource.org/licenses/MIT)
 | ||||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| #include <spdlog/common.h> | ||||
| #include <tuple> | ||||
| 
 | ||||
| namespace spdlog { | ||||
| 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 SPDLOG_API file_helper | ||||
| { | ||||
| public: | ||||
|     file_helper() = default; | ||||
|     explicit file_helper(const file_event_handlers &event_handlers); | ||||
| 
 | ||||
|     file_helper(const file_helper &) = delete; | ||||
|     file_helper &operator=(const file_helper &) = delete; | ||||
|     ~file_helper(); | ||||
| 
 | ||||
|     void open(const filename_t &fname, bool truncate = false); | ||||
|     void reopen(bool truncate); | ||||
|     void flush(); | ||||
|     void close(); | ||||
|     void write(const memory_buf_t &buf); | ||||
|     size_t size() const; | ||||
|     const filename_t &filename() const; | ||||
| 
 | ||||
|     //
 | ||||
|     // 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")
 | ||||
|     static std::tuple<filename_t, filename_t> split_by_extension(const filename_t &fname); | ||||
| 
 | ||||
| private: | ||||
|     const int open_tries_ = 5; | ||||
|     const unsigned int open_interval_ = 10; | ||||
|     std::FILE *fd_{nullptr}; | ||||
|     filename_t filename_; | ||||
|     file_event_handlers event_handlers_; | ||||
| }; | ||||
| } // namespace details
 | ||||
| } // namespace spdlog
 | ||||
| 
 | ||||
| #ifdef SPDLOG_HEADER_ONLY | ||||
| #    include "file_helper-inl.h" | ||||
| #endif | ||||
|  | @ -1,169 +0,0 @@ | |||
| // Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
 | ||||
| // Distributed under the MIT License (http://opensource.org/licenses/MIT)
 | ||||
| #pragma once | ||||
| 
 | ||||
| #include <chrono> | ||||
| #include <type_traits> | ||||
| #include <iterator> | ||||
| #include <spdlog/fmt/fmt.h> | ||||
| #include <spdlog/common.h> | ||||
| 
 | ||||
| #ifdef SPDLOG_USE_STD_FORMAT | ||||
| #    include <charconv> | ||||
| #    include <limits> | ||||
| #endif | ||||
| 
 | ||||
| // Some fmt helpers to efficiently format and pad ints and strings
 | ||||
| namespace spdlog { | ||||
| namespace details { | ||||
| namespace fmt_helper { | ||||
| 
 | ||||
| inline spdlog::string_view_t to_string_view(const memory_buf_t &buf) SPDLOG_NOEXCEPT | ||||
| { | ||||
|     return spdlog::string_view_t{buf.data(), buf.size()}; | ||||
| } | ||||
| 
 | ||||
| inline void append_string_view(spdlog::string_view_t view, memory_buf_t &dest) | ||||
| { | ||||
|     auto *buf_ptr = view.data(); | ||||
|     dest.append(buf_ptr, buf_ptr + view.size()); | ||||
| } | ||||
| 
 | ||||
| #ifdef SPDLOG_USE_STD_FORMAT | ||||
| template<typename T> | ||||
| inline void append_int(T n, memory_buf_t &dest) | ||||
| { | ||||
|     // Buffer should be large enough to hold all digits (digits10 + 1) and a sign
 | ||||
|     SPDLOG_CONSTEXPR const auto BUF_SIZE = std::numeric_limits<T>::digits10 + 2; | ||||
|     char buf[BUF_SIZE]; | ||||
| 
 | ||||
|     auto [ptr, ec] = std::to_chars(buf, buf + BUF_SIZE, n, 10); | ||||
|     if (ec == std::errc()) | ||||
|     { | ||||
|         dest.append(buf, ptr); | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         throw_spdlog_ex("Failed to format int", static_cast<int>(ec)); | ||||
|     } | ||||
| } | ||||
| #else | ||||
| template<typename T> | ||||
| inline void append_int(T n, memory_buf_t &dest) | ||||
| { | ||||
|     fmt::format_int i(n); | ||||
|     dest.append(i.data(), i.data() + i.size()); | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| template<typename T> | ||||
| SPDLOG_CONSTEXPR_FUNC unsigned int count_digits_fallback(T n) | ||||
| { | ||||
|     // taken from fmt: https://github.com/fmtlib/fmt/blob/8.0.1/include/fmt/format.h#L899-L912
 | ||||
|     unsigned int count = 1; | ||||
|     for (;;) | ||||
|     { | ||||
|         // Integer division is slow so do it for a group of four digits instead
 | ||||
|         // of for every digit. The idea comes from the talk by Alexandrescu
 | ||||
|         // "Three Optimization Tips for C++". See speed-test for a comparison.
 | ||||
|         if (n < 10) | ||||
|             return count; | ||||
|         if (n < 100) | ||||
|             return count + 1; | ||||
|         if (n < 1000) | ||||
|             return count + 2; | ||||
|         if (n < 10000) | ||||
|             return count + 3; | ||||
|         n /= 10000u; | ||||
|         count += 4; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| template<typename T> | ||||
| inline unsigned int count_digits(T n) | ||||
| { | ||||
|     using count_type = typename std::conditional<(sizeof(T) > sizeof(uint32_t)), uint64_t, uint32_t>::type; | ||||
| #ifdef SPDLOG_USE_STD_FORMAT | ||||
|     return count_digits_fallback(static_cast<count_type>(n)); | ||||
| #else | ||||
|     return static_cast<unsigned int>(fmt:: | ||||
| // fmt 7.0.0 renamed the internal namespace to detail.
 | ||||
| // See: https://github.com/fmtlib/fmt/issues/1538
 | ||||
| #    if FMT_VERSION < 70000 | ||||
|             internal | ||||
| #    else | ||||
|             detail | ||||
| #    endif | ||||
|         ::count_digits(static_cast<count_type>(n))); | ||||
| #endif | ||||
| } | ||||
| 
 | ||||
| inline void pad2(int n, memory_buf_t &dest) | ||||
| { | ||||
|     if (n >= 0 && n < 100) // 0-99
 | ||||
|     { | ||||
|         dest.push_back(static_cast<char>('0' + n / 10)); | ||||
|         dest.push_back(static_cast<char>('0' + n % 10)); | ||||
|     } | ||||
|     else // unlikely, but just in case, let fmt deal with it
 | ||||
|     { | ||||
|         fmt_lib::format_to(std::back_inserter(dest), "{:02}", n); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| template<typename T> | ||||
| 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"); | ||||
|     for (auto digits = count_digits(n); digits < width; digits++) | ||||
|     { | ||||
|         dest.push_back('0'); | ||||
|     } | ||||
|     append_int(n, dest); | ||||
| } | ||||
| 
 | ||||
| template<typename T> | ||||
| inline void pad3(T n, memory_buf_t &dest) | ||||
| { | ||||
|     static_assert(std::is_unsigned<T>::value, "pad3 must get unsigned T"); | ||||
|     if (n < 1000) | ||||
|     { | ||||
|         dest.push_back(static_cast<char>(n / 100 + '0')); | ||||
|         n = n % 100; | ||||
|         dest.push_back(static_cast<char>((n / 10) + '0')); | ||||
|         dest.push_back(static_cast<char>((n % 10) + '0')); | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         append_int(n, dest); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| template<typename T> | ||||
| inline void pad6(T n, memory_buf_t &dest) | ||||
| { | ||||
|     pad_uint(n, 6, dest); | ||||
| } | ||||
| 
 | ||||
| template<typename T> | ||||
| inline void pad9(T n, memory_buf_t &dest) | ||||
| { | ||||
|     pad_uint(n, 9, dest); | ||||
| } | ||||
| 
 | ||||
| // return fraction of a second of the given time_point.
 | ||||
| // e.g.
 | ||||
| // fraction<std::milliseconds>(tp) -> will return the millis part of the second
 | ||||
| template<typename ToDuration> | ||||
| inline ToDuration time_fraction(log_clock::time_point tp) | ||||
| { | ||||
|     using std::chrono::duration_cast; | ||||
|     using std::chrono::seconds; | ||||
|     auto duration = tp.time_since_epoch(); | ||||
|     auto secs = duration_cast<seconds>(duration); | ||||
|     return duration_cast<ToDuration>(duration) - duration_cast<ToDuration>(secs); | ||||
| } | ||||
| 
 | ||||
| } // namespace fmt_helper
 | ||||
| } // namespace details
 | ||||
| } // namespace spdlog
 | ||||
|  | @ -1,37 +0,0 @@ | |||
| // 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::log_clock::time_point log_time, spdlog::source_loc loc, string_view_t a_logger_name, | ||||
|     spdlog::level::level_enum lvl, spdlog::string_view_t msg) | ||||
|     : logger_name(a_logger_name) | ||||
|     , level(lvl) | ||||
|     , time(log_time) | ||||
| #ifndef SPDLOG_NO_THREAD_ID | ||||
|     , thread_id(os::thread_id()) | ||||
| #endif | ||||
|     , source(loc) | ||||
|     , payload(msg) | ||||
| {} | ||||
| 
 | ||||
| SPDLOG_INLINE log_msg::log_msg( | ||||
|     spdlog::source_loc loc, string_view_t a_logger_name, spdlog::level::level_enum lvl, spdlog::string_view_t msg) | ||||
|     : log_msg(os::now(), loc, a_logger_name, lvl, msg) | ||||
| {} | ||||
| 
 | ||||
| SPDLOG_INLINE log_msg::log_msg(string_view_t a_logger_name, spdlog::level::level_enum lvl, spdlog::string_view_t msg) | ||||
|     : log_msg(os::now(), source_loc{}, a_logger_name, lvl, msg) | ||||
| {} | ||||
| 
 | ||||
| } // namespace details
 | ||||
| } // namespace spdlog
 | ||||
|  | @ -1,37 +0,0 @@ | |||
| // Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
 | ||||
| // Distributed under the MIT License (http://opensource.org/licenses/MIT)
 | ||||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| #include <spdlog/common.h> | ||||
| #include <string> | ||||
| 
 | ||||
| namespace spdlog { | ||||
| namespace details { | ||||
| struct SPDLOG_API log_msg | ||||
| { | ||||
|     log_msg() = default; | ||||
|     log_msg(log_clock::time_point log_time, source_loc loc, string_view_t logger_name, level::level_enum lvl, string_view_t msg); | ||||
|     log_msg(source_loc loc, string_view_t logger_name, level::level_enum lvl, string_view_t msg); | ||||
|     log_msg(string_view_t logger_name, level::level_enum lvl, string_view_t msg); | ||||
|     log_msg(const log_msg &other) = default; | ||||
|     log_msg &operator=(const log_msg &other) = default; | ||||
| 
 | ||||
|     string_view_t logger_name; | ||||
|     level::level_enum level{level::off}; | ||||
|     log_clock::time_point time; | ||||
|     size_t thread_id{0}; | ||||
| 
 | ||||
|     // wrapping the formatted text with color (updated by pattern_formatter).
 | ||||
|     mutable size_t color_range_start{0}; | ||||
|     mutable size_t color_range_end{0}; | ||||
| 
 | ||||
|     source_loc source; | ||||
|     string_view_t payload; | ||||
| }; | ||||
| } // namespace details
 | ||||
| } // namespace spdlog
 | ||||
| 
 | ||||
| #ifdef SPDLOG_HEADER_ONLY | ||||
| #    include "log_msg-inl.h" | ||||
| #endif | ||||
|  | @ -1,58 +0,0 @@ | |||
| // 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) SPDLOG_NOEXCEPT : log_msg{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) SPDLOG_NOEXCEPT | ||||
| { | ||||
|     log_msg::operator=(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
 | ||||
|  | @ -1,33 +0,0 @@ | |||
| // 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 SPDLOG_API 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) SPDLOG_NOEXCEPT; | ||||
|     log_msg_buffer &operator=(const log_msg_buffer &other); | ||||
|     log_msg_buffer &operator=(log_msg_buffer &&other) SPDLOG_NOEXCEPT; | ||||
| }; | ||||
| 
 | ||||
| } // namespace details
 | ||||
| } // namespace spdlog
 | ||||
| 
 | ||||
| #ifdef SPDLOG_HEADER_ONLY | ||||
| #    include "log_msg_buffer-inl.h" | ||||
| #endif | ||||
|  | @ -1,126 +0,0 @@ | |||
| // Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
 | ||||
| // Distributed under the MIT License (http://opensource.org/licenses/MIT)
 | ||||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| // multi producer-multi consumer blocking queue.
 | ||||
| // enqueue(..) - will block until room found to put the new message.
 | ||||
| // enqueue_nowait(..) - will return immediately with false if no room left in
 | ||||
| // the queue.
 | ||||
| // dequeue_for(..) - will block until the queue is not empty or timeout have
 | ||||
| // passed.
 | ||||
| 
 | ||||
| #include <spdlog/details/circular_q.h> | ||||
| 
 | ||||
| #include <condition_variable> | ||||
| #include <mutex> | ||||
| 
 | ||||
| namespace spdlog { | ||||
| namespace details { | ||||
| 
 | ||||
| template<typename T> | ||||
| class mpmc_blocking_queue | ||||
| { | ||||
| public: | ||||
|     using item_type = T; | ||||
|     explicit mpmc_blocking_queue(size_t max_items) | ||||
|         : q_(max_items) | ||||
|     {} | ||||
| 
 | ||||
| #ifndef __MINGW32__ | ||||
|     // try to enqueue and block if no room left
 | ||||
|     void enqueue(T &&item) | ||||
|     { | ||||
|         { | ||||
|             std::unique_lock<std::mutex> lock(queue_mutex_); | ||||
|             pop_cv_.wait(lock, [this] { return !this->q_.full(); }); | ||||
|             q_.push_back(std::move(item)); | ||||
|         } | ||||
|         push_cv_.notify_one(); | ||||
|     } | ||||
| 
 | ||||
|     // enqueue immediately. overrun oldest message in the queue if no room left.
 | ||||
|     void enqueue_nowait(T &&item) | ||||
|     { | ||||
|         { | ||||
|             std::unique_lock<std::mutex> lock(queue_mutex_); | ||||
|             q_.push_back(std::move(item)); | ||||
|         } | ||||
|         push_cv_.notify_one(); | ||||
|     } | ||||
| 
 | ||||
|     // try to dequeue item. if no item found. wait up to timeout and try again
 | ||||
|     // Return true, if succeeded dequeue item, false otherwise
 | ||||
|     bool dequeue_for(T &popped_item, std::chrono::milliseconds wait_duration) | ||||
|     { | ||||
|         { | ||||
|             std::unique_lock<std::mutex> lock(queue_mutex_); | ||||
|             if (!push_cv_.wait_for(lock, wait_duration, [this] { return !this->q_.empty(); })) | ||||
|             { | ||||
|                 return false; | ||||
|             } | ||||
|             popped_item = std::move(q_.front()); | ||||
|             q_.pop_front(); | ||||
|         } | ||||
|         pop_cv_.notify_one(); | ||||
|         return true; | ||||
|     } | ||||
| 
 | ||||
| #else | ||||
|     // apparently mingw deadlocks if the mutex is released before cv.notify_one(),
 | ||||
|     // so release the mutex at the very end each function.
 | ||||
| 
 | ||||
|     // try to enqueue and block if no room left
 | ||||
|     void enqueue(T &&item) | ||||
|     { | ||||
|         std::unique_lock<std::mutex> lock(queue_mutex_); | ||||
|         pop_cv_.wait(lock, [this] { return !this->q_.full(); }); | ||||
|         q_.push_back(std::move(item)); | ||||
|         push_cv_.notify_one(); | ||||
|     } | ||||
| 
 | ||||
|     // enqueue immediately. overrun oldest message in the queue if no room left.
 | ||||
|     void enqueue_nowait(T &&item) | ||||
|     { | ||||
|         std::unique_lock<std::mutex> lock(queue_mutex_); | ||||
|         q_.push_back(std::move(item)); | ||||
|         push_cv_.notify_one(); | ||||
|     } | ||||
| 
 | ||||
|     // try to dequeue item. if no item found. wait up to timeout and try again
 | ||||
|     // Return true, if succeeded dequeue item, false otherwise
 | ||||
|     bool dequeue_for(T &popped_item, std::chrono::milliseconds wait_duration) | ||||
|     { | ||||
|         std::unique_lock<std::mutex> lock(queue_mutex_); | ||||
|         if (!push_cv_.wait_for(lock, wait_duration, [this] { return !this->q_.empty(); })) | ||||
|         { | ||||
|             return false; | ||||
|         } | ||||
|         popped_item = std::move(q_.front()); | ||||
|         q_.pop_front(); | ||||
|         pop_cv_.notify_one(); | ||||
|         return true; | ||||
|     } | ||||
| 
 | ||||
| #endif | ||||
| 
 | ||||
|     size_t overrun_counter() | ||||
|     { | ||||
|         std::unique_lock<std::mutex> lock(queue_mutex_); | ||||
|         return q_.overrun_counter(); | ||||
|     } | ||||
| 
 | ||||
|     size_t size() | ||||
|     { | ||||
|         std::unique_lock<std::mutex> lock(queue_mutex_); | ||||
|         return q_.size(); | ||||
|     } | ||||
| 
 | ||||
| private: | ||||
|     std::mutex queue_mutex_; | ||||
|     std::condition_variable push_cv_; | ||||
|     std::condition_variable pop_cv_; | ||||
|     spdlog::details::circular_q<T> q_; | ||||
| }; | ||||
| } // namespace details
 | ||||
| } // namespace spdlog
 | ||||
|  | @ -1,49 +0,0 @@ | |||
| // Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
 | ||||
| // Distributed under the MIT License (http://opensource.org/licenses/MIT)
 | ||||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| #include <atomic> | ||||
| #include <utility> | ||||
| // null, no cost dummy "mutex" and dummy "atomic" int
 | ||||
| 
 | ||||
| namespace spdlog { | ||||
| namespace details { | ||||
| struct null_mutex | ||||
| { | ||||
|     void lock() const {} | ||||
|     void unlock() const {} | ||||
|     bool try_lock() const | ||||
|     { | ||||
|         return true; | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| struct null_atomic_int | ||||
| { | ||||
|     int value; | ||||
|     null_atomic_int() = default; | ||||
| 
 | ||||
|     explicit null_atomic_int(int new_value) | ||||
|         : value(new_value) | ||||
|     {} | ||||
| 
 | ||||
|     int load(std::memory_order = std::memory_order_relaxed) const | ||||
|     { | ||||
|         return value; | ||||
|     } | ||||
| 
 | ||||
|     void store(int new_value, std::memory_order = std::memory_order_relaxed) | ||||
|     { | ||||
|         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
 | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| } // namespace details
 | ||||
| } // namespace spdlog
 | ||||
							
								
								
									
										610
									
								
								Dependencies/spdlog/include/spdlog/details/os-inl.h
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										610
									
								
								Dependencies/spdlog/include/spdlog/details/os-inl.h
									
										
									
									
										vendored
									
									
								
							|  | @ -1,610 +0,0 @@ | |||
| // 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 | ||||
| 
 | ||||
| #    include <io.h>      // _get_osfhandle and _isatty support
 | ||||
| #    include <process.h> //  _get_pid support
 | ||||
| #    include <spdlog/details/windows_include.h> | ||||
| 
 | ||||
| #    ifdef __MINGW32__ | ||||
| #        include <share.h> | ||||
| #    endif | ||||
| 
 | ||||
| #    if defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) || defined(SPDLOG_WCHAR_FILENAMES) | ||||
| #        include <limits> | ||||
| #    endif | ||||
| 
 | ||||
| #    include <direct.h> // for _mkdir/_wmkdir
 | ||||
| 
 | ||||
| #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_getthrds_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); | ||||
| } | ||||
| 
 | ||||
| // 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 | ||||
| #    if defined(SPDLOG_PREVENT_CHILD_FD) | ||||
|     if (*fp != nullptr) | ||||
|     { | ||||
|         auto file_handle = reinterpret_cast<HANDLE>(_get_osfhandle(::_fileno(*fp))); | ||||
|         if (!::SetHandleInformation(file_handle, HANDLE_FLAG_INHERIT, 0)) | ||||
|         { | ||||
|             ::fclose(*fp); | ||||
|             *fp = nullptr; | ||||
|         } | ||||
|     } | ||||
| #    endif | ||||
| #else // unix
 | ||||
| #    if defined(SPDLOG_PREVENT_CHILD_FD) | ||||
|     const int mode_flag = mode == SPDLOG_FILENAME_T("ab") ? O_APPEND : O_TRUNC; | ||||
|     const int fd = ::open((filename.c_str()), O_CREAT | O_WRONLY | O_CLOEXEC | mode_flag, mode_t(0644)); | ||||
|     if (fd == -1) | ||||
|     { | ||||
|         return true; | ||||
|     } | ||||
|     *fp = ::fdopen(fd, mode.c_str()); | ||||
|     if (*fp == nullptr) | ||||
|     { | ||||
|         ::close(fd); | ||||
|     } | ||||
| #    else | ||||
|     *fp = ::fopen((filename.c_str()), mode.c_str()); | ||||
| #    endif | ||||
| #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 path_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 path exists (file or directory)
 | ||||
| SPDLOG_INLINE bool path_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; | ||||
| #else // common linux/unix all have the stat system call
 | ||||
|     struct stat buffer; | ||||
|     return (::stat(filename.c_str(), &buffer) == 0); | ||||
| #endif | ||||
| } | ||||
| 
 | ||||
| #ifdef _MSC_VER | ||||
| // avoid warning about unreachable statement at the end of filesize()
 | ||||
| #    pragma warning(push) | ||||
| #    pragma warning(disable : 4702) | ||||
| #endif | ||||
| 
 | ||||
| // Return file size according to open FILE* object
 | ||||
| SPDLOG_INLINE 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 defined(_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
 | ||||
| // OpenBSD and AIX doesn't compile with :: before the fileno(..)
 | ||||
| #    if defined(__OpenBSD__) || defined(_AIX) | ||||
|     int fd = fileno(f); | ||||
| #    else | ||||
|     int fd = ::fileno(f); | ||||
| #    endif | ||||
| // 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 // other unix or linux 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 0; // will not be reached.
 | ||||
| } | ||||
| 
 | ||||
| #ifdef _MSC_VER | ||||
| #    pragma warning(pop) | ||||
| #endif | ||||
| 
 | ||||
| // 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) | ||||
|         throw_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) || (!defined(_BSD_SOURCE) && !defined(_GNU_SOURCE)) | ||||
|     // '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 */
 | ||||
|                 + static_cast<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) | ||||
|     struct __pthrdsinfo buf; | ||||
|     int reg_size = 0; | ||||
|     pthread_t pt = pthread_self(); | ||||
|     int retval = pthread_getthrds_np(&pt, PTHRDSINFO_QUERY_TID, &buf, sizeof(buf), NULL, ®_size); | ||||
|     int tid = (!retval) ? buf.__pi_tid : 0; | ||||
|     return static_cast<size_t>(tid); | ||||
| #elif 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(unsigned 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); | ||||
| #    ifdef SPDLOG_USE_STD_FORMAT | ||||
|     return buf; | ||||
| #    else | ||||
|     return fmt::to_string(buf); | ||||
| #    endif | ||||
| } | ||||
| #else | ||||
| SPDLOG_INLINE std::string filename_to_str(const filename_t &filename) | ||||
| { | ||||
|     return filename; | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| SPDLOG_INLINE int pid() SPDLOG_NOEXCEPT | ||||
| { | ||||
| 
 | ||||
| #ifdef _WIN32 | ||||
|     return conditional_static_cast<int>(::GetCurrentProcessId()); | ||||
| #else | ||||
|     return conditional_static_cast<int>(::getpid()); | ||||
| #endif | ||||
| } | ||||
| 
 | ||||
| // Determine if the terminal supports colors
 | ||||
| // Based on: https://github.com/agauniyal/rang/
 | ||||
| SPDLOG_INLINE bool is_color_terminal() SPDLOG_NOEXCEPT | ||||
| { | ||||
| #ifdef _WIN32 | ||||
|     return true; | ||||
| #else | ||||
| 
 | ||||
|     static const bool result = []() { | ||||
|         const char *env_colorterm_p = std::getenv("COLORTERM"); | ||||
|         if (env_colorterm_p != nullptr) | ||||
|         { | ||||
|             return true; | ||||
|         } | ||||
| 
 | ||||
|         static constexpr std::array<const char *, 16> terms = {{"ansi", "color", "console", "cygwin", "gnome", "konsole", "kterm", "linux", | ||||
|             "msys", "putty", "rxvt", "screen", "vt100", "xterm", "alacritty", "vt102"}}; | ||||
| 
 | ||||
|         const char *env_term_p = std::getenv("TERM"); | ||||
|         if (env_term_p == nullptr) | ||||
|         { | ||||
|             return false; | ||||
|         } | ||||
| 
 | ||||
|         return std::any_of(terms.begin(), terms.end(), [&](const char *term) { return std::strstr(env_term_p, term) != nullptr; }); | ||||
|     }(); | ||||
| 
 | ||||
|     return result; | ||||
| #endif | ||||
| } | ||||
| 
 | ||||
| // Determine 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)()) / 2 - 1) | ||||
|     { | ||||
|         throw_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; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     throw_spdlog_ex(fmt_lib::format("WideCharToMultiByte failed. Last error: {}", ::GetLastError())); | ||||
| } | ||||
| 
 | ||||
| SPDLOG_INLINE void utf8_to_wstrbuf(string_view_t str, wmemory_buf_t &target) | ||||
| { | ||||
|     if (str.size() > static_cast<size_t>((std::numeric_limits<int>::max)()) - 1) | ||||
|     { | ||||
|         throw_spdlog_ex("UTF-8 string is too big to be converted to UTF-16"); | ||||
|     } | ||||
| 
 | ||||
|     int str_size = static_cast<int>(str.size()); | ||||
|     if (str_size == 0) | ||||
|     { | ||||
|         target.resize(0); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     int result_size = static_cast<int>(target.capacity()); | ||||
|     if (str_size + 1 > result_size) | ||||
|     { | ||||
|         result_size = ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, str.data(), str_size, NULL, 0); | ||||
|     } | ||||
| 
 | ||||
|     if (result_size > 0) | ||||
|     { | ||||
|         target.resize(result_size); | ||||
|         result_size = ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, str.data(), str_size, target.data(), result_size); | ||||
| 
 | ||||
|         if (result_size > 0) | ||||
|         { | ||||
|             target.resize(result_size); | ||||
|             return; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     throw_spdlog_ex(fmt_lib::format("MultiByteToWideChar failed. Last error: {}", ::GetLastError())); | ||||
| } | ||||
| #endif // (defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) || defined(SPDLOG_WCHAR_FILENAMES)) && defined(_WIN32)
 | ||||
| 
 | ||||
| // return true on success
 | ||||
| static SPDLOG_INLINE bool mkdir_(const filename_t &path) | ||||
| { | ||||
| #ifdef _WIN32 | ||||
| #    ifdef SPDLOG_WCHAR_FILENAMES | ||||
|     return ::_wmkdir(path.c_str()) == 0; | ||||
| #    else | ||||
|     return ::_mkdir(path.c_str()) == 0; | ||||
| #    endif | ||||
| #else | ||||
|     return ::mkdir(path.c_str(), mode_t(0755)) == 0; | ||||
| #endif | ||||
| } | ||||
| 
 | ||||
| // create the given directory - and all directories leading to it
 | ||||
| // return true on success or if the directory already exists
 | ||||
| SPDLOG_INLINE bool create_dir(const filename_t &path) | ||||
| { | ||||
|     if (path_exists(path)) | ||||
|     { | ||||
|         return true; | ||||
|     } | ||||
| 
 | ||||
|     if (path.empty()) | ||||
|     { | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     size_t search_offset = 0; | ||||
|     do | ||||
|     { | ||||
|         auto token_pos = path.find_first_of(folder_seps_filename, search_offset); | ||||
|         // treat the entire path as a folder if no folder separator not found
 | ||||
|         if (token_pos == filename_t::npos) | ||||
|         { | ||||
|             token_pos = path.size(); | ||||
|         } | ||||
| 
 | ||||
|         auto subdir = path.substr(0, token_pos); | ||||
| 
 | ||||
|         if (!subdir.empty() && !path_exists(subdir) && !mkdir_(subdir)) | ||||
|         { | ||||
|             return false; // return error if failed creating dir
 | ||||
|         } | ||||
|         search_offset = token_pos + 1; | ||||
|     } while (search_offset < path.size()); | ||||
| 
 | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| // Return directory name from given path or empty string
 | ||||
| // "abc/file" => "abc"
 | ||||
| // "abc/" => "abc"
 | ||||
| // "abc" => ""
 | ||||
| // "abc///" => "abc//"
 | ||||
| SPDLOG_INLINE filename_t dir_name(const filename_t &path) | ||||
| { | ||||
|     auto pos = path.find_last_of(folder_seps_filename); | ||||
|     return pos != filename_t::npos ? path.substr(0, pos) : filename_t{}; | ||||
| } | ||||
| 
 | ||||
| std::string SPDLOG_INLINE getenv(const char *field) | ||||
| { | ||||
| 
 | ||||
| #if defined(_MSC_VER) | ||||
| #    if defined(__cplusplus_winrt) | ||||
|     return std::string{}; // not supported under uwp
 | ||||
| #    else | ||||
|     size_t len = 0; | ||||
|     char buf[128]; | ||||
|     bool ok = ::getenv_s(&len, buf, sizeof(buf), field) == 0; | ||||
|     return ok ? buf : std::string{}; | ||||
| #    endif | ||||
| #else // revert to getenv
 | ||||
|     char *buf = ::getenv(field); | ||||
|     return buf ? buf : std::string{}; | ||||
| #endif | ||||
| } | ||||
| 
 | ||||
| } // namespace os
 | ||||
| } // namespace details
 | ||||
| } // namespace spdlog
 | ||||
							
								
								
									
										118
									
								
								Dependencies/spdlog/include/spdlog/details/os.h
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										118
									
								
								Dependencies/spdlog/include/spdlog/details/os.h
									
										
									
									
										vendored
									
									
								
							|  | @ -1,118 +0,0 @@ | |||
| // Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
 | ||||
| // Distributed under the MIT License (http://opensource.org/licenses/MIT)
 | ||||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| #include <spdlog/common.h> | ||||
| #include <ctime> // std::time_t | ||||
| 
 | ||||
| namespace spdlog { | ||||
| namespace details { | ||||
| namespace os { | ||||
| 
 | ||||
| SPDLOG_API spdlog::log_clock::time_point now() SPDLOG_NOEXCEPT; | ||||
| 
 | ||||
| SPDLOG_API std::tm localtime(const std::time_t &time_tt) SPDLOG_NOEXCEPT; | ||||
| 
 | ||||
| SPDLOG_API std::tm localtime() SPDLOG_NOEXCEPT; | ||||
| 
 | ||||
| SPDLOG_API std::tm gmtime(const std::time_t &time_tt) SPDLOG_NOEXCEPT; | ||||
| 
 | ||||
| SPDLOG_API std::tm gmtime() SPDLOG_NOEXCEPT; | ||||
| 
 | ||||
| // eol definition
 | ||||
| #if !defined(SPDLOG_EOL) | ||||
| #    ifdef _WIN32 | ||||
| #        define SPDLOG_EOL "\r\n" | ||||
| #    else | ||||
| #        define SPDLOG_EOL "\n" | ||||
| #    endif | ||||
| #endif | ||||
| 
 | ||||
| SPDLOG_CONSTEXPR static const char *default_eol = SPDLOG_EOL; | ||||
| 
 | ||||
| // folder separator
 | ||||
| #if !defined(SPDLOG_FOLDER_SEPS) | ||||
| #    ifdef _WIN32 | ||||
| #        define SPDLOG_FOLDER_SEPS "\\/" | ||||
| #    else | ||||
| #        define SPDLOG_FOLDER_SEPS "/" | ||||
| #    endif | ||||
| #endif | ||||
| 
 | ||||
| SPDLOG_CONSTEXPR static const char folder_seps[] = SPDLOG_FOLDER_SEPS; | ||||
| SPDLOG_CONSTEXPR static const filename_t::value_type folder_seps_filename[] = SPDLOG_FILENAME_T(SPDLOG_FOLDER_SEPS); | ||||
| 
 | ||||
| // fopen_s on non windows for writing
 | ||||
| SPDLOG_API bool fopen_s(FILE **fp, const filename_t &filename, const filename_t &mode); | ||||
| 
 | ||||
| // Remove filename. return 0 on success
 | ||||
| SPDLOG_API 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)
 | ||||
| SPDLOG_API int remove_if_exists(const filename_t &filename) SPDLOG_NOEXCEPT; | ||||
| 
 | ||||
| SPDLOG_API int rename(const filename_t &filename1, const filename_t &filename2) SPDLOG_NOEXCEPT; | ||||
| 
 | ||||
| // Return if file exists.
 | ||||
| SPDLOG_API bool path_exists(const filename_t &filename) SPDLOG_NOEXCEPT; | ||||
| 
 | ||||
| // Return file size according to open FILE* object
 | ||||
| SPDLOG_API size_t filesize(FILE *f); | ||||
| 
 | ||||
| // Return utc offset in minutes or throw spdlog_ex on failure
 | ||||
| SPDLOG_API int utc_minutes_offset(const std::tm &tm = details::os::localtime()); | ||||
| 
 | ||||
| // Return current thread id as size_t
 | ||||
| // It exists because the std::this_thread::get_id() is much slower(especially
 | ||||
| // under VS 2013)
 | ||||
| SPDLOG_API size_t _thread_id() SPDLOG_NOEXCEPT; | ||||
| 
 | ||||
| // Return current thread id as size_t (from thread local storage)
 | ||||
| SPDLOG_API size_t thread_id() SPDLOG_NOEXCEPT; | ||||
| 
 | ||||
| // This is avoid msvc issue in sleep_for that happens if the clock changes.
 | ||||
| // See https://github.com/gabime/spdlog/issues/609
 | ||||
| SPDLOG_API void sleep_for_millis(unsigned int milliseconds) SPDLOG_NOEXCEPT; | ||||
| 
 | ||||
| SPDLOG_API std::string filename_to_str(const filename_t &filename); | ||||
| 
 | ||||
| SPDLOG_API int pid() SPDLOG_NOEXCEPT; | ||||
| 
 | ||||
| // Determine if the terminal supports colors
 | ||||
| // Source: https://github.com/agauniyal/rang/
 | ||||
| SPDLOG_API bool is_color_terminal() SPDLOG_NOEXCEPT; | ||||
| 
 | ||||
| // Determine if the terminal attached
 | ||||
| // Source: https://github.com/agauniyal/rang/
 | ||||
| SPDLOG_API bool in_terminal(FILE *file) SPDLOG_NOEXCEPT; | ||||
| 
 | ||||
| #if (defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) || defined(SPDLOG_WCHAR_FILENAMES)) && defined(_WIN32) | ||||
| SPDLOG_API void wstr_to_utf8buf(wstring_view_t wstr, memory_buf_t &target); | ||||
| 
 | ||||
| SPDLOG_API void utf8_to_wstrbuf(string_view_t str, wmemory_buf_t &target); | ||||
| #endif | ||||
| 
 | ||||
| // Return directory name from given path or empty string
 | ||||
| // "abc/file" => "abc"
 | ||||
| // "abc/" => "abc"
 | ||||
| // "abc" => ""
 | ||||
| // "abc///" => "abc//"
 | ||||
| SPDLOG_API filename_t dir_name(const filename_t &path); | ||||
| 
 | ||||
| // Create a dir from the given path.
 | ||||
| // Return true if succeeded or if this dir already exists.
 | ||||
| SPDLOG_API bool create_dir(const filename_t &path); | ||||
| 
 | ||||
| // non thread safe, cross platform getenv/getenv_s
 | ||||
| // return empty string if field not found
 | ||||
| SPDLOG_API std::string getenv(const char *field); | ||||
| 
 | ||||
| } // namespace os
 | ||||
| } // namespace details
 | ||||
| } // namespace spdlog
 | ||||
| 
 | ||||
| #ifdef SPDLOG_HEADER_ONLY | ||||
| #    include "os-inl.h" | ||||
| #endif | ||||
|  | @ -1,49 +0,0 @@ | |||
| // 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,40 +0,0 @@ | |||
| // Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
 | ||||
| // Distributed under the MIT License (http://opensource.org/licenses/MIT)
 | ||||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| // periodic worker thread - periodically executes the given callback function.
 | ||||
| //
 | ||||
| // RAII over the owned thread:
 | ||||
| //    creates the thread on construction.
 | ||||
| //    stops and joins the thread on destruction (if the thread is executing a callback, wait for it to finish first).
 | ||||
| 
 | ||||
| #include <chrono> | ||||
| #include <condition_variable> | ||||
| #include <functional> | ||||
| #include <mutex> | ||||
| #include <thread> | ||||
| namespace spdlog { | ||||
| namespace details { | ||||
| 
 | ||||
| class SPDLOG_API periodic_worker | ||||
| { | ||||
| public: | ||||
|     periodic_worker(const std::function<void()> &callback_fun, std::chrono::seconds interval); | ||||
|     periodic_worker(const periodic_worker &) = delete; | ||||
|     periodic_worker &operator=(const periodic_worker &) = delete; | ||||
|     // stop the worker thread and join it
 | ||||
|     ~periodic_worker(); | ||||
| 
 | ||||
| private: | ||||
|     bool active_; | ||||
|     std::thread worker_thread_; | ||||
|     std::mutex mutex_; | ||||
|     std::condition_variable cv_; | ||||
| }; | ||||
| } // namespace details
 | ||||
| } // namespace spdlog
 | ||||
| 
 | ||||
| #ifdef SPDLOG_HEADER_ONLY | ||||
| #    include "periodic_worker-inl.h" | ||||
| #endif | ||||
|  | @ -1,313 +0,0 @@ | |||
| // 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/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 registry::~registry() = default; | ||||
| 
 | ||||
| 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_); | ||||
|     } | ||||
| 
 | ||||
|     // set new level according to previously configured level or default level
 | ||||
|     auto it = log_levels_.find(new_logger->name()); | ||||
|     auto new_level = it != log_levels_.end() ? it->second : global_log_level_; | ||||
|     new_logger->set_level(new_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); | ||||
|     } | ||||
|     global_log_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_); | ||||
|     auto clbk = [this]() { this->flush_all(); }; | ||||
|     periodic_flusher_ = details::make_unique<periodic_worker>(clbk, interval); | ||||
| } | ||||
| 
 | ||||
| SPDLOG_INLINE void registry::set_error_handler(err_handler handler) | ||||
| { | ||||
|     std::lock_guard<std::mutex> lock(logger_map_mutex_); | ||||
|     for (auto &l : loggers_) | ||||
|     { | ||||
|         l.second->set_error_handler(handler); | ||||
|     } | ||||
|     err_handler_ = std::move(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_registration) | ||||
| { | ||||
|     std::lock_guard<std::mutex> lock(logger_map_mutex_); | ||||
|     automatic_registration_ = automatic_registration; | ||||
| } | ||||
| 
 | ||||
| SPDLOG_INLINE void registry::set_levels(log_levels levels, level::level_enum *global_level) | ||||
| { | ||||
|     std::lock_guard<std::mutex> lock(logger_map_mutex_); | ||||
|     log_levels_ = std::move(levels); | ||||
|     auto global_level_requested = global_level != nullptr; | ||||
|     global_log_level_ = global_level_requested ? *global_level : global_log_level_; | ||||
| 
 | ||||
|     for (auto &logger : loggers_) | ||||
|     { | ||||
|         auto logger_entry = log_levels_.find(logger.first); | ||||
|         if (logger_entry != log_levels_.end()) | ||||
|         { | ||||
|             logger.second->set_level(logger_entry->second); | ||||
|         } | ||||
|         else if (global_level_requested) | ||||
|         { | ||||
|             logger.second->set_level(*global_level); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| 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()) | ||||
|     { | ||||
|         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
 | ||||
|  | @ -1,115 +0,0 @@ | |||
| // Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
 | ||||
| // Distributed under the MIT License (http://opensource.org/licenses/MIT)
 | ||||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| // Loggers registry of unique name->logger pointer
 | ||||
| // 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
 | ||||
| // This class is thread safe
 | ||||
| 
 | ||||
| #include <spdlog/common.h> | ||||
| 
 | ||||
| #include <chrono> | ||||
| #include <functional> | ||||
| #include <memory> | ||||
| #include <string> | ||||
| #include <unordered_map> | ||||
| #include <mutex> | ||||
| 
 | ||||
| namespace spdlog { | ||||
| class logger; | ||||
| 
 | ||||
| namespace details { | ||||
| class thread_pool; | ||||
| class periodic_worker; | ||||
| 
 | ||||
| class SPDLOG_API registry | ||||
| { | ||||
| public: | ||||
|     using log_levels = std::unordered_map<std::string, level::level_enum>; | ||||
|     registry(const registry &) = delete; | ||||
|     registry &operator=(const registry &) = delete; | ||||
| 
 | ||||
|     void register_logger(std::shared_ptr<logger> new_logger); | ||||
|     void initialize_logger(std::shared_ptr<logger> new_logger); | ||||
|     std::shared_ptr<logger> get(const std::string &logger_name); | ||||
|     std::shared_ptr<logger> 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.
 | ||||
|     logger *get_default_raw(); | ||||
| 
 | ||||
|     // set default logger.
 | ||||
|     // 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_tp(std::shared_ptr<thread_pool> tp); | ||||
| 
 | ||||
|     std::shared_ptr<thread_pool> get_tp(); | ||||
| 
 | ||||
|     // Set global formatter. Each sink in each logger will get a clone of this object
 | ||||
|     void set_formatter(std::unique_ptr<formatter> formatter); | ||||
| 
 | ||||
|     void enable_backtrace(size_t n_messages); | ||||
| 
 | ||||
|     void disable_backtrace(); | ||||
| 
 | ||||
|     void set_level(level::level_enum log_level); | ||||
| 
 | ||||
|     void flush_on(level::level_enum log_level); | ||||
| 
 | ||||
|     void flush_every(std::chrono::seconds interval); | ||||
| 
 | ||||
|     void set_error_handler(err_handler handler); | ||||
| 
 | ||||
|     void apply_all(const std::function<void(const std::shared_ptr<logger>)> &fun); | ||||
| 
 | ||||
|     void flush_all(); | ||||
| 
 | ||||
|     void drop(const std::string &logger_name); | ||||
| 
 | ||||
|     void drop_all(); | ||||
| 
 | ||||
|     // clean all resources and threads started by the registry
 | ||||
|     void shutdown(); | ||||
| 
 | ||||
|     std::recursive_mutex &tp_mutex(); | ||||
| 
 | ||||
|     void set_automatic_registration(bool automatic_registration); | ||||
| 
 | ||||
|     // set levels for all existing/future loggers. global_level can be null if should not set.
 | ||||
|     void set_levels(log_levels levels, level::level_enum *global_level); | ||||
| 
 | ||||
|     static registry &instance(); | ||||
| 
 | ||||
| private: | ||||
|     registry(); | ||||
|     ~registry(); | ||||
| 
 | ||||
|     void throw_if_exists_(const std::string &logger_name); | ||||
|     void register_logger_(std::shared_ptr<logger> new_logger); | ||||
|     bool set_level_from_cfg_(logger *logger); | ||||
|     std::mutex logger_map_mutex_, flusher_mutex_; | ||||
|     std::recursive_mutex tp_mutex_; | ||||
|     std::unordered_map<std::string, std::shared_ptr<logger>> loggers_; | ||||
|     log_levels log_levels_; | ||||
|     std::unique_ptr<formatter> formatter_; | ||||
|     spdlog::level::level_enum global_log_level_ = level::info; | ||||
|     level::level_enum flush_level_ = level::off; | ||||
|     err_handler err_handler_; | ||||
|     std::shared_ptr<thread_pool> tp_; | ||||
|     std::unique_ptr<periodic_worker> periodic_flusher_; | ||||
|     std::shared_ptr<logger> default_logger_; | ||||
|     bool automatic_registration_ = true; | ||||
|     size_t backtrace_n_messages_ = 0; | ||||
| }; | ||||
| 
 | ||||
| } // namespace details
 | ||||
| } // namespace spdlog
 | ||||
| 
 | ||||
| #ifdef SPDLOG_HEADER_ONLY | ||||
| #    include "registry-inl.h" | ||||
| #endif | ||||
|  | @ -1,24 +0,0 @@ | |||
| // 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
 | ||||
|  | @ -1,160 +0,0 @@ | |||
| // Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
 | ||||
| // Distributed under the MIT License (http://opensource.org/licenses/MIT)
 | ||||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| #define WIN32_LEAN_AND_MEAN | ||||
| // tcp client helper
 | ||||
| #include <spdlog/common.h> | ||||
| #include <spdlog/details/os.h> | ||||
| 
 | ||||
| #include <winsock2.h> | ||||
| #include <windows.h> | ||||
| #include <ws2tcpip.h> | ||||
| #include <stdlib.h> | ||||
| #include <stdio.h> | ||||
| #include <string> | ||||
| 
 | ||||
| #pragma comment(lib, "Ws2_32.lib") | ||||
| #pragma comment(lib, "Mswsock.lib") | ||||
| #pragma comment(lib, "AdvApi32.lib") | ||||
| 
 | ||||
| namespace spdlog { | ||||
| namespace details { | ||||
| class tcp_client | ||||
| { | ||||
|     SOCKET socket_ = INVALID_SOCKET; | ||||
| 
 | ||||
|     static void init_winsock_() | ||||
|     { | ||||
|         WSADATA wsaData; | ||||
|         auto rv = WSAStartup(MAKEWORD(2, 2), &wsaData); | ||||
|         if (rv != 0) | ||||
|         { | ||||
|             throw_winsock_error_("WSAStartup failed", ::WSAGetLastError()); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     static void throw_winsock_error_(const std::string &msg, int last_error) | ||||
|     { | ||||
|         char buf[512]; | ||||
|         ::FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, last_error, | ||||
|             MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), buf, (sizeof(buf) / sizeof(char)), NULL); | ||||
| 
 | ||||
|         throw_spdlog_ex(fmt_lib::format("tcp_sink - {}: {}", msg, buf)); | ||||
|     } | ||||
| 
 | ||||
| public: | ||||
|     tcp_client() | ||||
|     { | ||||
|         init_winsock_(); | ||||
|     } | ||||
| 
 | ||||
|     ~tcp_client() | ||||
|     { | ||||
|         close(); | ||||
|         ::WSACleanup(); | ||||
|     } | ||||
| 
 | ||||
|     bool is_connected() const | ||||
|     { | ||||
|         return socket_ != INVALID_SOCKET; | ||||
|     } | ||||
| 
 | ||||
|     void close() | ||||
|     { | ||||
|         ::closesocket(socket_); | ||||
|         socket_ = INVALID_SOCKET; | ||||
|     } | ||||
| 
 | ||||
|     SOCKET fd() const | ||||
|     { | ||||
|         return socket_; | ||||
|     } | ||||
| 
 | ||||
|     // try to connect or throw on failure
 | ||||
|     void connect(const std::string &host, int port) | ||||
|     { | ||||
|         if (is_connected()) | ||||
|         { | ||||
|             close(); | ||||
|         } | ||||
|         struct addrinfo hints | ||||
|         {}; | ||||
|         ZeroMemory(&hints, sizeof(hints)); | ||||
| 
 | ||||
|         hints.ai_family = AF_INET;       // IPv4
 | ||||
|         hints.ai_socktype = SOCK_STREAM; // TCP
 | ||||
|         hints.ai_flags = AI_NUMERICSERV; // port passed as as numeric value
 | ||||
|         hints.ai_protocol = 0; | ||||
| 
 | ||||
|         auto port_str = std::to_string(port); | ||||
|         struct addrinfo *addrinfo_result; | ||||
|         auto rv = ::getaddrinfo(host.c_str(), port_str.c_str(), &hints, &addrinfo_result); | ||||
|         int last_error = 0; | ||||
|         if (rv != 0) | ||||
|         { | ||||
|             last_error = ::WSAGetLastError(); | ||||
|             WSACleanup(); | ||||
|             throw_winsock_error_("getaddrinfo failed", last_error); | ||||
|         } | ||||
| 
 | ||||
|         // Try each address until we successfully connect(2).
 | ||||
| 
 | ||||
|         for (auto *rp = addrinfo_result; rp != nullptr; rp = rp->ai_next) | ||||
|         { | ||||
|             socket_ = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); | ||||
|             if (socket_ == INVALID_SOCKET) | ||||
|             { | ||||
|                 last_error = ::WSAGetLastError(); | ||||
|                 WSACleanup(); | ||||
|                 continue; | ||||
|             } | ||||
|             if (::connect(socket_, rp->ai_addr, (int)rp->ai_addrlen) == 0) | ||||
|             { | ||||
|                 break; | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 last_error = ::WSAGetLastError(); | ||||
|                 close(); | ||||
|             } | ||||
|         } | ||||
|         ::freeaddrinfo(addrinfo_result); | ||||
|         if (socket_ == INVALID_SOCKET) | ||||
|         { | ||||
|             WSACleanup(); | ||||
|             throw_winsock_error_("connect failed", last_error); | ||||
|         } | ||||
| 
 | ||||
|         // set TCP_NODELAY
 | ||||
|         int enable_flag = 1; | ||||
|         ::setsockopt(socket_, IPPROTO_TCP, TCP_NODELAY, reinterpret_cast<char *>(&enable_flag), sizeof(enable_flag)); | ||||
|     } | ||||
| 
 | ||||
|     // Send exactly n_bytes of the given data.
 | ||||
|     // On error close the connection and throw.
 | ||||
|     void send(const char *data, size_t n_bytes) | ||||
|     { | ||||
|         size_t bytes_sent = 0; | ||||
|         while (bytes_sent < n_bytes) | ||||
|         { | ||||
|             const int send_flags = 0; | ||||
|             auto write_result = ::send(socket_, data + bytes_sent, (int)(n_bytes - bytes_sent), send_flags); | ||||
|             if (write_result == SOCKET_ERROR) | ||||
|             { | ||||
|                 int last_error = ::WSAGetLastError(); | ||||
|                 close(); | ||||
|                 throw_winsock_error_("send failed", last_error); | ||||
|             } | ||||
| 
 | ||||
|             if (write_result == 0) // (probably should not happen but in any case..)
 | ||||
|             { | ||||
|                 break; | ||||
|             } | ||||
|             bytes_sent += static_cast<size_t>(write_result); | ||||
|         } | ||||
|     } | ||||
| }; | ||||
| } // namespace details
 | ||||
| } // namespace spdlog
 | ||||
|  | @ -1,145 +0,0 @@ | |||
| // Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
 | ||||
| // Distributed under the MIT License (http://opensource.org/licenses/MIT)
 | ||||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| #ifdef _WIN32 | ||||
| #    error include tcp_client-windows.h instead | ||||
| #endif | ||||
| 
 | ||||
| // tcp client helper
 | ||||
| #include <spdlog/common.h> | ||||
| #include <spdlog/details/os.h> | ||||
| 
 | ||||
| #include <sys/socket.h> | ||||
| #include <arpa/inet.h> | ||||
| #include <unistd.h> | ||||
| #include <netdb.h> | ||||
| #include <netinet/tcp.h> | ||||
| 
 | ||||
| #include <string> | ||||
| 
 | ||||
| namespace spdlog { | ||||
| namespace details { | ||||
| class tcp_client | ||||
| { | ||||
|     int socket_ = -1; | ||||
| 
 | ||||
| public: | ||||
|     bool is_connected() const | ||||
|     { | ||||
|         return socket_ != -1; | ||||
|     } | ||||
| 
 | ||||
|     void close() | ||||
|     { | ||||
|         if (is_connected()) | ||||
|         { | ||||
|             ::close(socket_); | ||||
|             socket_ = -1; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     int fd() const | ||||
|     { | ||||
|         return socket_; | ||||
|     } | ||||
| 
 | ||||
|     ~tcp_client() | ||||
|     { | ||||
|         close(); | ||||
|     } | ||||
| 
 | ||||
|     // try to connect or throw on failure
 | ||||
|     void connect(const std::string &host, int port) | ||||
|     { | ||||
|         close(); | ||||
|         struct addrinfo hints | ||||
|         {}; | ||||
|         memset(&hints, 0, sizeof(struct addrinfo)); | ||||
|         hints.ai_family = AF_INET;       // IPv4
 | ||||
|         hints.ai_socktype = SOCK_STREAM; // TCP
 | ||||
|         hints.ai_flags = AI_NUMERICSERV; // port passed as as numeric value
 | ||||
|         hints.ai_protocol = 0; | ||||
| 
 | ||||
|         auto port_str = std::to_string(port); | ||||
|         struct addrinfo *addrinfo_result; | ||||
|         auto rv = ::getaddrinfo(host.c_str(), port_str.c_str(), &hints, &addrinfo_result); | ||||
|         if (rv != 0) | ||||
|         { | ||||
|             throw_spdlog_ex(fmt_lib::format("::getaddrinfo failed: {}", gai_strerror(rv))); | ||||
|         } | ||||
| 
 | ||||
|         // Try each address until we successfully connect(2).
 | ||||
|         int last_errno = 0; | ||||
|         for (auto *rp = addrinfo_result; rp != nullptr; rp = rp->ai_next) | ||||
|         { | ||||
| #if defined(SOCK_CLOEXEC) | ||||
|             const int flags = SOCK_CLOEXEC; | ||||
| #else | ||||
|             const int flags = 0; | ||||
| #endif | ||||
|             socket_ = ::socket(rp->ai_family, rp->ai_socktype | flags, rp->ai_protocol); | ||||
|             if (socket_ == -1) | ||||
|             { | ||||
|                 last_errno = errno; | ||||
|                 continue; | ||||
|             } | ||||
|             rv = ::connect(socket_, rp->ai_addr, rp->ai_addrlen); | ||||
|             if (rv == 0) | ||||
|             { | ||||
|                 break; | ||||
|             } | ||||
|             last_errno = errno; | ||||
|             ::close(socket_); | ||||
|             socket_ = -1; | ||||
|         } | ||||
|         ::freeaddrinfo(addrinfo_result); | ||||
|         if (socket_ == -1) | ||||
|         { | ||||
|             throw_spdlog_ex("::connect failed", last_errno); | ||||
|         } | ||||
| 
 | ||||
|         // set TCP_NODELAY
 | ||||
|         int enable_flag = 1; | ||||
|         ::setsockopt(socket_, IPPROTO_TCP, TCP_NODELAY, reinterpret_cast<char *>(&enable_flag), sizeof(enable_flag)); | ||||
| 
 | ||||
|         // prevent sigpipe on systems where MSG_NOSIGNAL is not available
 | ||||
| #if defined(SO_NOSIGPIPE) && !defined(MSG_NOSIGNAL) | ||||
|         ::setsockopt(socket_, SOL_SOCKET, SO_NOSIGPIPE, reinterpret_cast<char *>(&enable_flag), sizeof(enable_flag)); | ||||
| #endif | ||||
| 
 | ||||
| #if !defined(SO_NOSIGPIPE) && !defined(MSG_NOSIGNAL) | ||||
| #    error "tcp_sink would raise SIGPIPE since niether SO_NOSIGPIPE nor MSG_NOSIGNAL are available" | ||||
| #endif | ||||
|     } | ||||
| 
 | ||||
|     // Send exactly n_bytes of the given data.
 | ||||
|     // On error close the connection and throw.
 | ||||
|     void send(const char *data, size_t n_bytes) | ||||
|     { | ||||
|         size_t bytes_sent = 0; | ||||
|         while (bytes_sent < n_bytes) | ||||
|         { | ||||
| #if defined(MSG_NOSIGNAL) | ||||
|             const int send_flags = MSG_NOSIGNAL; | ||||
| #else | ||||
|             const int send_flags = 0; | ||||
| #endif | ||||
|             auto write_result = ::send(socket_, data + bytes_sent, n_bytes - bytes_sent, send_flags); | ||||
|             if (write_result < 0) | ||||
|             { | ||||
|                 close(); | ||||
|                 throw_spdlog_ex("write(2) failed", errno); | ||||
|             } | ||||
| 
 | ||||
|             if (write_result == 0) // (probably should not happen but in any case..)
 | ||||
|             { | ||||
|                 break; | ||||
|             } | ||||
|             bytes_sent += static_cast<size_t>(write_result); | ||||
|         } | ||||
|     } | ||||
| }; | ||||
| } // namespace details
 | ||||
| } // namespace spdlog
 | ||||
|  | @ -1,136 +0,0 @@ | |||
| // 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> | ||||
| #include <cassert> | ||||
| 
 | ||||
| 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, std::function<void()> on_thread_stop) | ||||
|     : q_(q_max_items) | ||||
| { | ||||
|     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([this, on_thread_start, on_thread_stop] { | ||||
|             on_thread_start(); | ||||
|             this->thread_pool::worker_loop_(); | ||||
|             on_thread_stop(); | ||||
|         }); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| SPDLOG_INLINE thread_pool::thread_pool(size_t q_max_items, size_t threads_n, std::function<void()> on_thread_start) | ||||
|     : thread_pool(q_max_items, threads_n, on_thread_start, [] {}) | ||||
| {} | ||||
| 
 | ||||
| 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_STD | ||||
| } | ||||
| 
 | ||||
| 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(); | ||||
| } | ||||
| 
 | ||||
| size_t SPDLOG_INLINE thread_pool::queue_size() | ||||
| { | ||||
|     return q_.size(); | ||||
| } | ||||
| 
 | ||||
| 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); | ||||
|     } | ||||
|     } | ||||
| 
 | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| } // namespace details
 | ||||
| } // namespace spdlog
 | ||||
|  | @ -1,121 +0,0 @@ | |||
| // 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/mpmc_blocking_q.h> | ||||
| #include <spdlog/details/os.h> | ||||
| 
 | ||||
| #include <chrono> | ||||
| #include <memory> | ||||
| #include <thread> | ||||
| #include <vector> | ||||
| #include <functional> | ||||
| 
 | ||||
| namespace spdlog { | ||||
| class async_logger; | ||||
| 
 | ||||
| namespace details { | ||||
| 
 | ||||
| using async_logger_ptr = std::shared_ptr<spdlog::async_logger>; | ||||
| 
 | ||||
| enum class async_msg_type | ||||
| { | ||||
|     log, | ||||
|     flush, | ||||
|     terminate | ||||
| }; | ||||
| 
 | ||||
| // Async msg to move to/from the queue
 | ||||
| // Movable only. should never be copied
 | ||||
| struct async_msg : log_msg_buffer | ||||
| { | ||||
|     async_msg_type msg_type{async_msg_type::log}; | ||||
|     async_logger_ptr worker_ptr; | ||||
| 
 | ||||
|     async_msg() = default; | ||||
|     ~async_msg() = default; | ||||
| 
 | ||||
|     // should only be moved in or out of the queue..
 | ||||
|     async_msg(const async_msg &) = delete; | ||||
| 
 | ||||
| // support for vs2013 move
 | ||||
| #if defined(_MSC_VER) && _MSC_VER <= 1800 | ||||
|     async_msg(async_msg &&other) | ||||
|         : log_msg_buffer(std::move(other)) | ||||
|         , msg_type(other.msg_type) | ||||
|         , worker_ptr(std::move(other.worker_ptr)) | ||||
|     {} | ||||
| 
 | ||||
|     async_msg &operator=(async_msg &&other) | ||||
|     { | ||||
|         *static_cast<log_msg_buffer *>(this) = std::move(other); | ||||
|         msg_type = other.msg_type; | ||||
|         worker_ptr = std::move(other.worker_ptr); | ||||
|         return *this; | ||||
|     } | ||||
| #else // (_MSC_VER) && _MSC_VER <= 1800
 | ||||
|     async_msg(async_msg &&) = default; | ||||
|     async_msg &operator=(async_msg &&) = default; | ||||
| #endif | ||||
| 
 | ||||
|     // construct from log_msg with given type
 | ||||
|     async_msg(async_logger_ptr &&worker, async_msg_type the_type, const details::log_msg &m) | ||||
|         : log_msg_buffer{m} | ||||
|         , msg_type{the_type} | ||||
|         , worker_ptr{std::move(worker)} | ||||
|     {} | ||||
| 
 | ||||
|     async_msg(async_logger_ptr &&worker, async_msg_type the_type) | ||||
|         : log_msg_buffer{} | ||||
|         , msg_type{the_type} | ||||
|         , worker_ptr{std::move(worker)} | ||||
|     {} | ||||
| 
 | ||||
|     explicit async_msg(async_msg_type the_type) | ||||
|         : async_msg{nullptr, the_type} | ||||
|     {} | ||||
| }; | ||||
| 
 | ||||
| class SPDLOG_API thread_pool | ||||
| { | ||||
| public: | ||||
|     using item_type = async_msg; | ||||
|     using q_type = details::mpmc_blocking_queue<item_type>; | ||||
| 
 | ||||
|     thread_pool(size_t q_max_items, size_t threads_n, std::function<void()> on_thread_start, std::function<void()> on_thread_stop); | ||||
|     thread_pool(size_t q_max_items, size_t threads_n, std::function<void()> on_thread_start); | ||||
|     thread_pool(size_t q_max_items, size_t threads_n); | ||||
| 
 | ||||
|     // message all threads to terminate gracefully and join them
 | ||||
|     ~thread_pool(); | ||||
| 
 | ||||
|     thread_pool(const thread_pool &) = delete; | ||||
|     thread_pool &operator=(thread_pool &&) = delete; | ||||
| 
 | ||||
|     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); | ||||
|     size_t overrun_counter(); | ||||
|     size_t queue_size(); | ||||
| 
 | ||||
| private: | ||||
|     q_type q_; | ||||
| 
 | ||||
|     std::vector<std::thread> threads_; | ||||
| 
 | ||||
|     void post_async_msg_(async_msg &&new_msg, async_overflow_policy overflow_policy); | ||||
|     void worker_loop_(); | ||||
| 
 | ||||
|     // process next message in the queue
 | ||||
|     // return true if this thread should still be active (while no terminate msg
 | ||||
|     // was received)
 | ||||
|     bool process_next_msg_(); | ||||
| }; | ||||
| 
 | ||||
| } // namespace details
 | ||||
| } // namespace spdlog
 | ||||
| 
 | ||||
| #ifdef SPDLOG_HEADER_ONLY | ||||
| #    include "thread_pool-inl.h" | ||||
| #endif | ||||
|  | @ -1,111 +0,0 @@ | |||
| // Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
 | ||||
| // Distributed under the MIT License (http://opensource.org/licenses/MIT)
 | ||||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| // Helper RAII over winsock udp client socket.
 | ||||
| // Will throw on construction if socket creation failed.
 | ||||
| 
 | ||||
| #include <spdlog/common.h> | ||||
| #include <spdlog/details/os.h> | ||||
| #include <spdlog/details/windows_include.h> | ||||
| #include <winsock2.h> | ||||
| #include <ws2tcpip.h> | ||||
| #include <stdlib.h> | ||||
| #include <stdio.h> | ||||
| #include <string> | ||||
| 
 | ||||
| #pragma comment(lib, "Ws2_32.lib") | ||||
| #pragma comment(lib, "Mswsock.lib") | ||||
| #pragma comment(lib, "AdvApi32.lib") | ||||
| 
 | ||||
| namespace spdlog { | ||||
| namespace details { | ||||
| class udp_client | ||||
| { | ||||
|     static constexpr int TX_BUFFER_SIZE = 1024 * 10; | ||||
|     SOCKET socket_ = INVALID_SOCKET; | ||||
|     sockaddr_in addr_ = {0}; | ||||
| 
 | ||||
|     static void init_winsock_() | ||||
|     { | ||||
|         WSADATA wsaData; | ||||
|         auto rv = ::WSAStartup(MAKEWORD(2, 2), &wsaData); | ||||
|         if (rv != 0) | ||||
|         { | ||||
|             throw_winsock_error_("WSAStartup failed", ::WSAGetLastError()); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     static void throw_winsock_error_(const std::string &msg, int last_error) | ||||
|     { | ||||
|         char buf[512]; | ||||
|         ::FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, last_error, | ||||
|             MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), buf, (sizeof(buf) / sizeof(char)), NULL); | ||||
| 
 | ||||
|         throw_spdlog_ex(fmt_lib::format("udp_sink - {}: {}", msg, buf)); | ||||
|     } | ||||
| 
 | ||||
|     void cleanup_() | ||||
|     { | ||||
|         if (socket_ != INVALID_SOCKET) | ||||
|         { | ||||
|             ::closesocket(socket_); | ||||
|         } | ||||
|         socket_ = INVALID_SOCKET; | ||||
|         ::WSACleanup(); | ||||
|     } | ||||
| 
 | ||||
| public: | ||||
|     udp_client(const std::string &host, uint16_t port) | ||||
|     { | ||||
|         init_winsock_(); | ||||
| 
 | ||||
|         addr_.sin_family = PF_INET; | ||||
|         addr_.sin_port = htons(port); | ||||
|         addr_.sin_addr.s_addr = INADDR_ANY; | ||||
|         if (InetPtonA(PF_INET, host.c_str(), &addr_.sin_addr.s_addr) != 1) | ||||
|         { | ||||
|             int last_error = ::WSAGetLastError(); | ||||
|             ::WSACleanup(); | ||||
|             throw_winsock_error_("error: Invalid address!", last_error); | ||||
|         } | ||||
| 
 | ||||
|         socket_ = ::socket(PF_INET, SOCK_DGRAM, 0); | ||||
|         if (socket_ == INVALID_SOCKET) | ||||
|         { | ||||
|             int last_error = ::WSAGetLastError(); | ||||
|             ::WSACleanup(); | ||||
|             throw_winsock_error_("error: Create Socket failed", last_error); | ||||
|         } | ||||
| 
 | ||||
|         int option_value = TX_BUFFER_SIZE; | ||||
|         if (::setsockopt(socket_, SOL_SOCKET, SO_SNDBUF, reinterpret_cast<const char *>(&option_value), sizeof(option_value)) < 0) | ||||
|         { | ||||
|             int last_error = ::WSAGetLastError(); | ||||
|             cleanup_(); | ||||
|             throw_winsock_error_("error: setsockopt(SO_SNDBUF) Failed!", last_error); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     ~udp_client() | ||||
|     { | ||||
|         cleanup_(); | ||||
|     } | ||||
| 
 | ||||
|     SOCKET fd() const | ||||
|     { | ||||
|         return socket_; | ||||
|     } | ||||
| 
 | ||||
|     void send(const char *data, size_t n_bytes) | ||||
|     { | ||||
|         socklen_t tolen = sizeof(struct sockaddr); | ||||
|         if (::sendto(socket_, data, static_cast<int>(n_bytes), 0, (struct sockaddr *)&addr_, tolen) == -1) | ||||
|         { | ||||
|             throw_spdlog_ex("sendto(2) failed", errno); | ||||
|         } | ||||
|     } | ||||
| }; | ||||
| } // namespace details
 | ||||
| } // namespace spdlog
 | ||||
|  | @ -1,94 +0,0 @@ | |||
| // Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
 | ||||
| // Distributed under the MIT License (http://opensource.org/licenses/MIT)
 | ||||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| // Helper RAII over unix udp client socket.
 | ||||
| // Will throw on construction if the socket creation failed.
 | ||||
| 
 | ||||
| #ifdef _WIN32 | ||||
| #    error "include udp_client-windows.h instead" | ||||
| #endif | ||||
| 
 | ||||
| #include <spdlog/common.h> | ||||
| #include <spdlog/details/os.h> | ||||
| 
 | ||||
| #include <sys/socket.h> | ||||
| #include <netinet/in.h> | ||||
| #include <arpa/inet.h> | ||||
| #include <unistd.h> | ||||
| #include <netdb.h> | ||||
| #include <netinet/udp.h> | ||||
| 
 | ||||
| #include <string> | ||||
| 
 | ||||
| namespace spdlog { | ||||
| namespace details { | ||||
| 
 | ||||
| class udp_client | ||||
| { | ||||
|     static constexpr int TX_BUFFER_SIZE = 1024 * 10; | ||||
|     int socket_ = -1; | ||||
|     struct sockaddr_in sockAddr_; | ||||
| 
 | ||||
|     void cleanup_() | ||||
|     { | ||||
|         if (socket_ != -1) | ||||
|         { | ||||
|             ::close(socket_); | ||||
|             socket_ = -1; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| public: | ||||
|     udp_client(const std::string &host, uint16_t port) | ||||
|     { | ||||
|         socket_ = ::socket(PF_INET, SOCK_DGRAM, 0); | ||||
|         if (socket_ < 0) | ||||
|         { | ||||
|             throw_spdlog_ex("error: Create Socket Failed!"); | ||||
|         } | ||||
| 
 | ||||
|         int option_value = TX_BUFFER_SIZE; | ||||
|         if (::setsockopt(socket_, SOL_SOCKET, SO_SNDBUF, reinterpret_cast<const char *>(&option_value), sizeof(option_value)) < 0) | ||||
|         { | ||||
|             cleanup_(); | ||||
|             throw_spdlog_ex("error: setsockopt(SO_SNDBUF) Failed!"); | ||||
|         } | ||||
| 
 | ||||
|         sockAddr_.sin_family = AF_INET; | ||||
|         sockAddr_.sin_port = htons(port); | ||||
| 
 | ||||
|         if (::inet_aton(host.c_str(), &sockAddr_.sin_addr) == 0) | ||||
|         { | ||||
|             cleanup_(); | ||||
|             throw_spdlog_ex("error: Invalid address!"); | ||||
|         } | ||||
| 
 | ||||
|         ::memset(sockAddr_.sin_zero, 0x00, sizeof(sockAddr_.sin_zero)); | ||||
|     } | ||||
| 
 | ||||
|     ~udp_client() | ||||
|     { | ||||
|         cleanup_(); | ||||
|     } | ||||
| 
 | ||||
|     int fd() const | ||||
|     { | ||||
|         return socket_; | ||||
|     } | ||||
| 
 | ||||
|     // Send exactly n_bytes of the given data.
 | ||||
|     // On error close the connection and throw.
 | ||||
|     void send(const char *data, size_t n_bytes) | ||||
|     { | ||||
|         ssize_t toslen = 0; | ||||
|         socklen_t tolen = sizeof(struct sockaddr); | ||||
|         if ((toslen = ::sendto(socket_, data, n_bytes, 0, (struct sockaddr *)&sockAddr_, tolen)) == -1) | ||||
|         { | ||||
|             throw_spdlog_ex("sendto(2) failed", errno); | ||||
|         } | ||||
|     } | ||||
| }; | ||||
| } // namespace details
 | ||||
| } // namespace spdlog
 | ||||
|  | @ -1,11 +0,0 @@ | |||
| #pragma once | ||||
| 
 | ||||
| #ifndef NOMINMAX | ||||
| #    define NOMINMAX // prevent windows redefining min/max
 | ||||
| #endif | ||||
| 
 | ||||
| #ifndef WIN32_LEAN_AND_MEAN | ||||
| #    define WIN32_LEAN_AND_MEAN | ||||
| #endif | ||||
| 
 | ||||
| #include <windows.h> | ||||
							
								
								
									
										246
									
								
								Dependencies/spdlog/include/spdlog/fmt/bin_to_hex.h
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										246
									
								
								Dependencies/spdlog/include/spdlog/fmt/bin_to_hex.h
									
										
									
									
										vendored
									
									
								
							|  | @ -1,246 +0,0 @@ | |||
| //
 | ||||
| // Copyright(c) 2015 Gabi Melman.
 | ||||
| // Distributed under the MIT License (http://opensource.org/licenses/MIT)
 | ||||
| //
 | ||||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| #include <cctype> | ||||
| #include <spdlog/common.h> | ||||
| 
 | ||||
| #if defined(__has_include) && __has_include(<version>) | ||||
| #    include <version> | ||||
| #endif | ||||
| 
 | ||||
| #if __cpp_lib_span >= 202002L | ||||
| #    include <span> | ||||
| #endif | ||||
| 
 | ||||
| //
 | ||||
| // Support for logging binary data as hex
 | ||||
| // format flags, any combination of the following:
 | ||||
| // {:X} - print in uppercase.
 | ||||
| // {:s} - don't separate each byte with space.
 | ||||
| // {:p} - don't print the position on each line start.
 | ||||
| // {:n} - don't split the output to lines.
 | ||||
| // {:a} - show ASCII if :n is not set
 | ||||
| 
 | ||||
| //
 | ||||
| // Examples:
 | ||||
| //
 | ||||
| // std::vector<char> v(200, 0x0b);
 | ||||
| // logger->info("Some buffer {}", spdlog::to_hex(v));
 | ||||
| // char buf[128];
 | ||||
| // logger->info("Some buffer {:X}", spdlog::to_hex(std::begin(buf), std::end(buf)));
 | ||||
| // logger->info("Some buffer {:X}", spdlog::to_hex(std::begin(buf), std::end(buf), 16));
 | ||||
| 
 | ||||
| namespace spdlog { | ||||
| namespace details { | ||||
| 
 | ||||
| template<typename It> | ||||
| class dump_info | ||||
| { | ||||
| public: | ||||
|     dump_info(It range_begin, It range_end, size_t size_per_line) | ||||
|         : begin_(range_begin) | ||||
|         , end_(range_end) | ||||
|         , size_per_line_(size_per_line) | ||||
|     {} | ||||
| 
 | ||||
|     // do not use begin() and end() to avoid collision with fmt/ranges
 | ||||
|     It get_begin() const | ||||
|     { | ||||
|         return begin_; | ||||
|     } | ||||
|     It get_end() const | ||||
|     { | ||||
|         return end_; | ||||
|     } | ||||
|     size_t size_per_line() const | ||||
|     { | ||||
|         return size_per_line_; | ||||
|     } | ||||
| 
 | ||||
| private: | ||||
|     It begin_, end_; | ||||
|     size_t size_per_line_; | ||||
| }; | ||||
| } // namespace details
 | ||||
| 
 | ||||
| // create a dump_info that wraps the given container
 | ||||
| template<typename Container> | ||||
| inline details::dump_info<typename Container::const_iterator> to_hex(const Container &container, size_t size_per_line = 32) | ||||
| { | ||||
|     static_assert(sizeof(typename Container::value_type) == 1, "sizeof(Container::value_type) != 1"); | ||||
|     using Iter = typename Container::const_iterator; | ||||
|     return details::dump_info<Iter>(std::begin(container), std::end(container), size_per_line); | ||||
| } | ||||
| 
 | ||||
| #if __cpp_lib_span >= 202002L | ||||
| 
 | ||||
| template<typename Value, size_t Extent> | ||||
| inline details::dump_info<typename std::span<Value, Extent>::iterator> to_hex( | ||||
|     const std::span<Value, Extent> &container, size_t size_per_line = 32) | ||||
| { | ||||
|     using Container = std::span<Value, Extent>; | ||||
|     static_assert(sizeof(typename Container::value_type) == 1, "sizeof(Container::value_type) != 1"); | ||||
|     using Iter = typename Container::iterator; | ||||
|     return details::dump_info<Iter>(std::begin(container), std::end(container), size_per_line); | ||||
| } | ||||
| 
 | ||||
| #endif | ||||
| 
 | ||||
| // create dump_info from ranges
 | ||||
| template<typename It> | ||||
| inline details::dump_info<It> to_hex(const It range_begin, const It range_end, size_t size_per_line = 32) | ||||
| { | ||||
|     return details::dump_info<It>(range_begin, range_end, size_per_line); | ||||
| } | ||||
| 
 | ||||
| } // namespace spdlog
 | ||||
| 
 | ||||
| namespace | ||||
| #ifdef SPDLOG_USE_STD_FORMAT | ||||
|     std | ||||
| #else | ||||
|     fmt | ||||
| #endif | ||||
| { | ||||
| 
 | ||||
| template<typename T> | ||||
| struct formatter<spdlog::details::dump_info<T>, char> | ||||
| { | ||||
|     const char delimiter = ' '; | ||||
|     bool put_newlines = true; | ||||
|     bool put_delimiters = true; | ||||
|     bool use_uppercase = false; | ||||
|     bool put_positions = true; // position on start of each line
 | ||||
|     bool show_ascii = false; | ||||
| 
 | ||||
|     // parse the format string flags
 | ||||
|     template<typename ParseContext> | ||||
|     SPDLOG_CONSTEXPR_FUNC auto parse(ParseContext &ctx) -> decltype(ctx.begin()) | ||||
|     { | ||||
|         auto it = ctx.begin(); | ||||
|         while (it != ctx.end() && *it != '}') | ||||
|         { | ||||
|             switch (*it) | ||||
|             { | ||||
|             case 'X': | ||||
|                 use_uppercase = true; | ||||
|                 break; | ||||
|             case 's': | ||||
|                 put_delimiters = false; | ||||
|                 break; | ||||
|             case 'p': | ||||
|                 put_positions = false; | ||||
|                 break; | ||||
|             case 'n': | ||||
|                 put_newlines = false; | ||||
|                 show_ascii = false; | ||||
|                 break; | ||||
|             case 'a': | ||||
|                 if (put_newlines) | ||||
|                 { | ||||
|                     show_ascii = true; | ||||
|                 } | ||||
|                 break; | ||||
|             } | ||||
| 
 | ||||
|             ++it; | ||||
|         } | ||||
|         return it; | ||||
|     } | ||||
| 
 | ||||
|     // format the given bytes range as hex
 | ||||
|     template<typename FormatContext, typename Container> | ||||
|     auto format(const spdlog::details::dump_info<Container> &the_range, FormatContext &ctx) -> decltype(ctx.out()) | ||||
|     { | ||||
|         SPDLOG_CONSTEXPR const char *hex_upper = "0123456789ABCDEF"; | ||||
|         SPDLOG_CONSTEXPR const char *hex_lower = "0123456789abcdef"; | ||||
|         const char *hex_chars = use_uppercase ? hex_upper : hex_lower; | ||||
| 
 | ||||
| #if !defined(SPDLOG_USE_STD_FORMAT) && FMT_VERSION < 60000 | ||||
|         auto inserter = ctx.begin(); | ||||
| #else | ||||
|         auto inserter = ctx.out(); | ||||
| #endif | ||||
| 
 | ||||
|         int size_per_line = static_cast<int>(the_range.size_per_line()); | ||||
|         auto start_of_line = the_range.get_begin(); | ||||
|         for (auto i = the_range.get_begin(); i != the_range.get_end(); i++) | ||||
|         { | ||||
|             auto ch = static_cast<unsigned char>(*i); | ||||
| 
 | ||||
|             if (put_newlines && (i == the_range.get_begin() || i - start_of_line >= size_per_line)) | ||||
|             { | ||||
|                 if (show_ascii && i != the_range.get_begin()) | ||||
|                 { | ||||
|                     *inserter++ = delimiter; | ||||
|                     *inserter++ = delimiter; | ||||
|                     for (auto j = start_of_line; j < i; j++) | ||||
|                     { | ||||
|                         auto pc = static_cast<unsigned char>(*j); | ||||
|                         *inserter++ = std::isprint(pc) ? static_cast<char>(*j) : '.'; | ||||
|                     } | ||||
|                 } | ||||
| 
 | ||||
|                 put_newline(inserter, static_cast<size_t>(i - the_range.get_begin())); | ||||
| 
 | ||||
|                 // put first byte without delimiter in front of it
 | ||||
|                 *inserter++ = hex_chars[(ch >> 4) & 0x0f]; | ||||
|                 *inserter++ = hex_chars[ch & 0x0f]; | ||||
|                 start_of_line = i; | ||||
|                 continue; | ||||
|             } | ||||
| 
 | ||||
|             if (put_delimiters) | ||||
|             { | ||||
|                 *inserter++ = delimiter; | ||||
|             } | ||||
| 
 | ||||
|             *inserter++ = hex_chars[(ch >> 4) & 0x0f]; | ||||
|             *inserter++ = hex_chars[ch & 0x0f]; | ||||
|         } | ||||
|         if (show_ascii) // add ascii to last line
 | ||||
|         { | ||||
|             if (the_range.get_end() - the_range.get_begin() > size_per_line) | ||||
|             { | ||||
|                 auto blank_num = size_per_line - (the_range.get_end() - start_of_line); | ||||
|                 while (blank_num-- > 0) | ||||
|                 { | ||||
|                     *inserter++ = delimiter; | ||||
|                     *inserter++ = delimiter; | ||||
|                     if (put_delimiters) | ||||
|                     { | ||||
|                         *inserter++ = delimiter; | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|             *inserter++ = delimiter; | ||||
|             *inserter++ = delimiter; | ||||
|             for (auto j = start_of_line; j != the_range.get_end(); j++) | ||||
|             { | ||||
|                 auto pc = static_cast<unsigned char>(*j); | ||||
|                 *inserter++ = std::isprint(pc) ? static_cast<char>(*j) : '.'; | ||||
|             } | ||||
|         } | ||||
|         return inserter; | ||||
|     } | ||||
| 
 | ||||
|     // put newline(and position header)
 | ||||
|     template<typename It> | ||||
|     void put_newline(It inserter, std::size_t pos) | ||||
|     { | ||||
| #ifdef _WIN32 | ||||
|         *inserter++ = '\r'; | ||||
| #endif | ||||
|         *inserter++ = '\n'; | ||||
| 
 | ||||
|         if (put_positions) | ||||
|         { | ||||
|             spdlog::fmt_lib::format_to(inserter, "{:04X}: ", pos); | ||||
|         } | ||||
|     } | ||||
| }; | ||||
| } // namespace std
 | ||||
|  | @ -1,234 +0,0 @@ | |||
| // Formatting library for C++ - dynamic format arguments
 | ||||
| //
 | ||||
| // Copyright (c) 2012 - present, Victor Zverovich
 | ||||
| // All rights reserved.
 | ||||
| //
 | ||||
| // For the license information refer to format.h.
 | ||||
| 
 | ||||
| #ifndef FMT_ARGS_H_ | ||||
| #define FMT_ARGS_H_ | ||||
| 
 | ||||
| #include <functional>  // std::reference_wrapper | ||||
| #include <memory>      // std::unique_ptr | ||||
| #include <vector> | ||||
| 
 | ||||
| #include "core.h" | ||||
| 
 | ||||
| FMT_BEGIN_NAMESPACE | ||||
| 
 | ||||
| namespace detail { | ||||
| 
 | ||||
| template <typename T> struct is_reference_wrapper : std::false_type {}; | ||||
| template <typename T> | ||||
| struct is_reference_wrapper<std::reference_wrapper<T>> : std::true_type {}; | ||||
| 
 | ||||
| template <typename T> const T& unwrap(const T& v) { return v; } | ||||
| template <typename T> const T& unwrap(const std::reference_wrapper<T>& v) { | ||||
|   return static_cast<const T&>(v); | ||||
| } | ||||
| 
 | ||||
| class dynamic_arg_list { | ||||
|   // Workaround for clang's -Wweak-vtables. Unlike for regular classes, for
 | ||||
|   // templates it doesn't complain about inability to deduce single translation
 | ||||
|   // unit for placing vtable. So storage_node_base is made a fake template.
 | ||||
|   template <typename = void> struct node { | ||||
|     virtual ~node() = default; | ||||
|     std::unique_ptr<node<>> next; | ||||
|   }; | ||||
| 
 | ||||
|   template <typename T> struct typed_node : node<> { | ||||
|     T value; | ||||
| 
 | ||||
|     template <typename Arg> | ||||
|     FMT_CONSTEXPR typed_node(const Arg& arg) : value(arg) {} | ||||
| 
 | ||||
|     template <typename Char> | ||||
|     FMT_CONSTEXPR typed_node(const basic_string_view<Char>& arg) | ||||
|         : value(arg.data(), arg.size()) {} | ||||
|   }; | ||||
| 
 | ||||
|   std::unique_ptr<node<>> head_; | ||||
| 
 | ||||
|  public: | ||||
|   template <typename T, typename Arg> const T& push(const Arg& arg) { | ||||
|     auto new_node = std::unique_ptr<typed_node<T>>(new typed_node<T>(arg)); | ||||
|     auto& value = new_node->value; | ||||
|     new_node->next = std::move(head_); | ||||
|     head_ = std::move(new_node); | ||||
|     return value; | ||||
|   } | ||||
| }; | ||||
| }  // namespace detail
 | ||||
| 
 | ||||
| /**
 | ||||
|   \rst | ||||
|   A dynamic version of `fmt::format_arg_store`. | ||||
|   It's equipped with a storage to potentially temporary objects which lifetimes | ||||
|   could be shorter than the format arguments object. | ||||
| 
 | ||||
|   It can be implicitly converted into `~fmt::basic_format_args` for passing | ||||
|   into type-erased formatting functions such as `~fmt::vformat`. | ||||
|   \endrst | ||||
|  */ | ||||
| template <typename Context> | ||||
| class dynamic_format_arg_store | ||||
| #if FMT_GCC_VERSION && FMT_GCC_VERSION < 409 | ||||
|     // Workaround a GCC template argument substitution bug.
 | ||||
|     : public basic_format_args<Context> | ||||
| #endif | ||||
| { | ||||
|  private: | ||||
|   using char_type = typename Context::char_type; | ||||
| 
 | ||||
|   template <typename T> struct need_copy { | ||||
|     static constexpr detail::type mapped_type = | ||||
|         detail::mapped_type_constant<T, Context>::value; | ||||
| 
 | ||||
|     enum { | ||||
|       value = !(detail::is_reference_wrapper<T>::value || | ||||
|                 std::is_same<T, basic_string_view<char_type>>::value || | ||||
|                 std::is_same<T, detail::std_string_view<char_type>>::value || | ||||
|                 (mapped_type != detail::type::cstring_type && | ||||
|                  mapped_type != detail::type::string_type && | ||||
|                  mapped_type != detail::type::custom_type)) | ||||
|     }; | ||||
|   }; | ||||
| 
 | ||||
|   template <typename T> | ||||
|   using stored_type = conditional_t<detail::is_string<T>::value && | ||||
|                                         !has_formatter<T, Context>::value && | ||||
|                                         !detail::is_reference_wrapper<T>::value, | ||||
|                                     std::basic_string<char_type>, T>; | ||||
| 
 | ||||
|   // Storage of basic_format_arg must be contiguous.
 | ||||
|   std::vector<basic_format_arg<Context>> data_; | ||||
|   std::vector<detail::named_arg_info<char_type>> named_info_; | ||||
| 
 | ||||
|   // Storage of arguments not fitting into basic_format_arg must grow
 | ||||
|   // without relocation because items in data_ refer to it.
 | ||||
|   detail::dynamic_arg_list dynamic_args_; | ||||
| 
 | ||||
|   friend class basic_format_args<Context>; | ||||
| 
 | ||||
|   unsigned long long get_types() const { | ||||
|     return detail::is_unpacked_bit | data_.size() | | ||||
|            (named_info_.empty() | ||||
|                 ? 0ULL | ||||
|                 : static_cast<unsigned long long>(detail::has_named_args_bit)); | ||||
|   } | ||||
| 
 | ||||
|   const basic_format_arg<Context>* data() const { | ||||
|     return named_info_.empty() ? data_.data() : data_.data() + 1; | ||||
|   } | ||||
| 
 | ||||
|   template <typename T> void emplace_arg(const T& arg) { | ||||
|     data_.emplace_back(detail::make_arg<Context>(arg)); | ||||
|   } | ||||
| 
 | ||||
|   template <typename T> | ||||
|   void emplace_arg(const detail::named_arg<char_type, T>& arg) { | ||||
|     if (named_info_.empty()) { | ||||
|       constexpr const detail::named_arg_info<char_type>* zero_ptr{nullptr}; | ||||
|       data_.insert(data_.begin(), {zero_ptr, 0}); | ||||
|     } | ||||
|     data_.emplace_back(detail::make_arg<Context>(detail::unwrap(arg.value))); | ||||
|     auto pop_one = [](std::vector<basic_format_arg<Context>>* data) { | ||||
|       data->pop_back(); | ||||
|     }; | ||||
|     std::unique_ptr<std::vector<basic_format_arg<Context>>, decltype(pop_one)> | ||||
|         guard{&data_, pop_one}; | ||||
|     named_info_.push_back({arg.name, static_cast<int>(data_.size() - 2u)}); | ||||
|     data_[0].value_.named_args = {named_info_.data(), named_info_.size()}; | ||||
|     guard.release(); | ||||
|   } | ||||
| 
 | ||||
|  public: | ||||
|   constexpr dynamic_format_arg_store() = default; | ||||
| 
 | ||||
|   /**
 | ||||
|     \rst | ||||
|     Adds an argument into the dynamic store for later passing to a formatting | ||||
|     function. | ||||
| 
 | ||||
|     Note that custom types and string types (but not string views) are copied | ||||
|     into the store dynamically allocating memory if necessary. | ||||
| 
 | ||||
|     **Example**:: | ||||
| 
 | ||||
|       fmt::dynamic_format_arg_store<fmt::format_context> store; | ||||
|       store.push_back(42); | ||||
|       store.push_back("abc"); | ||||
|       store.push_back(1.5f); | ||||
|       std::string result = fmt::vformat("{} and {} and {}", store); | ||||
|     \endrst | ||||
|   */ | ||||
|   template <typename T> void push_back(const T& arg) { | ||||
|     if (detail::const_check(need_copy<T>::value)) | ||||
|       emplace_arg(dynamic_args_.push<stored_type<T>>(arg)); | ||||
|     else | ||||
|       emplace_arg(detail::unwrap(arg)); | ||||
|   } | ||||
| 
 | ||||
|   /**
 | ||||
|     \rst | ||||
|     Adds a reference to the argument into the dynamic store for later passing to | ||||
|     a formatting function. | ||||
| 
 | ||||
|     **Example**:: | ||||
| 
 | ||||
|       fmt::dynamic_format_arg_store<fmt::format_context> store; | ||||
|       char band[] = "Rolling Stones"; | ||||
|       store.push_back(std::cref(band)); | ||||
|       band[9] = 'c'; // Changing str affects the output.
 | ||||
|       std::string result = fmt::vformat("{}", store); | ||||
|       // result == "Rolling Scones"
 | ||||
|     \endrst | ||||
|   */ | ||||
|   template <typename T> void push_back(std::reference_wrapper<T> arg) { | ||||
|     static_assert( | ||||
|         need_copy<T>::value, | ||||
|         "objects of built-in types and string views are always copied"); | ||||
|     emplace_arg(arg.get()); | ||||
|   } | ||||
| 
 | ||||
|   /**
 | ||||
|     Adds named argument into the dynamic store for later passing to a formatting | ||||
|     function. ``std::reference_wrapper`` is supported to avoid copying of the | ||||
|     argument. The name is always copied into the store. | ||||
|   */ | ||||
|   template <typename T> | ||||
|   void push_back(const detail::named_arg<char_type, T>& arg) { | ||||
|     const char_type* arg_name = | ||||
|         dynamic_args_.push<std::basic_string<char_type>>(arg.name).c_str(); | ||||
|     if (detail::const_check(need_copy<T>::value)) { | ||||
|       emplace_arg( | ||||
|           fmt::arg(arg_name, dynamic_args_.push<stored_type<T>>(arg.value))); | ||||
|     } else { | ||||
|       emplace_arg(fmt::arg(arg_name, arg.value)); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   /** Erase all elements from the store */ | ||||
|   void clear() { | ||||
|     data_.clear(); | ||||
|     named_info_.clear(); | ||||
|     dynamic_args_ = detail::dynamic_arg_list(); | ||||
|   } | ||||
| 
 | ||||
|   /**
 | ||||
|     \rst | ||||
|     Reserves space to store at least *new_cap* arguments including | ||||
|     *new_cap_named* named arguments. | ||||
|     \endrst | ||||
|   */ | ||||
|   void reserve(size_t new_cap, size_t new_cap_named) { | ||||
|     FMT_ASSERT(new_cap >= new_cap_named, | ||||
|                "Set of arguments includes set of named arguments"); | ||||
|     data_.reserve(new_cap); | ||||
|     named_info_.reserve(new_cap_named); | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| FMT_END_NAMESPACE | ||||
| 
 | ||||
| #endif  // FMT_ARGS_H_
 | ||||
							
								
								
									
										2067
									
								
								Dependencies/spdlog/include/spdlog/fmt/bundled/chrono.h
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										2067
									
								
								Dependencies/spdlog/include/spdlog/fmt/bundled/chrono.h
									
										
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							|  | @ -1,638 +0,0 @@ | |||
| // Formatting library for C++ - color support
 | ||||
| //
 | ||||
| // Copyright (c) 2018 - present, Victor Zverovich and fmt contributors
 | ||||
| // All rights reserved.
 | ||||
| //
 | ||||
| // For the license information refer to format.h.
 | ||||
| 
 | ||||
| #ifndef FMT_COLOR_H_ | ||||
| #define FMT_COLOR_H_ | ||||
| 
 | ||||
| #include "format.h" | ||||
| 
 | ||||
| // __declspec(deprecated) is broken in some MSVC versions.
 | ||||
| #if FMT_MSC_VER | ||||
| #  define FMT_DEPRECATED_NONMSVC | ||||
| #else | ||||
| #  define FMT_DEPRECATED_NONMSVC FMT_DEPRECATED | ||||
| #endif | ||||
| 
 | ||||
| FMT_BEGIN_NAMESPACE | ||||
| FMT_MODULE_EXPORT_BEGIN | ||||
| 
 | ||||
| enum class color : uint32_t { | ||||
|   alice_blue = 0xF0F8FF,               // rgb(240,248,255)
 | ||||
|   antique_white = 0xFAEBD7,            // rgb(250,235,215)
 | ||||
|   aqua = 0x00FFFF,                     // rgb(0,255,255)
 | ||||
|   aquamarine = 0x7FFFD4,               // rgb(127,255,212)
 | ||||
|   azure = 0xF0FFFF,                    // rgb(240,255,255)
 | ||||
|   beige = 0xF5F5DC,                    // rgb(245,245,220)
 | ||||
|   bisque = 0xFFE4C4,                   // rgb(255,228,196)
 | ||||
|   black = 0x000000,                    // rgb(0,0,0)
 | ||||
|   blanched_almond = 0xFFEBCD,          // rgb(255,235,205)
 | ||||
|   blue = 0x0000FF,                     // rgb(0,0,255)
 | ||||
|   blue_violet = 0x8A2BE2,              // rgb(138,43,226)
 | ||||
|   brown = 0xA52A2A,                    // rgb(165,42,42)
 | ||||
|   burly_wood = 0xDEB887,               // rgb(222,184,135)
 | ||||
|   cadet_blue = 0x5F9EA0,               // rgb(95,158,160)
 | ||||
|   chartreuse = 0x7FFF00,               // rgb(127,255,0)
 | ||||
|   chocolate = 0xD2691E,                // rgb(210,105,30)
 | ||||
|   coral = 0xFF7F50,                    // rgb(255,127,80)
 | ||||
|   cornflower_blue = 0x6495ED,          // rgb(100,149,237)
 | ||||
|   cornsilk = 0xFFF8DC,                 // rgb(255,248,220)
 | ||||
|   crimson = 0xDC143C,                  // rgb(220,20,60)
 | ||||
|   cyan = 0x00FFFF,                     // rgb(0,255,255)
 | ||||
|   dark_blue = 0x00008B,                // rgb(0,0,139)
 | ||||
|   dark_cyan = 0x008B8B,                // rgb(0,139,139)
 | ||||
|   dark_golden_rod = 0xB8860B,          // rgb(184,134,11)
 | ||||
|   dark_gray = 0xA9A9A9,                // rgb(169,169,169)
 | ||||
|   dark_green = 0x006400,               // rgb(0,100,0)
 | ||||
|   dark_khaki = 0xBDB76B,               // rgb(189,183,107)
 | ||||
|   dark_magenta = 0x8B008B,             // rgb(139,0,139)
 | ||||
|   dark_olive_green = 0x556B2F,         // rgb(85,107,47)
 | ||||
|   dark_orange = 0xFF8C00,              // rgb(255,140,0)
 | ||||
|   dark_orchid = 0x9932CC,              // rgb(153,50,204)
 | ||||
|   dark_red = 0x8B0000,                 // rgb(139,0,0)
 | ||||
|   dark_salmon = 0xE9967A,              // rgb(233,150,122)
 | ||||
|   dark_sea_green = 0x8FBC8F,           // rgb(143,188,143)
 | ||||
|   dark_slate_blue = 0x483D8B,          // rgb(72,61,139)
 | ||||
|   dark_slate_gray = 0x2F4F4F,          // rgb(47,79,79)
 | ||||
|   dark_turquoise = 0x00CED1,           // rgb(0,206,209)
 | ||||
|   dark_violet = 0x9400D3,              // rgb(148,0,211)
 | ||||
|   deep_pink = 0xFF1493,                // rgb(255,20,147)
 | ||||
|   deep_sky_blue = 0x00BFFF,            // rgb(0,191,255)
 | ||||
|   dim_gray = 0x696969,                 // rgb(105,105,105)
 | ||||
|   dodger_blue = 0x1E90FF,              // rgb(30,144,255)
 | ||||
|   fire_brick = 0xB22222,               // rgb(178,34,34)
 | ||||
|   floral_white = 0xFFFAF0,             // rgb(255,250,240)
 | ||||
|   forest_green = 0x228B22,             // rgb(34,139,34)
 | ||||
|   fuchsia = 0xFF00FF,                  // rgb(255,0,255)
 | ||||
|   gainsboro = 0xDCDCDC,                // rgb(220,220,220)
 | ||||
|   ghost_white = 0xF8F8FF,              // rgb(248,248,255)
 | ||||
|   gold = 0xFFD700,                     // rgb(255,215,0)
 | ||||
|   golden_rod = 0xDAA520,               // rgb(218,165,32)
 | ||||
|   gray = 0x808080,                     // rgb(128,128,128)
 | ||||
|   green = 0x008000,                    // rgb(0,128,0)
 | ||||
|   green_yellow = 0xADFF2F,             // rgb(173,255,47)
 | ||||
|   honey_dew = 0xF0FFF0,                // rgb(240,255,240)
 | ||||
|   hot_pink = 0xFF69B4,                 // rgb(255,105,180)
 | ||||
|   indian_red = 0xCD5C5C,               // rgb(205,92,92)
 | ||||
|   indigo = 0x4B0082,                   // rgb(75,0,130)
 | ||||
|   ivory = 0xFFFFF0,                    // rgb(255,255,240)
 | ||||
|   khaki = 0xF0E68C,                    // rgb(240,230,140)
 | ||||
|   lavender = 0xE6E6FA,                 // rgb(230,230,250)
 | ||||
|   lavender_blush = 0xFFF0F5,           // rgb(255,240,245)
 | ||||
|   lawn_green = 0x7CFC00,               // rgb(124,252,0)
 | ||||
|   lemon_chiffon = 0xFFFACD,            // rgb(255,250,205)
 | ||||
|   light_blue = 0xADD8E6,               // rgb(173,216,230)
 | ||||
|   light_coral = 0xF08080,              // rgb(240,128,128)
 | ||||
|   light_cyan = 0xE0FFFF,               // rgb(224,255,255)
 | ||||
|   light_golden_rod_yellow = 0xFAFAD2,  // rgb(250,250,210)
 | ||||
|   light_gray = 0xD3D3D3,               // rgb(211,211,211)
 | ||||
|   light_green = 0x90EE90,              // rgb(144,238,144)
 | ||||
|   light_pink = 0xFFB6C1,               // rgb(255,182,193)
 | ||||
|   light_salmon = 0xFFA07A,             // rgb(255,160,122)
 | ||||
|   light_sea_green = 0x20B2AA,          // rgb(32,178,170)
 | ||||
|   light_sky_blue = 0x87CEFA,           // rgb(135,206,250)
 | ||||
|   light_slate_gray = 0x778899,         // rgb(119,136,153)
 | ||||
|   light_steel_blue = 0xB0C4DE,         // rgb(176,196,222)
 | ||||
|   light_yellow = 0xFFFFE0,             // rgb(255,255,224)
 | ||||
|   lime = 0x00FF00,                     // rgb(0,255,0)
 | ||||
|   lime_green = 0x32CD32,               // rgb(50,205,50)
 | ||||
|   linen = 0xFAF0E6,                    // rgb(250,240,230)
 | ||||
|   magenta = 0xFF00FF,                  // rgb(255,0,255)
 | ||||
|   maroon = 0x800000,                   // rgb(128,0,0)
 | ||||
|   medium_aquamarine = 0x66CDAA,        // rgb(102,205,170)
 | ||||
|   medium_blue = 0x0000CD,              // rgb(0,0,205)
 | ||||
|   medium_orchid = 0xBA55D3,            // rgb(186,85,211)
 | ||||
|   medium_purple = 0x9370DB,            // rgb(147,112,219)
 | ||||
|   medium_sea_green = 0x3CB371,         // rgb(60,179,113)
 | ||||
|   medium_slate_blue = 0x7B68EE,        // rgb(123,104,238)
 | ||||
|   medium_spring_green = 0x00FA9A,      // rgb(0,250,154)
 | ||||
|   medium_turquoise = 0x48D1CC,         // rgb(72,209,204)
 | ||||
|   medium_violet_red = 0xC71585,        // rgb(199,21,133)
 | ||||
|   midnight_blue = 0x191970,            // rgb(25,25,112)
 | ||||
|   mint_cream = 0xF5FFFA,               // rgb(245,255,250)
 | ||||
|   misty_rose = 0xFFE4E1,               // rgb(255,228,225)
 | ||||
|   moccasin = 0xFFE4B5,                 // rgb(255,228,181)
 | ||||
|   navajo_white = 0xFFDEAD,             // rgb(255,222,173)
 | ||||
|   navy = 0x000080,                     // rgb(0,0,128)
 | ||||
|   old_lace = 0xFDF5E6,                 // rgb(253,245,230)
 | ||||
|   olive = 0x808000,                    // rgb(128,128,0)
 | ||||
|   olive_drab = 0x6B8E23,               // rgb(107,142,35)
 | ||||
|   orange = 0xFFA500,                   // rgb(255,165,0)
 | ||||
|   orange_red = 0xFF4500,               // rgb(255,69,0)
 | ||||
|   orchid = 0xDA70D6,                   // rgb(218,112,214)
 | ||||
|   pale_golden_rod = 0xEEE8AA,          // rgb(238,232,170)
 | ||||
|   pale_green = 0x98FB98,               // rgb(152,251,152)
 | ||||
|   pale_turquoise = 0xAFEEEE,           // rgb(175,238,238)
 | ||||
|   pale_violet_red = 0xDB7093,          // rgb(219,112,147)
 | ||||
|   papaya_whip = 0xFFEFD5,              // rgb(255,239,213)
 | ||||
|   peach_puff = 0xFFDAB9,               // rgb(255,218,185)
 | ||||
|   peru = 0xCD853F,                     // rgb(205,133,63)
 | ||||
|   pink = 0xFFC0CB,                     // rgb(255,192,203)
 | ||||
|   plum = 0xDDA0DD,                     // rgb(221,160,221)
 | ||||
|   powder_blue = 0xB0E0E6,              // rgb(176,224,230)
 | ||||
|   purple = 0x800080,                   // rgb(128,0,128)
 | ||||
|   rebecca_purple = 0x663399,           // rgb(102,51,153)
 | ||||
|   red = 0xFF0000,                      // rgb(255,0,0)
 | ||||
|   rosy_brown = 0xBC8F8F,               // rgb(188,143,143)
 | ||||
|   royal_blue = 0x4169E1,               // rgb(65,105,225)
 | ||||
|   saddle_brown = 0x8B4513,             // rgb(139,69,19)
 | ||||
|   salmon = 0xFA8072,                   // rgb(250,128,114)
 | ||||
|   sandy_brown = 0xF4A460,              // rgb(244,164,96)
 | ||||
|   sea_green = 0x2E8B57,                // rgb(46,139,87)
 | ||||
|   sea_shell = 0xFFF5EE,                // rgb(255,245,238)
 | ||||
|   sienna = 0xA0522D,                   // rgb(160,82,45)
 | ||||
|   silver = 0xC0C0C0,                   // rgb(192,192,192)
 | ||||
|   sky_blue = 0x87CEEB,                 // rgb(135,206,235)
 | ||||
|   slate_blue = 0x6A5ACD,               // rgb(106,90,205)
 | ||||
|   slate_gray = 0x708090,               // rgb(112,128,144)
 | ||||
|   snow = 0xFFFAFA,                     // rgb(255,250,250)
 | ||||
|   spring_green = 0x00FF7F,             // rgb(0,255,127)
 | ||||
|   steel_blue = 0x4682B4,               // rgb(70,130,180)
 | ||||
|   tan = 0xD2B48C,                      // rgb(210,180,140)
 | ||||
|   teal = 0x008080,                     // rgb(0,128,128)
 | ||||
|   thistle = 0xD8BFD8,                  // rgb(216,191,216)
 | ||||
|   tomato = 0xFF6347,                   // rgb(255,99,71)
 | ||||
|   turquoise = 0x40E0D0,                // rgb(64,224,208)
 | ||||
|   violet = 0xEE82EE,                   // rgb(238,130,238)
 | ||||
|   wheat = 0xF5DEB3,                    // rgb(245,222,179)
 | ||||
|   white = 0xFFFFFF,                    // rgb(255,255,255)
 | ||||
|   white_smoke = 0xF5F5F5,              // rgb(245,245,245)
 | ||||
|   yellow = 0xFFFF00,                   // rgb(255,255,0)
 | ||||
|   yellow_green = 0x9ACD32              // rgb(154,205,50)
 | ||||
| };                                     // enum class color
 | ||||
| 
 | ||||
| enum class terminal_color : uint8_t { | ||||
|   black = 30, | ||||
|   red, | ||||
|   green, | ||||
|   yellow, | ||||
|   blue, | ||||
|   magenta, | ||||
|   cyan, | ||||
|   white, | ||||
|   bright_black = 90, | ||||
|   bright_red, | ||||
|   bright_green, | ||||
|   bright_yellow, | ||||
|   bright_blue, | ||||
|   bright_magenta, | ||||
|   bright_cyan, | ||||
|   bright_white | ||||
| }; | ||||
| 
 | ||||
| enum class emphasis : uint8_t { | ||||
|   bold = 1, | ||||
|   faint = 1 << 1, | ||||
|   italic = 1 << 2, | ||||
|   underline = 1 << 3, | ||||
|   blink = 1 << 4, | ||||
|   reverse = 1 << 5, | ||||
|   conceal = 1 << 6, | ||||
|   strikethrough = 1 << 7, | ||||
| }; | ||||
| 
 | ||||
| // rgb is a struct for red, green and blue colors.
 | ||||
| // Using the name "rgb" makes some editors show the color in a tooltip.
 | ||||
| struct rgb { | ||||
|   FMT_CONSTEXPR rgb() : r(0), g(0), b(0) {} | ||||
|   FMT_CONSTEXPR rgb(uint8_t r_, uint8_t g_, uint8_t b_) : r(r_), g(g_), b(b_) {} | ||||
|   FMT_CONSTEXPR rgb(uint32_t hex) | ||||
|       : r((hex >> 16) & 0xFF), g((hex >> 8) & 0xFF), b(hex & 0xFF) {} | ||||
|   FMT_CONSTEXPR rgb(color hex) | ||||
|       : r((uint32_t(hex) >> 16) & 0xFF), | ||||
|         g((uint32_t(hex) >> 8) & 0xFF), | ||||
|         b(uint32_t(hex) & 0xFF) {} | ||||
|   uint8_t r; | ||||
|   uint8_t g; | ||||
|   uint8_t b; | ||||
| }; | ||||
| 
 | ||||
| FMT_BEGIN_DETAIL_NAMESPACE | ||||
| 
 | ||||
| // color is a struct of either a rgb color or a terminal color.
 | ||||
| struct color_type { | ||||
|   FMT_CONSTEXPR color_type() FMT_NOEXCEPT : is_rgb(), value{} {} | ||||
|   FMT_CONSTEXPR color_type(color rgb_color) FMT_NOEXCEPT : is_rgb(true), | ||||
|                                                            value{} { | ||||
|     value.rgb_color = static_cast<uint32_t>(rgb_color); | ||||
|   } | ||||
|   FMT_CONSTEXPR color_type(rgb rgb_color) FMT_NOEXCEPT : is_rgb(true), value{} { | ||||
|     value.rgb_color = (static_cast<uint32_t>(rgb_color.r) << 16) | | ||||
|                       (static_cast<uint32_t>(rgb_color.g) << 8) | rgb_color.b; | ||||
|   } | ||||
|   FMT_CONSTEXPR color_type(terminal_color term_color) FMT_NOEXCEPT : is_rgb(), | ||||
|                                                                      value{} { | ||||
|     value.term_color = static_cast<uint8_t>(term_color); | ||||
|   } | ||||
|   bool is_rgb; | ||||
|   union color_union { | ||||
|     uint8_t term_color; | ||||
|     uint32_t rgb_color; | ||||
|   } value; | ||||
| }; | ||||
| 
 | ||||
| FMT_END_DETAIL_NAMESPACE | ||||
| 
 | ||||
| /** A text style consisting of foreground and background colors and emphasis. */ | ||||
| class text_style { | ||||
|  public: | ||||
|   FMT_CONSTEXPR text_style(emphasis em = emphasis()) FMT_NOEXCEPT | ||||
|       : set_foreground_color(), | ||||
|         set_background_color(), | ||||
|         ems(em) {} | ||||
| 
 | ||||
|   FMT_CONSTEXPR text_style& operator|=(const text_style& rhs) { | ||||
|     if (!set_foreground_color) { | ||||
|       set_foreground_color = rhs.set_foreground_color; | ||||
|       foreground_color = rhs.foreground_color; | ||||
|     } else if (rhs.set_foreground_color) { | ||||
|       if (!foreground_color.is_rgb || !rhs.foreground_color.is_rgb) | ||||
|         FMT_THROW(format_error("can't OR a terminal color")); | ||||
|       foreground_color.value.rgb_color |= rhs.foreground_color.value.rgb_color; | ||||
|     } | ||||
| 
 | ||||
|     if (!set_background_color) { | ||||
|       set_background_color = rhs.set_background_color; | ||||
|       background_color = rhs.background_color; | ||||
|     } else if (rhs.set_background_color) { | ||||
|       if (!background_color.is_rgb || !rhs.background_color.is_rgb) | ||||
|         FMT_THROW(format_error("can't OR a terminal color")); | ||||
|       background_color.value.rgb_color |= rhs.background_color.value.rgb_color; | ||||
|     } | ||||
| 
 | ||||
|     ems = static_cast<emphasis>(static_cast<uint8_t>(ems) | | ||||
|                                 static_cast<uint8_t>(rhs.ems)); | ||||
|     return *this; | ||||
|   } | ||||
| 
 | ||||
|   friend FMT_CONSTEXPR text_style operator|(text_style lhs, | ||||
|                                             const text_style& rhs) { | ||||
|     return lhs |= rhs; | ||||
|   } | ||||
| 
 | ||||
|   FMT_DEPRECATED_NONMSVC FMT_CONSTEXPR text_style& operator&=( | ||||
|       const text_style& rhs) { | ||||
|     return and_assign(rhs); | ||||
|   } | ||||
| 
 | ||||
|   FMT_DEPRECATED_NONMSVC friend FMT_CONSTEXPR text_style | ||||
|   operator&(text_style lhs, const text_style& rhs) { | ||||
|     return lhs.and_assign(rhs); | ||||
|   } | ||||
| 
 | ||||
|   FMT_CONSTEXPR bool has_foreground() const FMT_NOEXCEPT { | ||||
|     return set_foreground_color; | ||||
|   } | ||||
|   FMT_CONSTEXPR bool has_background() const FMT_NOEXCEPT { | ||||
|     return set_background_color; | ||||
|   } | ||||
|   FMT_CONSTEXPR bool has_emphasis() const FMT_NOEXCEPT { | ||||
|     return static_cast<uint8_t>(ems) != 0; | ||||
|   } | ||||
|   FMT_CONSTEXPR detail::color_type get_foreground() const FMT_NOEXCEPT { | ||||
|     FMT_ASSERT(has_foreground(), "no foreground specified for this style"); | ||||
|     return foreground_color; | ||||
|   } | ||||
|   FMT_CONSTEXPR detail::color_type get_background() const FMT_NOEXCEPT { | ||||
|     FMT_ASSERT(has_background(), "no background specified for this style"); | ||||
|     return background_color; | ||||
|   } | ||||
|   FMT_CONSTEXPR emphasis get_emphasis() const FMT_NOEXCEPT { | ||||
|     FMT_ASSERT(has_emphasis(), "no emphasis specified for this style"); | ||||
|     return ems; | ||||
|   } | ||||
| 
 | ||||
|  private: | ||||
|   FMT_CONSTEXPR text_style(bool is_foreground, | ||||
|                            detail::color_type text_color) FMT_NOEXCEPT | ||||
|       : set_foreground_color(), | ||||
|         set_background_color(), | ||||
|         ems() { | ||||
|     if (is_foreground) { | ||||
|       foreground_color = text_color; | ||||
|       set_foreground_color = true; | ||||
|     } else { | ||||
|       background_color = text_color; | ||||
|       set_background_color = true; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   // DEPRECATED!
 | ||||
|   FMT_CONSTEXPR text_style& and_assign(const text_style& rhs) { | ||||
|     if (!set_foreground_color) { | ||||
|       set_foreground_color = rhs.set_foreground_color; | ||||
|       foreground_color = rhs.foreground_color; | ||||
|     } else if (rhs.set_foreground_color) { | ||||
|       if (!foreground_color.is_rgb || !rhs.foreground_color.is_rgb) | ||||
|         FMT_THROW(format_error("can't AND a terminal color")); | ||||
|       foreground_color.value.rgb_color &= rhs.foreground_color.value.rgb_color; | ||||
|     } | ||||
| 
 | ||||
|     if (!set_background_color) { | ||||
|       set_background_color = rhs.set_background_color; | ||||
|       background_color = rhs.background_color; | ||||
|     } else if (rhs.set_background_color) { | ||||
|       if (!background_color.is_rgb || !rhs.background_color.is_rgb) | ||||
|         FMT_THROW(format_error("can't AND a terminal color")); | ||||
|       background_color.value.rgb_color &= rhs.background_color.value.rgb_color; | ||||
|     } | ||||
| 
 | ||||
|     ems = static_cast<emphasis>(static_cast<uint8_t>(ems) & | ||||
|                                 static_cast<uint8_t>(rhs.ems)); | ||||
|     return *this; | ||||
|   } | ||||
| 
 | ||||
|   friend FMT_CONSTEXPR_DECL text_style fg(detail::color_type foreground) | ||||
|       FMT_NOEXCEPT; | ||||
| 
 | ||||
|   friend FMT_CONSTEXPR_DECL text_style bg(detail::color_type background) | ||||
|       FMT_NOEXCEPT; | ||||
| 
 | ||||
|   detail::color_type foreground_color; | ||||
|   detail::color_type background_color; | ||||
|   bool set_foreground_color; | ||||
|   bool set_background_color; | ||||
|   emphasis ems; | ||||
| }; | ||||
| 
 | ||||
| /** Creates a text style from the foreground (text) color. */ | ||||
| FMT_CONSTEXPR inline text_style fg(detail::color_type foreground) FMT_NOEXCEPT { | ||||
|   return text_style(true, foreground); | ||||
| } | ||||
| 
 | ||||
| /** Creates a text style from the background color. */ | ||||
| FMT_CONSTEXPR inline text_style bg(detail::color_type background) FMT_NOEXCEPT { | ||||
|   return text_style(false, background); | ||||
| } | ||||
| 
 | ||||
| FMT_CONSTEXPR inline text_style operator|(emphasis lhs, | ||||
|                                           emphasis rhs) FMT_NOEXCEPT { | ||||
|   return text_style(lhs) | rhs; | ||||
| } | ||||
| 
 | ||||
| FMT_BEGIN_DETAIL_NAMESPACE | ||||
| 
 | ||||
| template <typename Char> struct ansi_color_escape { | ||||
|   FMT_CONSTEXPR ansi_color_escape(detail::color_type text_color, | ||||
|                                   const char* esc) FMT_NOEXCEPT { | ||||
|     // If we have a terminal color, we need to output another escape code
 | ||||
|     // sequence.
 | ||||
|     if (!text_color.is_rgb) { | ||||
|       bool is_background = esc == string_view("\x1b[48;2;"); | ||||
|       uint32_t value = text_color.value.term_color; | ||||
|       // Background ASCII codes are the same as the foreground ones but with
 | ||||
|       // 10 more.
 | ||||
|       if (is_background) value += 10u; | ||||
| 
 | ||||
|       size_t index = 0; | ||||
|       buffer[index++] = static_cast<Char>('\x1b'); | ||||
|       buffer[index++] = static_cast<Char>('['); | ||||
| 
 | ||||
|       if (value >= 100u) { | ||||
|         buffer[index++] = static_cast<Char>('1'); | ||||
|         value %= 100u; | ||||
|       } | ||||
|       buffer[index++] = static_cast<Char>('0' + value / 10u); | ||||
|       buffer[index++] = static_cast<Char>('0' + value % 10u); | ||||
| 
 | ||||
|       buffer[index++] = static_cast<Char>('m'); | ||||
|       buffer[index++] = static_cast<Char>('\0'); | ||||
|       return; | ||||
|     } | ||||
| 
 | ||||
|     for (int i = 0; i < 7; i++) { | ||||
|       buffer[i] = static_cast<Char>(esc[i]); | ||||
|     } | ||||
|     rgb color(text_color.value.rgb_color); | ||||
|     to_esc(color.r, buffer + 7, ';'); | ||||
|     to_esc(color.g, buffer + 11, ';'); | ||||
|     to_esc(color.b, buffer + 15, 'm'); | ||||
|     buffer[19] = static_cast<Char>(0); | ||||
|   } | ||||
|   FMT_CONSTEXPR ansi_color_escape(emphasis em) FMT_NOEXCEPT { | ||||
|     uint8_t em_codes[num_emphases] = {}; | ||||
|     if (has_emphasis(em, emphasis::bold)) em_codes[0] = 1; | ||||
|     if (has_emphasis(em, emphasis::faint)) em_codes[1] = 2; | ||||
|     if (has_emphasis(em, emphasis::italic)) em_codes[2] = 3; | ||||
|     if (has_emphasis(em, emphasis::underline)) em_codes[3] = 4; | ||||
|     if (has_emphasis(em, emphasis::blink)) em_codes[4] = 5; | ||||
|     if (has_emphasis(em, emphasis::reverse)) em_codes[5] = 7; | ||||
|     if (has_emphasis(em, emphasis::conceal)) em_codes[6] = 8; | ||||
|     if (has_emphasis(em, emphasis::strikethrough)) em_codes[7] = 9; | ||||
| 
 | ||||
|     size_t index = 0; | ||||
|     for (size_t i = 0; i < num_emphases; ++i) { | ||||
|       if (!em_codes[i]) continue; | ||||
|       buffer[index++] = static_cast<Char>('\x1b'); | ||||
|       buffer[index++] = static_cast<Char>('['); | ||||
|       buffer[index++] = static_cast<Char>('0' + em_codes[i]); | ||||
|       buffer[index++] = static_cast<Char>('m'); | ||||
|     } | ||||
|     buffer[index++] = static_cast<Char>(0); | ||||
|   } | ||||
|   FMT_CONSTEXPR operator const Char*() const FMT_NOEXCEPT { return buffer; } | ||||
| 
 | ||||
|   FMT_CONSTEXPR const Char* begin() const FMT_NOEXCEPT { return buffer; } | ||||
|   FMT_CONSTEXPR_CHAR_TRAITS const Char* end() const FMT_NOEXCEPT { | ||||
|     return buffer + std::char_traits<Char>::length(buffer); | ||||
|   } | ||||
| 
 | ||||
|  private: | ||||
|   static constexpr size_t num_emphases = 8; | ||||
|   Char buffer[7u + 3u * num_emphases + 1u]; | ||||
| 
 | ||||
|   static FMT_CONSTEXPR void to_esc(uint8_t c, Char* out, | ||||
|                                    char delimiter) FMT_NOEXCEPT { | ||||
|     out[0] = static_cast<Char>('0' + c / 100); | ||||
|     out[1] = static_cast<Char>('0' + c / 10 % 10); | ||||
|     out[2] = static_cast<Char>('0' + c % 10); | ||||
|     out[3] = static_cast<Char>(delimiter); | ||||
|   } | ||||
|   static FMT_CONSTEXPR bool has_emphasis(emphasis em, | ||||
|                                          emphasis mask) FMT_NOEXCEPT { | ||||
|     return static_cast<uint8_t>(em) & static_cast<uint8_t>(mask); | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| template <typename Char> | ||||
| FMT_CONSTEXPR ansi_color_escape<Char> make_foreground_color( | ||||
|     detail::color_type foreground) FMT_NOEXCEPT { | ||||
|   return ansi_color_escape<Char>(foreground, "\x1b[38;2;"); | ||||
| } | ||||
| 
 | ||||
| template <typename Char> | ||||
| FMT_CONSTEXPR ansi_color_escape<Char> make_background_color( | ||||
|     detail::color_type background) FMT_NOEXCEPT { | ||||
|   return ansi_color_escape<Char>(background, "\x1b[48;2;"); | ||||
| } | ||||
| 
 | ||||
| template <typename Char> | ||||
| FMT_CONSTEXPR ansi_color_escape<Char> make_emphasis(emphasis em) FMT_NOEXCEPT { | ||||
|   return ansi_color_escape<Char>(em); | ||||
| } | ||||
| 
 | ||||
| template <typename Char> | ||||
| inline void fputs(const Char* chars, FILE* stream) FMT_NOEXCEPT { | ||||
|   std::fputs(chars, stream); | ||||
| } | ||||
| 
 | ||||
| template <> | ||||
| inline void fputs<wchar_t>(const wchar_t* chars, FILE* stream) FMT_NOEXCEPT { | ||||
|   std::fputws(chars, stream); | ||||
| } | ||||
| 
 | ||||
| template <typename Char> inline void reset_color(FILE* stream) FMT_NOEXCEPT { | ||||
|   fputs("\x1b[0m", stream); | ||||
| } | ||||
| 
 | ||||
| template <> inline void reset_color<wchar_t>(FILE* stream) FMT_NOEXCEPT { | ||||
|   fputs(L"\x1b[0m", stream); | ||||
| } | ||||
| 
 | ||||
| template <typename Char> | ||||
| inline void reset_color(buffer<Char>& buffer) FMT_NOEXCEPT { | ||||
|   auto reset_color = string_view("\x1b[0m"); | ||||
|   buffer.append(reset_color.begin(), reset_color.end()); | ||||
| } | ||||
| 
 | ||||
| template <typename Char> | ||||
| void vformat_to(buffer<Char>& buf, const text_style& ts, | ||||
|                 basic_string_view<Char> format_str, | ||||
|                 basic_format_args<buffer_context<type_identity_t<Char>>> args) { | ||||
|   bool has_style = false; | ||||
|   if (ts.has_emphasis()) { | ||||
|     has_style = true; | ||||
|     auto emphasis = detail::make_emphasis<Char>(ts.get_emphasis()); | ||||
|     buf.append(emphasis.begin(), emphasis.end()); | ||||
|   } | ||||
|   if (ts.has_foreground()) { | ||||
|     has_style = true; | ||||
|     auto foreground = detail::make_foreground_color<Char>(ts.get_foreground()); | ||||
|     buf.append(foreground.begin(), foreground.end()); | ||||
|   } | ||||
|   if (ts.has_background()) { | ||||
|     has_style = true; | ||||
|     auto background = detail::make_background_color<Char>(ts.get_background()); | ||||
|     buf.append(background.begin(), background.end()); | ||||
|   } | ||||
|   detail::vformat_to(buf, format_str, args, {}); | ||||
|   if (has_style) detail::reset_color<Char>(buf); | ||||
| } | ||||
| 
 | ||||
| FMT_END_DETAIL_NAMESPACE | ||||
| 
 | ||||
| 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<type_identity_t<Char>>> args) { | ||||
|   basic_memory_buffer<Char> buf; | ||||
|   detail::vformat_to(buf, ts, to_string_view(format), args); | ||||
|   buf.push_back(Char(0)); | ||||
|   detail::fputs(buf.data(), f); | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|   \rst | ||||
|   Formats a string and prints it to the specified file stream using ANSI | ||||
|   escape sequences to specify text formatting. | ||||
| 
 | ||||
|   **Example**:: | ||||
| 
 | ||||
|     fmt::print(fmt::emphasis::bold | fg(fmt::color::red), | ||||
|                "Elapsed time: {0:.2f} seconds", 1.23); | ||||
|   \endrst | ||||
|  */ | ||||
| template <typename S, typename... Args, | ||||
|           FMT_ENABLE_IF(detail::is_string<S>::value)> | ||||
| void print(std::FILE* f, const text_style& ts, const S& format_str, | ||||
|            const Args&... args) { | ||||
|   vprint(f, ts, format_str, | ||||
|          fmt::make_args_checked<Args...>(format_str, args...)); | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|   \rst | ||||
|   Formats a string and prints it to stdout using ANSI escape sequences to | ||||
|   specify text formatting. | ||||
| 
 | ||||
|   **Example**:: | ||||
| 
 | ||||
|     fmt::print(fmt::emphasis::bold | fg(fmt::color::red), | ||||
|                "Elapsed time: {0:.2f} seconds", 1.23); | ||||
|   \endrst | ||||
|  */ | ||||
| template <typename S, typename... Args, | ||||
|           FMT_ENABLE_IF(detail::is_string<S>::value)> | ||||
| void print(const text_style& ts, const S& format_str, const Args&... args) { | ||||
|   return print(stdout, ts, format_str, args...); | ||||
| } | ||||
| 
 | ||||
| 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<type_identity_t<Char>>> args) { | ||||
|   basic_memory_buffer<Char> buf; | ||||
|   detail::vformat_to(buf, ts, to_string_view(format_str), args); | ||||
|   return fmt::to_string(buf); | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|   \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 fmt::vformat(ts, to_string_view(format_str), | ||||
|                       fmt::make_args_checked<Args...>(format_str, args...)); | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|   Formats a string with the given text_style and writes the output to ``out``. | ||||
|  */ | ||||
| template <typename OutputIt, typename Char, | ||||
|           FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value)> | ||||
| OutputIt vformat_to( | ||||
|     OutputIt out, const text_style& ts, basic_string_view<Char> format_str, | ||||
|     basic_format_args<buffer_context<type_identity_t<Char>>> args) { | ||||
|   auto&& buf = detail::get_buffer<Char>(out); | ||||
|   detail::vformat_to(buf, ts, format_str, args); | ||||
|   return detail::get_iterator(buf); | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|   \rst | ||||
|   Formats arguments with the given text_style, writes the result to the output | ||||
|   iterator ``out`` and returns the iterator past the end of the output range. | ||||
| 
 | ||||
|   **Example**:: | ||||
| 
 | ||||
|     std::vector<char> out; | ||||
|     fmt::format_to(std::back_inserter(out), | ||||
|                    fmt::emphasis::bold | fg(fmt::color::red), "{}", 42); | ||||
|   \endrst | ||||
| */ | ||||
| template <typename OutputIt, typename S, typename... Args, | ||||
|           bool enable = detail::is_output_iterator<OutputIt, char_t<S>>::value&& | ||||
|               detail::is_string<S>::value> | ||||
| inline auto format_to(OutputIt out, const text_style& ts, const S& format_str, | ||||
|                       Args&&... args) -> | ||||
|     typename std::enable_if<enable, OutputIt>::type { | ||||
|   return vformat_to(out, ts, to_string_view(format_str), | ||||
|                     fmt::make_args_checked<Args...>(format_str, args...)); | ||||
| } | ||||
| 
 | ||||
| FMT_MODULE_EXPORT_END | ||||
| FMT_END_NAMESPACE | ||||
| 
 | ||||
| #endif  // FMT_COLOR_H_
 | ||||
|  | @ -1,642 +0,0 @@ | |||
| // 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 "format.h" | ||||
| 
 | ||||
| FMT_BEGIN_NAMESPACE | ||||
| namespace detail { | ||||
| 
 | ||||
| // An output iterator that counts the number of objects written to it and
 | ||||
| // discards them.
 | ||||
| class counting_iterator { | ||||
|  private: | ||||
|   size_t count_; | ||||
| 
 | ||||
|  public: | ||||
|   using iterator_category = std::output_iterator_tag; | ||||
|   using difference_type = std::ptrdiff_t; | ||||
|   using pointer = void; | ||||
|   using reference = void; | ||||
|   using _Unchecked_type = counting_iterator;  // Mark iterator as checked.
 | ||||
| 
 | ||||
|   struct value_type { | ||||
|     template <typename T> void operator=(const T&) {} | ||||
|   }; | ||||
| 
 | ||||
|   counting_iterator() : count_(0) {} | ||||
| 
 | ||||
|   size_t count() const { return count_; } | ||||
| 
 | ||||
|   counting_iterator& operator++() { | ||||
|     ++count_; | ||||
|     return *this; | ||||
|   } | ||||
|   counting_iterator operator++(int) { | ||||
|     auto it = *this; | ||||
|     ++*this; | ||||
|     return it; | ||||
|   } | ||||
| 
 | ||||
|   friend counting_iterator operator+(counting_iterator it, difference_type n) { | ||||
|     it.count_ += static_cast<size_t>(n); | ||||
|     return it; | ||||
|   } | ||||
| 
 | ||||
|   value_type operator*() const { return {}; } | ||||
| }; | ||||
| 
 | ||||
| template <typename Char, typename InputIt> | ||||
| inline counting_iterator copy_str(InputIt begin, InputIt end, | ||||
|                                   counting_iterator it) { | ||||
|   return it + (end - begin); | ||||
| } | ||||
| 
 | ||||
| template <typename OutputIt> class truncating_iterator_base { | ||||
|  protected: | ||||
|   OutputIt out_; | ||||
|   size_t limit_; | ||||
|   size_t count_ = 0; | ||||
| 
 | ||||
|   truncating_iterator_base() : out_(), limit_(0) {} | ||||
| 
 | ||||
|   truncating_iterator_base(OutputIt out, size_t limit) | ||||
|       : out_(out), limit_(limit) {} | ||||
| 
 | ||||
|  public: | ||||
|   using iterator_category = std::output_iterator_tag; | ||||
|   using value_type = typename std::iterator_traits<OutputIt>::value_type; | ||||
|   using difference_type = std::ptrdiff_t; | ||||
|   using pointer = void; | ||||
|   using reference = void; | ||||
|   using _Unchecked_type = | ||||
|       truncating_iterator_base;  // Mark iterator as checked.
 | ||||
| 
 | ||||
|   OutputIt base() const { return out_; } | ||||
|   size_t count() const { return count_; } | ||||
| }; | ||||
| 
 | ||||
| // An output iterator that truncates the output and counts the number of objects
 | ||||
| // written to it.
 | ||||
| template <typename OutputIt, | ||||
|           typename Enable = typename std::is_void< | ||||
|               typename std::iterator_traits<OutputIt>::value_type>::type> | ||||
| class truncating_iterator; | ||||
| 
 | ||||
| template <typename OutputIt> | ||||
| class truncating_iterator<OutputIt, std::false_type> | ||||
|     : public truncating_iterator_base<OutputIt> { | ||||
|   mutable typename truncating_iterator_base<OutputIt>::value_type blackhole_; | ||||
| 
 | ||||
|  public: | ||||
|   using value_type = typename truncating_iterator_base<OutputIt>::value_type; | ||||
| 
 | ||||
|   truncating_iterator() = default; | ||||
| 
 | ||||
|   truncating_iterator(OutputIt out, size_t limit) | ||||
|       : truncating_iterator_base<OutputIt>(out, limit) {} | ||||
| 
 | ||||
|   truncating_iterator& operator++() { | ||||
|     if (this->count_++ < this->limit_) ++this->out_; | ||||
|     return *this; | ||||
|   } | ||||
| 
 | ||||
|   truncating_iterator operator++(int) { | ||||
|     auto it = *this; | ||||
|     ++*this; | ||||
|     return it; | ||||
|   } | ||||
| 
 | ||||
|   value_type& operator*() const { | ||||
|     return this->count_ < this->limit_ ? *this->out_ : blackhole_; | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| template <typename OutputIt> | ||||
| class truncating_iterator<OutputIt, std::true_type> | ||||
|     : public truncating_iterator_base<OutputIt> { | ||||
|  public: | ||||
|   truncating_iterator() = default; | ||||
| 
 | ||||
|   truncating_iterator(OutputIt out, size_t limit) | ||||
|       : truncating_iterator_base<OutputIt>(out, limit) {} | ||||
| 
 | ||||
|   template <typename T> truncating_iterator& operator=(T val) { | ||||
|     if (this->count_++ < this->limit_) *this->out_++ = val; | ||||
|     return *this; | ||||
|   } | ||||
| 
 | ||||
|   truncating_iterator& operator++() { return *this; } | ||||
|   truncating_iterator& operator++(int) { return *this; } | ||||
|   truncating_iterator& operator*() { return *this; } | ||||
| }; | ||||
| 
 | ||||
| // A compile-time string which is compiled into fast formatting code.
 | ||||
| class compiled_string {}; | ||||
| 
 | ||||
| template <typename S> | ||||
| struct is_compiled_string : std::is_base_of<compiled_string, S> {}; | ||||
| 
 | ||||
| /**
 | ||||
|   \rst | ||||
|   Converts a string literal *s* into a format string that will be parsed at | ||||
|   compile time and converted into efficient formatting code. Requires C++17 | ||||
|   ``constexpr if`` compiler support. | ||||
| 
 | ||||
|   **Example**:: | ||||
| 
 | ||||
|     // Converts 42 into std::string using the most efficient method and no
 | ||||
|     // runtime format string processing.
 | ||||
|     std::string s = fmt::format(FMT_COMPILE("{}"), 42); | ||||
|   \endrst | ||||
|  */ | ||||
| #if defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction) | ||||
| #  define FMT_COMPILE(s) \ | ||||
|     FMT_STRING_IMPL(s, fmt::detail::compiled_string, explicit) | ||||
| #else | ||||
| #  define FMT_COMPILE(s) FMT_STRING(s) | ||||
| #endif | ||||
| 
 | ||||
| #if FMT_USE_NONTYPE_TEMPLATE_PARAMETERS | ||||
| template <typename Char, size_t N, | ||||
|           fmt::detail_exported::fixed_string<Char, N> Str> | ||||
| struct udl_compiled_string : compiled_string { | ||||
|   using char_type = Char; | ||||
|   constexpr operator basic_string_view<char_type>() const { | ||||
|     return {Str.data, N - 1}; | ||||
|   } | ||||
| }; | ||||
| #endif | ||||
| 
 | ||||
| template <typename T, typename... Tail> | ||||
| const T& first(const T& value, const Tail&...) { | ||||
|   return value; | ||||
| } | ||||
| 
 | ||||
| #if defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction) | ||||
| template <typename... Args> struct type_list {}; | ||||
| 
 | ||||
| // Returns a reference to the argument at index N from [first, rest...].
 | ||||
| template <int N, typename T, typename... Args> | ||||
| constexpr const auto& get([[maybe_unused]] const T& first, | ||||
|                           [[maybe_unused]] const Args&... rest) { | ||||
|   static_assert(N < 1 + sizeof...(Args), "index is out of bounds"); | ||||
|   if constexpr (N == 0) | ||||
|     return first; | ||||
|   else | ||||
|     return detail::get<N - 1>(rest...); | ||||
| } | ||||
| 
 | ||||
| template <typename Char, typename... Args> | ||||
| constexpr int get_arg_index_by_name(basic_string_view<Char> name, | ||||
|                                     type_list<Args...>) { | ||||
|   return get_arg_index_by_name<Args...>(name); | ||||
| } | ||||
| 
 | ||||
| template <int N, typename> struct get_type_impl; | ||||
| 
 | ||||
| template <int N, typename... Args> struct get_type_impl<N, type_list<Args...>> { | ||||
|   using type = | ||||
|       remove_cvref_t<decltype(detail::get<N>(std::declval<Args>()...))>; | ||||
| }; | ||||
| 
 | ||||
| template <int N, typename T> | ||||
| using get_type = typename get_type_impl<N, T>::type; | ||||
| 
 | ||||
| template <typename T> struct is_compiled_format : std::false_type {}; | ||||
| 
 | ||||
| template <typename Char> struct text { | ||||
|   basic_string_view<Char> data; | ||||
|   using char_type = Char; | ||||
| 
 | ||||
|   template <typename OutputIt, typename... Args> | ||||
|   constexpr OutputIt format(OutputIt out, const Args&...) const { | ||||
|     return write<Char>(out, data); | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| template <typename Char> | ||||
| struct is_compiled_format<text<Char>> : std::true_type {}; | ||||
| 
 | ||||
| template <typename Char> | ||||
| constexpr text<Char> make_text(basic_string_view<Char> s, size_t pos, | ||||
|                                size_t size) { | ||||
|   return {{&s[pos], size}}; | ||||
| } | ||||
| 
 | ||||
| template <typename Char> struct code_unit { | ||||
|   Char value; | ||||
|   using char_type = Char; | ||||
| 
 | ||||
|   template <typename OutputIt, typename... Args> | ||||
|   constexpr OutputIt format(OutputIt out, const Args&...) const { | ||||
|     return write<Char>(out, value); | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| // This ensures that the argument type is convertible to `const T&`.
 | ||||
| template <typename T, int N, typename... Args> | ||||
| constexpr const T& get_arg_checked(const Args&... args) { | ||||
|   const auto& arg = detail::get<N>(args...); | ||||
|   if constexpr (detail::is_named_arg<remove_cvref_t<decltype(arg)>>()) { | ||||
|     return arg.value; | ||||
|   } else { | ||||
|     return arg; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| template <typename Char> | ||||
| struct is_compiled_format<code_unit<Char>> : std::true_type {}; | ||||
| 
 | ||||
| // A replacement field that refers to argument N.
 | ||||
| template <typename Char, typename T, int N> struct field { | ||||
|   using char_type = Char; | ||||
| 
 | ||||
|   template <typename OutputIt, typename... Args> | ||||
|   constexpr OutputIt format(OutputIt out, const Args&... args) const { | ||||
|     return write<Char>(out, get_arg_checked<T, N>(args...)); | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| template <typename Char, typename T, int N> | ||||
| struct is_compiled_format<field<Char, T, N>> : std::true_type {}; | ||||
| 
 | ||||
| // A replacement field that refers to argument with name.
 | ||||
| template <typename Char> struct runtime_named_field { | ||||
|   using char_type = Char; | ||||
|   basic_string_view<Char> name; | ||||
| 
 | ||||
|   template <typename OutputIt, typename T> | ||||
|   constexpr static bool try_format_argument( | ||||
|       OutputIt& out, | ||||
|       // [[maybe_unused]] due to unused-but-set-parameter warning in GCC 7,8,9
 | ||||
|       [[maybe_unused]] basic_string_view<Char> arg_name, const T& arg) { | ||||
|     if constexpr (is_named_arg<typename std::remove_cv<T>::type>::value) { | ||||
|       if (arg_name == arg.name) { | ||||
|         out = write<Char>(out, arg.value); | ||||
|         return true; | ||||
|       } | ||||
|     } | ||||
|     return false; | ||||
|   } | ||||
| 
 | ||||
|   template <typename OutputIt, typename... Args> | ||||
|   constexpr OutputIt format(OutputIt out, const Args&... args) const { | ||||
|     bool found = (try_format_argument(out, name, args) || ...); | ||||
|     if (!found) { | ||||
|       FMT_THROW(format_error("argument with specified name is not found")); | ||||
|     } | ||||
|     return out; | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| template <typename Char> | ||||
| struct is_compiled_format<runtime_named_field<Char>> : std::true_type {}; | ||||
| 
 | ||||
| // A replacement field that refers to argument N and has format specifiers.
 | ||||
| template <typename Char, typename T, int N> struct spec_field { | ||||
|   using char_type = Char; | ||||
|   formatter<T, Char> fmt; | ||||
| 
 | ||||
|   template <typename OutputIt, typename... Args> | ||||
|   constexpr FMT_INLINE OutputIt format(OutputIt out, | ||||
|                                        const Args&... args) const { | ||||
|     const auto& vargs = | ||||
|         fmt::make_format_args<basic_format_context<OutputIt, Char>>(args...); | ||||
|     basic_format_context<OutputIt, Char> ctx(out, vargs); | ||||
|     return fmt.format(get_arg_checked<T, N>(args...), ctx); | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| template <typename Char, typename T, int N> | ||||
| struct is_compiled_format<spec_field<Char, T, N>> : std::true_type {}; | ||||
| 
 | ||||
| template <typename L, typename R> struct concat { | ||||
|   L lhs; | ||||
|   R rhs; | ||||
|   using char_type = typename L::char_type; | ||||
| 
 | ||||
|   template <typename OutputIt, typename... Args> | ||||
|   constexpr OutputIt format(OutputIt out, const Args&... args) const { | ||||
|     out = lhs.format(out, args...); | ||||
|     return rhs.format(out, args...); | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| template <typename L, typename R> | ||||
| struct is_compiled_format<concat<L, R>> : std::true_type {}; | ||||
| 
 | ||||
| template <typename L, typename R> | ||||
| constexpr concat<L, R> make_concat(L lhs, R rhs) { | ||||
|   return {lhs, rhs}; | ||||
| } | ||||
| 
 | ||||
| struct unknown_format {}; | ||||
| 
 | ||||
| template <typename Char> | ||||
| constexpr size_t parse_text(basic_string_view<Char> str, size_t pos) { | ||||
|   for (size_t size = str.size(); pos != size; ++pos) { | ||||
|     if (str[pos] == '{' || str[pos] == '}') break; | ||||
|   } | ||||
|   return pos; | ||||
| } | ||||
| 
 | ||||
| template <typename Args, size_t POS, int ID, typename S> | ||||
| constexpr auto compile_format_string(S format_str); | ||||
| 
 | ||||
| template <typename Args, size_t POS, int ID, typename T, typename S> | ||||
| constexpr auto parse_tail(T head, S format_str) { | ||||
|   if constexpr (POS != | ||||
|                 basic_string_view<typename S::char_type>(format_str).size()) { | ||||
|     constexpr auto tail = compile_format_string<Args, POS, ID>(format_str); | ||||
|     if constexpr (std::is_same<remove_cvref_t<decltype(tail)>, | ||||
|                                unknown_format>()) | ||||
|       return tail; | ||||
|     else | ||||
|       return make_concat(head, tail); | ||||
|   } else { | ||||
|     return head; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| template <typename T, typename Char> struct parse_specs_result { | ||||
|   formatter<T, Char> fmt; | ||||
|   size_t end; | ||||
|   int next_arg_id; | ||||
| }; | ||||
| 
 | ||||
| constexpr int manual_indexing_id = -1; | ||||
| 
 | ||||
| template <typename T, typename Char> | ||||
| constexpr parse_specs_result<T, Char> parse_specs(basic_string_view<Char> str, | ||||
|                                                   size_t pos, int next_arg_id) { | ||||
|   str.remove_prefix(pos); | ||||
|   auto ctx = basic_format_parse_context<Char>(str, {}, next_arg_id); | ||||
|   auto f = formatter<T, Char>(); | ||||
|   auto end = f.parse(ctx); | ||||
|   return {f, pos + fmt::detail::to_unsigned(end - str.data()) + 1, | ||||
|           next_arg_id == 0 ? manual_indexing_id : ctx.next_arg_id()}; | ||||
| } | ||||
| 
 | ||||
| template <typename Char> struct arg_id_handler { | ||||
|   arg_ref<Char> arg_id; | ||||
| 
 | ||||
|   constexpr int operator()() { | ||||
|     FMT_ASSERT(false, "handler cannot be used with automatic indexing"); | ||||
|     return 0; | ||||
|   } | ||||
|   constexpr int operator()(int id) { | ||||
|     arg_id = arg_ref<Char>(id); | ||||
|     return 0; | ||||
|   } | ||||
|   constexpr int operator()(basic_string_view<Char> id) { | ||||
|     arg_id = arg_ref<Char>(id); | ||||
|     return 0; | ||||
|   } | ||||
| 
 | ||||
|   constexpr void on_error(const char* message) { | ||||
|     FMT_THROW(format_error(message)); | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| template <typename Char> struct parse_arg_id_result { | ||||
|   arg_ref<Char> arg_id; | ||||
|   const Char* arg_id_end; | ||||
| }; | ||||
| 
 | ||||
| template <int ID, typename Char> | ||||
| constexpr auto parse_arg_id(const Char* begin, const Char* end) { | ||||
|   auto handler = arg_id_handler<Char>{arg_ref<Char>{}}; | ||||
|   auto arg_id_end = parse_arg_id(begin, end, handler); | ||||
|   return parse_arg_id_result<Char>{handler.arg_id, arg_id_end}; | ||||
| } | ||||
| 
 | ||||
| template <typename T, typename Enable = void> struct field_type { | ||||
|   using type = remove_cvref_t<T>; | ||||
| }; | ||||
| 
 | ||||
| template <typename T> | ||||
| struct field_type<T, enable_if_t<detail::is_named_arg<T>::value>> { | ||||
|   using type = remove_cvref_t<decltype(T::value)>; | ||||
| }; | ||||
| 
 | ||||
| template <typename T, typename Args, size_t END_POS, int ARG_INDEX, int NEXT_ID, | ||||
|           typename S> | ||||
| constexpr auto parse_replacement_field_then_tail(S format_str) { | ||||
|   using char_type = typename S::char_type; | ||||
|   constexpr auto str = basic_string_view<char_type>(format_str); | ||||
|   constexpr char_type c = END_POS != str.size() ? str[END_POS] : char_type(); | ||||
|   if constexpr (c == '}') { | ||||
|     return parse_tail<Args, END_POS + 1, NEXT_ID>( | ||||
|         field<char_type, typename field_type<T>::type, ARG_INDEX>(), | ||||
|         format_str); | ||||
|   } else if constexpr (c == ':') { | ||||
|     constexpr auto result = parse_specs<typename field_type<T>::type>( | ||||
|         str, END_POS + 1, NEXT_ID == manual_indexing_id ? 0 : NEXT_ID); | ||||
|     return parse_tail<Args, result.end, result.next_arg_id>( | ||||
|         spec_field<char_type, typename field_type<T>::type, ARG_INDEX>{ | ||||
|             result.fmt}, | ||||
|         format_str); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| // Compiles a non-empty format string and returns the compiled representation
 | ||||
| // or unknown_format() on unrecognized input.
 | ||||
| template <typename Args, size_t POS, int ID, typename S> | ||||
| constexpr auto compile_format_string(S format_str) { | ||||
|   using char_type = typename S::char_type; | ||||
|   constexpr auto str = basic_string_view<char_type>(format_str); | ||||
|   if constexpr (str[POS] == '{') { | ||||
|     if constexpr (POS + 1 == str.size()) | ||||
|       FMT_THROW(format_error("unmatched '{' in format string")); | ||||
|     if constexpr (str[POS + 1] == '{') { | ||||
|       return parse_tail<Args, POS + 2, ID>(make_text(str, POS, 1), format_str); | ||||
|     } else if constexpr (str[POS + 1] == '}' || str[POS + 1] == ':') { | ||||
|       static_assert(ID != manual_indexing_id, | ||||
|                     "cannot switch from manual to automatic argument indexing"); | ||||
|       constexpr auto next_id = | ||||
|           ID != manual_indexing_id ? ID + 1 : manual_indexing_id; | ||||
|       return parse_replacement_field_then_tail<get_type<ID, Args>, Args, | ||||
|                                                POS + 1, ID, next_id>( | ||||
|           format_str); | ||||
|     } else { | ||||
|       constexpr auto arg_id_result = | ||||
|           parse_arg_id<ID>(str.data() + POS + 1, str.data() + str.size()); | ||||
|       constexpr auto arg_id_end_pos = arg_id_result.arg_id_end - str.data(); | ||||
|       constexpr char_type c = | ||||
|           arg_id_end_pos != str.size() ? str[arg_id_end_pos] : char_type(); | ||||
|       static_assert(c == '}' || c == ':', "missing '}' in format string"); | ||||
|       if constexpr (arg_id_result.arg_id.kind == arg_id_kind::index) { | ||||
|         static_assert( | ||||
|             ID == manual_indexing_id || ID == 0, | ||||
|             "cannot switch from automatic to manual argument indexing"); | ||||
|         constexpr auto arg_index = arg_id_result.arg_id.val.index; | ||||
|         return parse_replacement_field_then_tail<get_type<arg_index, Args>, | ||||
|                                                  Args, arg_id_end_pos, | ||||
|                                                  arg_index, manual_indexing_id>( | ||||
|             format_str); | ||||
|       } else if constexpr (arg_id_result.arg_id.kind == arg_id_kind::name) { | ||||
|         constexpr auto arg_index = | ||||
|             get_arg_index_by_name(arg_id_result.arg_id.val.name, Args{}); | ||||
|         if constexpr (arg_index != invalid_arg_index) { | ||||
|           constexpr auto next_id = | ||||
|               ID != manual_indexing_id ? ID + 1 : manual_indexing_id; | ||||
|           return parse_replacement_field_then_tail< | ||||
|               decltype(get_type<arg_index, Args>::value), Args, arg_id_end_pos, | ||||
|               arg_index, next_id>(format_str); | ||||
|         } else { | ||||
|           if constexpr (c == '}') { | ||||
|             return parse_tail<Args, arg_id_end_pos + 1, ID>( | ||||
|                 runtime_named_field<char_type>{arg_id_result.arg_id.val.name}, | ||||
|                 format_str); | ||||
|           } else if constexpr (c == ':') { | ||||
|             return unknown_format();  // no type info for specs parsing
 | ||||
|           } | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   } else if constexpr (str[POS] == '}') { | ||||
|     if constexpr (POS + 1 == str.size()) | ||||
|       FMT_THROW(format_error("unmatched '}' in format string")); | ||||
|     return parse_tail<Args, POS + 2, ID>(make_text(str, POS, 1), format_str); | ||||
|   } else { | ||||
|     constexpr auto end = parse_text(str, POS + 1); | ||||
|     if constexpr (end - POS > 1) { | ||||
|       return parse_tail<Args, end, ID>(make_text(str, POS, end - POS), | ||||
|                                        format_str); | ||||
|     } else { | ||||
|       return parse_tail<Args, end, ID>(code_unit<char_type>{str[POS]}, | ||||
|                                        format_str); | ||||
|     } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| template <typename... Args, typename S, | ||||
|           FMT_ENABLE_IF(detail::is_compiled_string<S>::value)> | ||||
| constexpr auto compile(S format_str) { | ||||
|   constexpr auto str = basic_string_view<typename S::char_type>(format_str); | ||||
|   if constexpr (str.size() == 0) { | ||||
|     return detail::make_text(str, 0, 0); | ||||
|   } else { | ||||
|     constexpr auto result = | ||||
|         detail::compile_format_string<detail::type_list<Args...>, 0, 0>( | ||||
|             format_str); | ||||
|     return result; | ||||
|   } | ||||
| } | ||||
| #endif  // defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction)
 | ||||
| }  // namespace detail
 | ||||
| 
 | ||||
| FMT_MODULE_EXPORT_BEGIN | ||||
| 
 | ||||
| #if defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction) | ||||
| 
 | ||||
| template <typename CompiledFormat, typename... Args, | ||||
|           typename Char = typename CompiledFormat::char_type, | ||||
|           FMT_ENABLE_IF(detail::is_compiled_format<CompiledFormat>::value)> | ||||
| FMT_INLINE std::basic_string<Char> format(const CompiledFormat& cf, | ||||
|                                           const Args&... args) { | ||||
|   auto s = std::basic_string<Char>(); | ||||
|   cf.format(std::back_inserter(s), args...); | ||||
|   return s; | ||||
| } | ||||
| 
 | ||||
| template <typename OutputIt, typename CompiledFormat, typename... Args, | ||||
|           FMT_ENABLE_IF(detail::is_compiled_format<CompiledFormat>::value)> | ||||
| constexpr FMT_INLINE OutputIt format_to(OutputIt out, const CompiledFormat& cf, | ||||
|                                         const Args&... args) { | ||||
|   return cf.format(out, args...); | ||||
| } | ||||
| 
 | ||||
| template <typename S, typename... Args, | ||||
|           FMT_ENABLE_IF(detail::is_compiled_string<S>::value)> | ||||
| FMT_INLINE std::basic_string<typename S::char_type> format(const S&, | ||||
|                                                            Args&&... args) { | ||||
|   if constexpr (std::is_same<typename S::char_type, char>::value) { | ||||
|     constexpr auto str = basic_string_view<typename S::char_type>(S()); | ||||
|     if constexpr (str.size() == 2 && str[0] == '{' && str[1] == '}') { | ||||
|       const auto& first = detail::first(args...); | ||||
|       if constexpr (detail::is_named_arg< | ||||
|                         remove_cvref_t<decltype(first)>>::value) { | ||||
|         return fmt::to_string(first.value); | ||||
|       } else { | ||||
|         return fmt::to_string(first); | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|   constexpr auto compiled = detail::compile<Args...>(S()); | ||||
|   if constexpr (std::is_same<remove_cvref_t<decltype(compiled)>, | ||||
|                              detail::unknown_format>()) { | ||||
|     return format(static_cast<basic_string_view<typename S::char_type>>(S()), | ||||
|                   std::forward<Args>(args)...); | ||||
|   } else { | ||||
|     return format(compiled, std::forward<Args>(args)...); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| template <typename OutputIt, typename S, typename... Args, | ||||
|           FMT_ENABLE_IF(detail::is_compiled_string<S>::value)> | ||||
| FMT_CONSTEXPR OutputIt format_to(OutputIt out, const S&, Args&&... args) { | ||||
|   constexpr auto compiled = detail::compile<Args...>(S()); | ||||
|   if constexpr (std::is_same<remove_cvref_t<decltype(compiled)>, | ||||
|                              detail::unknown_format>()) { | ||||
|     return format_to(out, | ||||
|                      static_cast<basic_string_view<typename S::char_type>>(S()), | ||||
|                      std::forward<Args>(args)...); | ||||
|   } else { | ||||
|     return format_to(out, compiled, std::forward<Args>(args)...); | ||||
|   } | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| template <typename OutputIt, typename S, typename... Args, | ||||
|           FMT_ENABLE_IF(detail::is_compiled_string<S>::value)> | ||||
| format_to_n_result<OutputIt> format_to_n(OutputIt out, size_t n, | ||||
|                                          const S& format_str, Args&&... args) { | ||||
|   auto it = format_to(detail::truncating_iterator<OutputIt>(out, n), format_str, | ||||
|                       std::forward<Args>(args)...); | ||||
|   return {it.base(), it.count()}; | ||||
| } | ||||
| 
 | ||||
| template <typename S, typename... Args, | ||||
|           FMT_ENABLE_IF(detail::is_compiled_string<S>::value)> | ||||
| size_t formatted_size(const S& format_str, const Args&... args) { | ||||
|   return format_to(detail::counting_iterator(), format_str, args...).count(); | ||||
| } | ||||
| 
 | ||||
| template <typename S, typename... Args, | ||||
|           FMT_ENABLE_IF(detail::is_compiled_string<S>::value)> | ||||
| void print(std::FILE* f, const S& format_str, const Args&... args) { | ||||
|   memory_buffer buffer; | ||||
|   format_to(std::back_inserter(buffer), format_str, args...); | ||||
|   detail::print(f, {buffer.data(), buffer.size()}); | ||||
| } | ||||
| 
 | ||||
| template <typename S, typename... Args, | ||||
|           FMT_ENABLE_IF(detail::is_compiled_string<S>::value)> | ||||
| void print(const S& format_str, const Args&... args) { | ||||
|   print(stdout, format_str, args...); | ||||
| } | ||||
| 
 | ||||
| #if FMT_USE_NONTYPE_TEMPLATE_PARAMETERS | ||||
| inline namespace literals { | ||||
| template <detail_exported::fixed_string Str> | ||||
| constexpr detail::udl_compiled_string< | ||||
|     remove_cvref_t<decltype(Str.data[0])>, | ||||
|     sizeof(Str.data) / sizeof(decltype(Str.data[0])), Str> | ||||
| operator""_cf() { | ||||
|   return {}; | ||||
| } | ||||
| }  // namespace literals
 | ||||
| #endif | ||||
| 
 | ||||
| FMT_MODULE_EXPORT_END | ||||
| FMT_END_NAMESPACE | ||||
| 
 | ||||
| #endif  // FMT_COMPILE_H_
 | ||||
							
								
								
									
										3236
									
								
								Dependencies/spdlog/include/spdlog/fmt/bundled/core.h
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										3236
									
								
								Dependencies/spdlog/include/spdlog/fmt/bundled/core.h
									
										
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							|  | @ -1,27 +0,0 @@ | |||
| Copyright (c) 2012 - present, Victor Zverovich | ||||
| 
 | ||||
| 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. | ||||
| 
 | ||||
| --- Optional exception to the license --- | ||||
| 
 | ||||
| As an exception, if, as a result of your compiling your source code, portions | ||||
| of this Software are embedded into a machine-executable object form of such | ||||
| source code, you may redistribute such embedded portions in such object form | ||||
| without including the above copyright and permission notices. | ||||
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										3104
									
								
								Dependencies/spdlog/include/spdlog/fmt/bundled/format.h
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										3104
									
								
								Dependencies/spdlog/include/spdlog/fmt/bundled/format.h
									
										
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							|  | @ -1,2 +0,0 @@ | |||
| #include "xchar.h" | ||||
| #warning fmt/locale.h is deprecated, include fmt/format.h or fmt/xchar.h instead | ||||
							
								
								
									
										527
									
								
								Dependencies/spdlog/include/spdlog/fmt/bundled/os.h
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										527
									
								
								Dependencies/spdlog/include/spdlog/fmt/bundled/os.h
									
										
									
									
										vendored
									
									
								
							|  | @ -1,527 +0,0 @@ | |||
| // Formatting library for C++ - optional OS-specific functionality
 | ||||
| //
 | ||||
| // Copyright (c) 2012 - present, Victor Zverovich
 | ||||
| // All rights reserved.
 | ||||
| //
 | ||||
| // For the license information refer to format.h.
 | ||||
| 
 | ||||
| #ifndef FMT_OS_H_ | ||||
| #define FMT_OS_H_ | ||||
| 
 | ||||
| #include <cerrno> | ||||
| #include <clocale>  // locale_t | ||||
| #include <cstddef> | ||||
| #include <cstdio> | ||||
| #include <cstdlib>       // strtod_l | ||||
| #include <system_error>  // std::system_error | ||||
| 
 | ||||
| #if defined __APPLE__ || defined(__FreeBSD__) | ||||
| #  include <xlocale.h>  // for LC_NUMERIC_MASK on OS X
 | ||||
| #endif | ||||
| 
 | ||||
| #include "format.h" | ||||
| 
 | ||||
| #ifndef FMT_USE_FCNTL | ||||
| // UWP doesn't provide _pipe.
 | ||||
| #  if FMT_HAS_INCLUDE("winapifamily.h") | ||||
| #    include <winapifamily.h> | ||||
| #  endif | ||||
| #  if (FMT_HAS_INCLUDE(<fcntl.h>) || defined(__APPLE__) || \ | ||||
|        defined(__linux__)) &&                              \ | ||||
|       (!defined(WINAPI_FAMILY) ||                          \ | ||||
|        (WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP)) | ||||
| #    include <fcntl.h>  // for O_RDONLY
 | ||||
| #    define FMT_USE_FCNTL 1 | ||||
| #  else | ||||
| #    define FMT_USE_FCNTL 0 | ||||
| #  endif | ||||
| #endif | ||||
| 
 | ||||
| #ifndef FMT_POSIX | ||||
| #  if defined(_WIN32) && !defined(__MINGW32__) | ||||
| // Fix warnings about deprecated symbols.
 | ||||
| #    define FMT_POSIX(call) _##call | ||||
| #  else | ||||
| #    define FMT_POSIX(call) call | ||||
| #  endif | ||||
| #endif | ||||
| 
 | ||||
| // Calls to system functions are wrapped in FMT_SYSTEM for testability.
 | ||||
| #ifdef FMT_SYSTEM | ||||
| #  define FMT_POSIX_CALL(call) FMT_SYSTEM(call) | ||||
| #else | ||||
| #  define FMT_SYSTEM(call) ::call | ||||
| #  ifdef _WIN32 | ||||
| // Fix warnings about deprecated symbols.
 | ||||
| #    define FMT_POSIX_CALL(call) ::_##call | ||||
| #  else | ||||
| #    define FMT_POSIX_CALL(call) ::call | ||||
| #  endif | ||||
| #endif | ||||
| 
 | ||||
| // Retries the expression while it evaluates to error_result and errno
 | ||||
| // equals to EINTR.
 | ||||
| #ifndef _WIN32 | ||||
| #  define FMT_RETRY_VAL(result, expression, error_result) \ | ||||
|     do {                                                  \ | ||||
|       (result) = (expression);                            \ | ||||
|     } while ((result) == (error_result) && errno == EINTR) | ||||
| #else | ||||
| #  define FMT_RETRY_VAL(result, expression, error_result) result = (expression) | ||||
| #endif | ||||
| 
 | ||||
| #define FMT_RETRY(result, expression) FMT_RETRY_VAL(result, expression, -1) | ||||
| 
 | ||||
| FMT_BEGIN_NAMESPACE | ||||
| FMT_MODULE_EXPORT_BEGIN | ||||
| 
 | ||||
| /**
 | ||||
|   \rst | ||||
|   A reference to a null-terminated string. It can be constructed from a C | ||||
|   string or ``std::string``. | ||||
| 
 | ||||
|   You can use one of the following type aliases for common character types: | ||||
| 
 | ||||
|   +---------------+-----------------------------+ | ||||
|   | Type          | Definition                  | | ||||
|   +===============+=============================+ | ||||
|   | cstring_view  | basic_cstring_view<char>    | | ||||
|   +---------------+-----------------------------+ | ||||
|   | wcstring_view | basic_cstring_view<wchar_t> | | ||||
|   +---------------+-----------------------------+ | ||||
| 
 | ||||
|   This class is most useful as a parameter type to allow passing | ||||
|   different types of strings to a function, for example:: | ||||
| 
 | ||||
|     template <typename... Args> | ||||
|     std::string format(cstring_view format_str, const Args & ... args); | ||||
| 
 | ||||
|     format("{}", 42); | ||||
|     format(std::string("{}"), 42); | ||||
|   \endrst | ||||
|  */ | ||||
| template <typename Char> class basic_cstring_view { | ||||
|  private: | ||||
|   const Char* data_; | ||||
| 
 | ||||
|  public: | ||||
|   /** Constructs a string reference object from a C string. */ | ||||
|   basic_cstring_view(const Char* s) : data_(s) {} | ||||
| 
 | ||||
|   /**
 | ||||
|     \rst | ||||
|     Constructs a string reference from an ``std::string`` object. | ||||
|     \endrst | ||||
|    */ | ||||
|   basic_cstring_view(const std::basic_string<Char>& s) : data_(s.c_str()) {} | ||||
| 
 | ||||
|   /** Returns the pointer to a C string. */ | ||||
|   const Char* c_str() const { return data_; } | ||||
| }; | ||||
| 
 | ||||
| using cstring_view = basic_cstring_view<char>; | ||||
| using wcstring_view = basic_cstring_view<wchar_t>; | ||||
| 
 | ||||
| template <typename Char> struct formatter<std::error_code, Char> { | ||||
|   template <typename ParseContext> | ||||
|   FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { | ||||
|     return ctx.begin(); | ||||
|   } | ||||
| 
 | ||||
|   template <typename FormatContext> | ||||
|   FMT_CONSTEXPR auto format(const std::error_code& ec, FormatContext& ctx) const | ||||
|       -> decltype(ctx.out()) { | ||||
|     auto out = ctx.out(); | ||||
|     out = detail::write_bytes(out, ec.category().name(), | ||||
|                               basic_format_specs<Char>()); | ||||
|     out = detail::write<Char>(out, Char(':')); | ||||
|     out = detail::write<Char>(out, ec.value()); | ||||
|     return out; | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| #ifdef _WIN32 | ||||
| FMT_API const std::error_category& system_category() FMT_NOEXCEPT; | ||||
| 
 | ||||
| FMT_BEGIN_DETAIL_NAMESPACE | ||||
| // A converter from UTF-16 to UTF-8.
 | ||||
| // It is only provided for Windows since other systems support UTF-8 natively.
 | ||||
| class utf16_to_utf8 { | ||||
|  private: | ||||
|   memory_buffer buffer_; | ||||
| 
 | ||||
|  public: | ||||
|   utf16_to_utf8() {} | ||||
|   FMT_API explicit utf16_to_utf8(basic_string_view<wchar_t> s); | ||||
|   operator string_view() const { return string_view(&buffer_[0], size()); } | ||||
|   size_t size() const { return buffer_.size() - 1; } | ||||
|   const char* c_str() const { return &buffer_[0]; } | ||||
|   std::string str() const { return std::string(&buffer_[0], size()); } | ||||
| 
 | ||||
|   // Performs conversion returning a system error code instead of
 | ||||
|   // throwing exception on conversion error. This method may still throw
 | ||||
|   // in case of memory allocation error.
 | ||||
|   FMT_API int convert(basic_string_view<wchar_t> s); | ||||
| }; | ||||
| 
 | ||||
| FMT_API void format_windows_error(buffer<char>& out, int error_code, | ||||
|                                   const char* message) FMT_NOEXCEPT; | ||||
| FMT_END_DETAIL_NAMESPACE | ||||
| 
 | ||||
| FMT_API std::system_error vwindows_error(int error_code, string_view format_str, | ||||
|                                          format_args args); | ||||
| 
 | ||||
| /**
 | ||||
|  \rst | ||||
|  Constructs a :class:`std::system_error` object with the description | ||||
|  of the form | ||||
| 
 | ||||
|  .. parsed-literal:: | ||||
|    *<message>*: *<system-message>* | ||||
| 
 | ||||
|  where *<message>* is the formatted message and *<system-message>* is the | ||||
|  system message corresponding to the error code. | ||||
|  *error_code* is a Windows error code as given by ``GetLastError``. | ||||
|  If *error_code* is not a valid error code such as -1, the system message | ||||
|  will look like "error -1". | ||||
| 
 | ||||
|  **Example**:: | ||||
| 
 | ||||
|    // This throws a system_error with the description
 | ||||
|    //   cannot open file 'madeup': The system cannot find the file specified.
 | ||||
|    // or similar (system message may vary).
 | ||||
|    const char *filename = "madeup"; | ||||
|    LPOFSTRUCT of = LPOFSTRUCT(); | ||||
|    HFILE file = OpenFile(filename, &of, OF_READ); | ||||
|    if (file == HFILE_ERROR) { | ||||
|      throw fmt::windows_error(GetLastError(), | ||||
|                               "cannot open file '{}'", filename); | ||||
|    } | ||||
|  \endrst | ||||
| */ | ||||
| template <typename... Args> | ||||
| std::system_error windows_error(int error_code, string_view message, | ||||
|                                 const Args&... args) { | ||||
|   return vwindows_error(error_code, message, fmt::make_format_args(args...)); | ||||
| } | ||||
| 
 | ||||
| // Reports a Windows error without throwing an exception.
 | ||||
| // Can be used to report errors from destructors.
 | ||||
| FMT_API void report_windows_error(int error_code, | ||||
|                                   const char* message) FMT_NOEXCEPT; | ||||
| #else | ||||
| inline const std::error_category& system_category() FMT_NOEXCEPT { | ||||
|   return std::system_category(); | ||||
| } | ||||
| #endif  // _WIN32
 | ||||
| 
 | ||||
| // std::system is not available on some platforms such as iOS (#2248).
 | ||||
| #ifdef __OSX__ | ||||
| template <typename S, typename... Args, typename Char = char_t<S>> | ||||
| void say(const S& format_str, Args&&... args) { | ||||
|   std::system(format("say \"{}\"", format(format_str, args...)).c_str()); | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| // A buffered file.
 | ||||
| class buffered_file { | ||||
|  private: | ||||
|   FILE* file_; | ||||
| 
 | ||||
|   friend class file; | ||||
| 
 | ||||
|   explicit buffered_file(FILE* f) : file_(f) {} | ||||
| 
 | ||||
|  public: | ||||
|   buffered_file(const buffered_file&) = delete; | ||||
|   void operator=(const buffered_file&) = delete; | ||||
| 
 | ||||
|   // Constructs a buffered_file object which doesn't represent any file.
 | ||||
|   buffered_file() FMT_NOEXCEPT : file_(nullptr) {} | ||||
| 
 | ||||
|   // Destroys the object closing the file it represents if any.
 | ||||
|   FMT_API ~buffered_file() FMT_NOEXCEPT; | ||||
| 
 | ||||
|  public: | ||||
|   buffered_file(buffered_file&& other) FMT_NOEXCEPT : file_(other.file_) { | ||||
|     other.file_ = nullptr; | ||||
|   } | ||||
| 
 | ||||
|   buffered_file& operator=(buffered_file&& other) { | ||||
|     close(); | ||||
|     file_ = other.file_; | ||||
|     other.file_ = nullptr; | ||||
|     return *this; | ||||
|   } | ||||
| 
 | ||||
|   // Opens a file.
 | ||||
|   FMT_API buffered_file(cstring_view filename, cstring_view mode); | ||||
| 
 | ||||
|   // Closes the file.
 | ||||
|   FMT_API void close(); | ||||
| 
 | ||||
|   // Returns the pointer to a FILE object representing this file.
 | ||||
|   FILE* get() const FMT_NOEXCEPT { return file_; } | ||||
| 
 | ||||
|   // We place parentheses around fileno to workaround a bug in some versions
 | ||||
|   // of MinGW that define fileno as a macro.
 | ||||
|   FMT_API int(fileno)() const; | ||||
| 
 | ||||
|   void vprint(string_view format_str, format_args args) { | ||||
|     fmt::vprint(file_, format_str, args); | ||||
|   } | ||||
| 
 | ||||
|   template <typename... Args> | ||||
|   inline void print(string_view format_str, const Args&... args) { | ||||
|     vprint(format_str, fmt::make_format_args(args...)); | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| #if FMT_USE_FCNTL | ||||
| // A file. Closed file is represented by a file object with descriptor -1.
 | ||||
| // Methods that are not declared with FMT_NOEXCEPT may throw
 | ||||
| // fmt::system_error in case of failure. Note that some errors such as
 | ||||
| // closing the file multiple times will cause a crash on Windows rather
 | ||||
| // than an exception. You can get standard behavior by overriding the
 | ||||
| // invalid parameter handler with _set_invalid_parameter_handler.
 | ||||
| class file { | ||||
|  private: | ||||
|   int fd_;  // File descriptor.
 | ||||
| 
 | ||||
|   // Constructs a file object with a given descriptor.
 | ||||
|   explicit file(int fd) : fd_(fd) {} | ||||
| 
 | ||||
|  public: | ||||
|   // Possible values for the oflag argument to the constructor.
 | ||||
|   enum { | ||||
|     RDONLY = FMT_POSIX(O_RDONLY),  // Open for reading only.
 | ||||
|     WRONLY = FMT_POSIX(O_WRONLY),  // Open for writing only.
 | ||||
|     RDWR = FMT_POSIX(O_RDWR),      // Open for reading and writing.
 | ||||
|     CREATE = FMT_POSIX(O_CREAT),   // Create if the file doesn't exist.
 | ||||
|     APPEND = FMT_POSIX(O_APPEND),  // Open in append mode.
 | ||||
|     TRUNC = FMT_POSIX(O_TRUNC)     // Truncate the content of the file.
 | ||||
|   }; | ||||
| 
 | ||||
|   // Constructs a file object which doesn't represent any file.
 | ||||
|   file() FMT_NOEXCEPT : fd_(-1) {} | ||||
| 
 | ||||
|   // Opens a file and constructs a file object representing this file.
 | ||||
|   FMT_API file(cstring_view path, int oflag); | ||||
| 
 | ||||
|  public: | ||||
|   file(const file&) = delete; | ||||
|   void operator=(const file&) = delete; | ||||
| 
 | ||||
|   file(file&& other) FMT_NOEXCEPT : fd_(other.fd_) { other.fd_ = -1; } | ||||
| 
 | ||||
|   // Move assignment is not noexcept because close may throw.
 | ||||
|   file& operator=(file&& other) { | ||||
|     close(); | ||||
|     fd_ = other.fd_; | ||||
|     other.fd_ = -1; | ||||
|     return *this; | ||||
|   } | ||||
| 
 | ||||
|   // Destroys the object closing the file it represents if any.
 | ||||
|   FMT_API ~file() FMT_NOEXCEPT; | ||||
| 
 | ||||
|   // Returns the file descriptor.
 | ||||
|   int descriptor() const FMT_NOEXCEPT { return fd_; } | ||||
| 
 | ||||
|   // Closes the file.
 | ||||
|   FMT_API void close(); | ||||
| 
 | ||||
|   // Returns the file size. The size has signed type for consistency with
 | ||||
|   // stat::st_size.
 | ||||
|   FMT_API long long size() const; | ||||
| 
 | ||||
|   // Attempts to read count bytes from the file into the specified buffer.
 | ||||
|   FMT_API size_t read(void* buffer, size_t count); | ||||
| 
 | ||||
|   // Attempts to write count bytes from the specified buffer to the file.
 | ||||
|   FMT_API size_t write(const void* buffer, size_t count); | ||||
| 
 | ||||
|   // Duplicates a file descriptor with the dup function and returns
 | ||||
|   // the duplicate as a file object.
 | ||||
|   FMT_API static file dup(int fd); | ||||
| 
 | ||||
|   // Makes fd be the copy of this file descriptor, closing fd first if
 | ||||
|   // necessary.
 | ||||
|   FMT_API void dup2(int fd); | ||||
| 
 | ||||
|   // Makes fd be the copy of this file descriptor, closing fd first if
 | ||||
|   // necessary.
 | ||||
|   FMT_API void dup2(int fd, std::error_code& ec) FMT_NOEXCEPT; | ||||
| 
 | ||||
|   // Creates a pipe setting up read_end and write_end file objects for reading
 | ||||
|   // and writing respectively.
 | ||||
|   FMT_API static void pipe(file& read_end, file& write_end); | ||||
| 
 | ||||
|   // Creates a buffered_file object associated with this file and detaches
 | ||||
|   // this file object from the file.
 | ||||
|   FMT_API buffered_file fdopen(const char* mode); | ||||
| }; | ||||
| 
 | ||||
| // Returns the memory page size.
 | ||||
| long getpagesize(); | ||||
| 
 | ||||
| FMT_BEGIN_DETAIL_NAMESPACE | ||||
| 
 | ||||
| struct buffer_size { | ||||
|   buffer_size() = default; | ||||
|   size_t value = 0; | ||||
|   buffer_size operator=(size_t val) const { | ||||
|     auto bs = buffer_size(); | ||||
|     bs.value = val; | ||||
|     return bs; | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| struct ostream_params { | ||||
|   int oflag = file::WRONLY | file::CREATE | file::TRUNC; | ||||
|   size_t buffer_size = BUFSIZ > 32768 ? BUFSIZ : 32768; | ||||
| 
 | ||||
|   ostream_params() {} | ||||
| 
 | ||||
|   template <typename... T> | ||||
|   ostream_params(T... params, int new_oflag) : ostream_params(params...) { | ||||
|     oflag = new_oflag; | ||||
|   } | ||||
| 
 | ||||
|   template <typename... T> | ||||
|   ostream_params(T... params, detail::buffer_size bs) | ||||
|       : ostream_params(params...) { | ||||
|     this->buffer_size = bs.value; | ||||
|   } | ||||
| 
 | ||||
| // Intel has a bug that results in failure to deduce a constructor
 | ||||
| // for empty parameter packs.
 | ||||
| #  if defined(__INTEL_COMPILER) && __INTEL_COMPILER < 2000 | ||||
|   ostream_params(int new_oflag) : oflag(new_oflag) {} | ||||
|   ostream_params(detail::buffer_size bs) : buffer_size(bs.value) {} | ||||
| #  endif | ||||
| }; | ||||
| 
 | ||||
| FMT_END_DETAIL_NAMESPACE | ||||
| 
 | ||||
| // Added {} below to work around default constructor error known to
 | ||||
| // occur in Xcode versions 7.2.1 and 8.2.1.
 | ||||
| constexpr detail::buffer_size buffer_size{}; | ||||
| 
 | ||||
| /** A fast output stream which is not thread-safe. */ | ||||
| class FMT_API ostream final : private detail::buffer<char> { | ||||
|  private: | ||||
|   file file_; | ||||
| 
 | ||||
|   void grow(size_t) override; | ||||
| 
 | ||||
|   ostream(cstring_view path, const detail::ostream_params& params) | ||||
|       : file_(path, params.oflag) { | ||||
|     set(new char[params.buffer_size], params.buffer_size); | ||||
|   } | ||||
| 
 | ||||
|  public: | ||||
|   ostream(ostream&& other) | ||||
|       : detail::buffer<char>(other.data(), other.size(), other.capacity()), | ||||
|         file_(std::move(other.file_)) { | ||||
|     other.clear(); | ||||
|     other.set(nullptr, 0); | ||||
|   } | ||||
|   ~ostream() { | ||||
|     flush(); | ||||
|     delete[] data(); | ||||
|   } | ||||
| 
 | ||||
|   void flush() { | ||||
|     if (size() == 0) return; | ||||
|     file_.write(data(), size()); | ||||
|     clear(); | ||||
|   } | ||||
| 
 | ||||
|   template <typename... T> | ||||
|   friend ostream output_file(cstring_view path, T... params); | ||||
| 
 | ||||
|   void close() { | ||||
|     flush(); | ||||
|     file_.close(); | ||||
|   } | ||||
| 
 | ||||
|   /**
 | ||||
|     Formats ``args`` according to specifications in ``fmt`` and writes the | ||||
|     output to the file. | ||||
|    */ | ||||
|   template <typename... T> void print(format_string<T...> fmt, T&&... args) { | ||||
|     vformat_to(detail::buffer_appender<char>(*this), fmt, | ||||
|                fmt::make_format_args(args...)); | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| /**
 | ||||
|   \rst | ||||
|   Opens a file for writing. Supported parameters passed in *params*: | ||||
| 
 | ||||
|   * ``<integer>``: Flags passed to `open | ||||
|     <https://pubs.opengroup.org/onlinepubs/007904875/functions/open.html>`_
 | ||||
|     (``file::WRONLY | file::CREATE`` by default) | ||||
|   * ``buffer_size=<integer>``: Output buffer size | ||||
| 
 | ||||
|   **Example**:: | ||||
| 
 | ||||
|     auto out = fmt::output_file("guide.txt"); | ||||
|     out.print("Don't {}", "Panic"); | ||||
|   \endrst | ||||
|  */ | ||||
| template <typename... T> | ||||
| inline ostream output_file(cstring_view path, T... params) { | ||||
|   return {path, detail::ostream_params(params...)}; | ||||
| } | ||||
| #endif  // FMT_USE_FCNTL
 | ||||
| 
 | ||||
| #ifdef FMT_LOCALE | ||||
| // A "C" numeric locale.
 | ||||
| class locale { | ||||
|  private: | ||||
| #  ifdef _WIN32 | ||||
|   using locale_t = _locale_t; | ||||
| 
 | ||||
|   static void freelocale(locale_t loc) { _free_locale(loc); } | ||||
| 
 | ||||
|   static double strtod_l(const char* nptr, char** endptr, _locale_t loc) { | ||||
|     return _strtod_l(nptr, endptr, loc); | ||||
|   } | ||||
| #  endif | ||||
| 
 | ||||
|   locale_t locale_; | ||||
| 
 | ||||
|  public: | ||||
|   using type = locale_t; | ||||
|   locale(const locale&) = delete; | ||||
|   void operator=(const locale&) = delete; | ||||
| 
 | ||||
|   locale() { | ||||
| #  ifndef _WIN32 | ||||
|     locale_ = FMT_SYSTEM(newlocale(LC_NUMERIC_MASK, "C", nullptr)); | ||||
| #  else | ||||
|     locale_ = _create_locale(LC_NUMERIC, "C"); | ||||
| #  endif | ||||
|     if (!locale_) FMT_THROW(system_error(errno, "cannot create locale")); | ||||
|   } | ||||
|   ~locale() { freelocale(locale_); } | ||||
| 
 | ||||
|   type get() const { return locale_; } | ||||
| 
 | ||||
|   // Converts string to floating-point number and advances str past the end
 | ||||
|   // of the parsed input.
 | ||||
|   FMT_DEPRECATED double strtod(const char*& str) const { | ||||
|     char* end = nullptr; | ||||
|     double result = strtod_l(str, &end, locale_); | ||||
|     str = end; | ||||
|     return result; | ||||
|   } | ||||
| }; | ||||
| using Locale FMT_DEPRECATED_ALIAS = locale; | ||||
| #endif  // FMT_LOCALE
 | ||||
| FMT_MODULE_EXPORT_END | ||||
| FMT_END_NAMESPACE | ||||
| 
 | ||||
| #endif  // FMT_OS_H_
 | ||||
|  | @ -1,135 +0,0 @@ | |||
| // Formatting library for C++ - std::ostream support
 | ||||
| //
 | ||||
| // Copyright (c) 2012 - present, Victor Zverovich
 | ||||
| // All rights reserved.
 | ||||
| //
 | ||||
| // For the license information refer to format.h.
 | ||||
| 
 | ||||
| #ifndef FMT_OSTREAM_H_ | ||||
| #define FMT_OSTREAM_H_ | ||||
| 
 | ||||
| #include <ostream> | ||||
| 
 | ||||
| #include "format.h" | ||||
| 
 | ||||
| FMT_BEGIN_NAMESPACE | ||||
| 
 | ||||
| template <typename OutputIt, typename Char> class basic_printf_context; | ||||
| 
 | ||||
| namespace detail { | ||||
| 
 | ||||
| // Checks if T has a user-defined operator<<.
 | ||||
| template <typename T, typename Char, typename Enable = void> | ||||
| class is_streamable { | ||||
|  private: | ||||
|   template <typename U> | ||||
|   static auto test(int) | ||||
|       -> bool_constant<sizeof(std::declval<std::basic_ostream<Char>&>() | ||||
|                               << std::declval<U>()) != 0>; | ||||
| 
 | ||||
|   template <typename> static auto test(...) -> std::false_type; | ||||
| 
 | ||||
|   using result = decltype(test<T>(0)); | ||||
| 
 | ||||
|  public: | ||||
|   is_streamable() = default; | ||||
| 
 | ||||
|   static const bool value = result::value; | ||||
| }; | ||||
| 
 | ||||
| // Formatting of built-in types and arrays is intentionally disabled because
 | ||||
| // it's handled by standard (non-ostream) formatters.
 | ||||
| template <typename T, typename Char> | ||||
| struct is_streamable< | ||||
|     T, Char, | ||||
|     enable_if_t< | ||||
|         std::is_arithmetic<T>::value || std::is_array<T>::value || | ||||
|         std::is_pointer<T>::value || std::is_same<T, char8_type>::value || | ||||
|         std::is_same<T, std::basic_string<Char>>::value || | ||||
|         std::is_same<T, std_string_view<Char>>::value || | ||||
|         (std::is_convertible<T, int>::value && !std::is_enum<T>::value)>> | ||||
|     : std::false_type {}; | ||||
| 
 | ||||
| // Write the content of buf to os.
 | ||||
| // It is a separate function rather than a part of vprint to simplify testing.
 | ||||
| template <typename Char> | ||||
| void write_buffer(std::basic_ostream<Char>& os, buffer<Char>& buf) { | ||||
|   const Char* buf_data = buf.data(); | ||||
|   using unsigned_streamsize = std::make_unsigned<std::streamsize>::type; | ||||
|   unsigned_streamsize size = buf.size(); | ||||
|   unsigned_streamsize max_size = to_unsigned(max_value<std::streamsize>()); | ||||
|   do { | ||||
|     unsigned_streamsize n = size <= max_size ? size : max_size; | ||||
|     os.write(buf_data, static_cast<std::streamsize>(n)); | ||||
|     buf_data += n; | ||||
|     size -= n; | ||||
|   } while (size != 0); | ||||
| } | ||||
| 
 | ||||
| template <typename Char, typename T> | ||||
| void format_value(buffer<Char>& buf, const T& value, | ||||
|                   locale_ref loc = locale_ref()) { | ||||
|   auto&& format_buf = formatbuf<std::basic_streambuf<Char>>(buf); | ||||
|   auto&& output = std::basic_ostream<Char>(&format_buf); | ||||
| #if !defined(FMT_STATIC_THOUSANDS_SEPARATOR) | ||||
|   if (loc) output.imbue(loc.get<std::locale>()); | ||||
| #endif | ||||
|   output << value; | ||||
|   output.exceptions(std::ios_base::failbit | std::ios_base::badbit); | ||||
|   buf.try_resize(buf.size()); | ||||
| } | ||||
| 
 | ||||
| // Formats an object of type T that has an overloaded ostream operator<<.
 | ||||
| template <typename T, typename Char> | ||||
| struct fallback_formatter<T, Char, enable_if_t<is_streamable<T, Char>::value>> | ||||
|     : private formatter<basic_string_view<Char>, Char> { | ||||
|   using formatter<basic_string_view<Char>, Char>::parse; | ||||
| 
 | ||||
|   template <typename OutputIt> | ||||
|   auto format(const T& value, basic_format_context<OutputIt, Char>& ctx) | ||||
|       -> OutputIt { | ||||
|     auto buffer = basic_memory_buffer<Char>(); | ||||
|     format_value(buffer, value, ctx.locale()); | ||||
|     return formatter<basic_string_view<Char>, Char>::format( | ||||
|         {buffer.data(), buffer.size()}, ctx); | ||||
|   } | ||||
| 
 | ||||
|   // DEPRECATED!
 | ||||
|   template <typename OutputIt> | ||||
|   auto format(const T& value, basic_printf_context<OutputIt, Char>& ctx) | ||||
|       -> OutputIt { | ||||
|     auto buffer = basic_memory_buffer<Char>(); | ||||
|     format_value(buffer, value, ctx.locale()); | ||||
|     return std::copy(buffer.begin(), buffer.end(), ctx.out()); | ||||
|   } | ||||
| }; | ||||
| }  // namespace detail
 | ||||
| 
 | ||||
| FMT_MODULE_EXPORT | ||||
| template <typename Char> | ||||
| void vprint(std::basic_ostream<Char>& os, basic_string_view<Char> format_str, | ||||
|             basic_format_args<buffer_context<type_identity_t<Char>>> args) { | ||||
|   auto buffer = basic_memory_buffer<Char>(); | ||||
|   detail::vformat_to(buffer, format_str, args); | ||||
|   detail::write_buffer(os, buffer); | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|   \rst | ||||
|   Prints formatted data to the stream *os*. | ||||
| 
 | ||||
|   **Example**:: | ||||
| 
 | ||||
|     fmt::print(cerr, "Don't {}!", "panic"); | ||||
|   \endrst | ||||
|  */ | ||||
| FMT_MODULE_EXPORT | ||||
| template <typename S, typename... Args, | ||||
|           typename Char = enable_if_t<detail::is_string<S>::value, char_t<S>>> | ||||
| void print(std::basic_ostream<Char>& os, const S& format_str, Args&&... args) { | ||||
|   vprint(os, to_string_view(format_str), | ||||
|          fmt::make_args_checked<Args...>(format_str, args...)); | ||||
| } | ||||
| FMT_END_NAMESPACE | ||||
| 
 | ||||
| #endif  // FMT_OSTREAM_H_
 | ||||
|  | @ -1,657 +0,0 @@ | |||
| // Formatting library for C++ - legacy printf implementation
 | ||||
| //
 | ||||
| // Copyright (c) 2012 - 2016, Victor Zverovich
 | ||||
| // All rights reserved.
 | ||||
| //
 | ||||
| // For the license information refer to format.h.
 | ||||
| 
 | ||||
| #ifndef FMT_PRINTF_H_ | ||||
| #define FMT_PRINTF_H_ | ||||
| 
 | ||||
| #include <algorithm>  // std::max | ||||
| #include <limits>     // std::numeric_limits | ||||
| #include <ostream> | ||||
| 
 | ||||
| #include "format.h" | ||||
| 
 | ||||
| FMT_BEGIN_NAMESPACE | ||||
| FMT_MODULE_EXPORT_BEGIN | ||||
| 
 | ||||
| template <typename T> struct printf_formatter { printf_formatter() = delete; }; | ||||
| 
 | ||||
| template <typename Char> | ||||
| class basic_printf_parse_context : public basic_format_parse_context<Char> { | ||||
|   using basic_format_parse_context<Char>::basic_format_parse_context; | ||||
| }; | ||||
| 
 | ||||
| template <typename OutputIt, typename Char> class basic_printf_context { | ||||
|  private: | ||||
|   OutputIt out_; | ||||
|   basic_format_args<basic_printf_context> args_; | ||||
| 
 | ||||
|  public: | ||||
|   using char_type = Char; | ||||
|   using format_arg = basic_format_arg<basic_printf_context>; | ||||
|   using parse_context_type = basic_printf_parse_context<Char>; | ||||
|   template <typename T> using formatter_type = printf_formatter<T>; | ||||
| 
 | ||||
|   /**
 | ||||
|     \rst | ||||
|     Constructs a ``printf_context`` object. References to the arguments are | ||||
|     stored in the context object so make sure they have appropriate lifetimes. | ||||
|     \endrst | ||||
|    */ | ||||
|   basic_printf_context(OutputIt out, | ||||
|                        basic_format_args<basic_printf_context> args) | ||||
|       : out_(out), args_(args) {} | ||||
| 
 | ||||
|   OutputIt out() { return out_; } | ||||
|   void advance_to(OutputIt it) { out_ = it; } | ||||
| 
 | ||||
|   detail::locale_ref locale() { return {}; } | ||||
| 
 | ||||
|   format_arg arg(int id) const { return args_.get(id); } | ||||
| 
 | ||||
|   FMT_CONSTEXPR void on_error(const char* message) { | ||||
|     detail::error_handler().on_error(message); | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| FMT_BEGIN_DETAIL_NAMESPACE | ||||
| 
 | ||||
| // Checks if a value fits in int - used to avoid warnings about comparing
 | ||||
| // signed and unsigned integers.
 | ||||
| template <bool IsSigned> struct int_checker { | ||||
|   template <typename T> static bool fits_in_int(T value) { | ||||
|     unsigned max = max_value<int>(); | ||||
|     return value <= max; | ||||
|   } | ||||
|   static bool fits_in_int(bool) { return true; } | ||||
| }; | ||||
| 
 | ||||
| template <> struct int_checker<true> { | ||||
|   template <typename T> static bool fits_in_int(T value) { | ||||
|     return value >= (std::numeric_limits<int>::min)() && | ||||
|            value <= max_value<int>(); | ||||
|   } | ||||
|   static bool fits_in_int(int) { return true; } | ||||
| }; | ||||
| 
 | ||||
| class printf_precision_handler { | ||||
|  public: | ||||
|   template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)> | ||||
|   int operator()(T value) { | ||||
|     if (!int_checker<std::numeric_limits<T>::is_signed>::fits_in_int(value)) | ||||
|       FMT_THROW(format_error("number is too big")); | ||||
|     return (std::max)(static_cast<int>(value), 0); | ||||
|   } | ||||
| 
 | ||||
|   template <typename T, FMT_ENABLE_IF(!std::is_integral<T>::value)> | ||||
|   int operator()(T) { | ||||
|     FMT_THROW(format_error("precision is not integer")); | ||||
|     return 0; | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| // An argument visitor that returns true iff arg is a zero integer.
 | ||||
| class is_zero_int { | ||||
|  public: | ||||
|   template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)> | ||||
|   bool operator()(T value) { | ||||
|     return value == 0; | ||||
|   } | ||||
| 
 | ||||
|   template <typename T, FMT_ENABLE_IF(!std::is_integral<T>::value)> | ||||
|   bool operator()(T) { | ||||
|     return false; | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| template <typename T> struct make_unsigned_or_bool : std::make_unsigned<T> {}; | ||||
| 
 | ||||
| template <> struct make_unsigned_or_bool<bool> { using type = bool; }; | ||||
| 
 | ||||
| template <typename T, typename Context> class arg_converter { | ||||
|  private: | ||||
|   using char_type = typename Context::char_type; | ||||
| 
 | ||||
|   basic_format_arg<Context>& arg_; | ||||
|   char_type type_; | ||||
| 
 | ||||
|  public: | ||||
|   arg_converter(basic_format_arg<Context>& arg, char_type type) | ||||
|       : arg_(arg), type_(type) {} | ||||
| 
 | ||||
|   void operator()(bool value) { | ||||
|     if (type_ != 's') operator()<bool>(value); | ||||
|   } | ||||
| 
 | ||||
|   template <typename U, FMT_ENABLE_IF(std::is_integral<U>::value)> | ||||
|   void operator()(U value) { | ||||
|     bool is_signed = type_ == 'd' || type_ == 'i'; | ||||
|     using target_type = conditional_t<std::is_same<T, void>::value, U, T>; | ||||
|     if (const_check(sizeof(target_type) <= sizeof(int))) { | ||||
|       // Extra casts are used to silence warnings.
 | ||||
|       if (is_signed) { | ||||
|         arg_ = detail::make_arg<Context>( | ||||
|             static_cast<int>(static_cast<target_type>(value))); | ||||
|       } else { | ||||
|         using unsigned_type = typename make_unsigned_or_bool<target_type>::type; | ||||
|         arg_ = detail::make_arg<Context>( | ||||
|             static_cast<unsigned>(static_cast<unsigned_type>(value))); | ||||
|       } | ||||
|     } else { | ||||
|       if (is_signed) { | ||||
|         // glibc's printf doesn't sign extend arguments of smaller types:
 | ||||
|         //   std::printf("%lld", -42);  // prints "4294967254"
 | ||||
|         // but we don't have to do the same because it's a UB.
 | ||||
|         arg_ = detail::make_arg<Context>(static_cast<long long>(value)); | ||||
|       } else { | ||||
|         arg_ = detail::make_arg<Context>( | ||||
|             static_cast<typename make_unsigned_or_bool<U>::type>(value)); | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   template <typename U, FMT_ENABLE_IF(!std::is_integral<U>::value)> | ||||
|   void operator()(U) {}  // No conversion needed for non-integral types.
 | ||||
| }; | ||||
| 
 | ||||
| // Converts an integer argument to T for printf, if T is an integral type.
 | ||||
| // If T is void, the argument is converted to corresponding signed or unsigned
 | ||||
| // type depending on the type specifier: 'd' and 'i' - signed, other -
 | ||||
| // unsigned).
 | ||||
| template <typename T, typename Context, typename Char> | ||||
| void convert_arg(basic_format_arg<Context>& arg, Char type) { | ||||
|   visit_format_arg(arg_converter<T, Context>(arg, type), arg); | ||||
| } | ||||
| 
 | ||||
| // Converts an integer argument to char for printf.
 | ||||
| template <typename Context> class char_converter { | ||||
|  private: | ||||
|   basic_format_arg<Context>& arg_; | ||||
| 
 | ||||
|  public: | ||||
|   explicit char_converter(basic_format_arg<Context>& arg) : arg_(arg) {} | ||||
| 
 | ||||
|   template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)> | ||||
|   void operator()(T value) { | ||||
|     arg_ = detail::make_arg<Context>( | ||||
|         static_cast<typename Context::char_type>(value)); | ||||
|   } | ||||
| 
 | ||||
|   template <typename T, FMT_ENABLE_IF(!std::is_integral<T>::value)> | ||||
|   void operator()(T) {}  // No conversion needed for non-integral types.
 | ||||
| }; | ||||
| 
 | ||||
| // An argument visitor that return a pointer to a C string if argument is a
 | ||||
| // string or null otherwise.
 | ||||
| template <typename Char> struct get_cstring { | ||||
|   template <typename T> const Char* operator()(T) { return nullptr; } | ||||
|   const Char* operator()(const Char* s) { return s; } | ||||
| }; | ||||
| 
 | ||||
| // Checks if an argument is a valid printf width specifier and sets
 | ||||
| // left alignment if it is negative.
 | ||||
| template <typename Char> class printf_width_handler { | ||||
|  private: | ||||
|   using format_specs = basic_format_specs<Char>; | ||||
| 
 | ||||
|   format_specs& specs_; | ||||
| 
 | ||||
|  public: | ||||
|   explicit printf_width_handler(format_specs& specs) : specs_(specs) {} | ||||
| 
 | ||||
|   template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)> | ||||
|   unsigned operator()(T value) { | ||||
|     auto width = static_cast<uint32_or_64_or_128_t<T>>(value); | ||||
|     if (detail::is_negative(value)) { | ||||
|       specs_.align = align::left; | ||||
|       width = 0 - width; | ||||
|     } | ||||
|     unsigned int_max = max_value<int>(); | ||||
|     if (width > int_max) FMT_THROW(format_error("number is too big")); | ||||
|     return static_cast<unsigned>(width); | ||||
|   } | ||||
| 
 | ||||
|   template <typename T, FMT_ENABLE_IF(!std::is_integral<T>::value)> | ||||
|   unsigned operator()(T) { | ||||
|     FMT_THROW(format_error("width is not integer")); | ||||
|     return 0; | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| // The ``printf`` argument formatter.
 | ||||
| template <typename OutputIt, typename Char> | ||||
| class printf_arg_formatter : public arg_formatter<Char> { | ||||
|  private: | ||||
|   using base = arg_formatter<Char>; | ||||
|   using context_type = basic_printf_context<OutputIt, Char>; | ||||
|   using format_specs = basic_format_specs<Char>; | ||||
| 
 | ||||
|   context_type& context_; | ||||
| 
 | ||||
|   OutputIt write_null_pointer(bool is_string = false) { | ||||
|     auto s = this->specs; | ||||
|     s.type = presentation_type::none; | ||||
|     return write_bytes(this->out, is_string ? "(null)" : "(nil)", s); | ||||
|   } | ||||
| 
 | ||||
|  public: | ||||
|   printf_arg_formatter(OutputIt iter, format_specs& s, context_type& ctx) | ||||
|       : base{iter, s, locale_ref()}, context_(ctx) {} | ||||
| 
 | ||||
|   OutputIt operator()(monostate value) { return base::operator()(value); } | ||||
| 
 | ||||
|   template <typename T, FMT_ENABLE_IF(detail::is_integral<T>::value)> | ||||
|   OutputIt operator()(T value) { | ||||
|     // MSVC2013 fails to compile separate overloads for bool and Char so use
 | ||||
|     // std::is_same instead.
 | ||||
|     if (std::is_same<T, Char>::value) { | ||||
|       format_specs fmt_specs = this->specs; | ||||
|       if (fmt_specs.type != presentation_type::none && | ||||
|           fmt_specs.type != presentation_type::chr) { | ||||
|         return (*this)(static_cast<int>(value)); | ||||
|       } | ||||
|       fmt_specs.sign = sign::none; | ||||
|       fmt_specs.alt = false; | ||||
|       fmt_specs.fill[0] = ' ';  // Ignore '0' flag for char types.
 | ||||
|       // align::numeric needs to be overwritten here since the '0' flag is
 | ||||
|       // ignored for non-numeric types
 | ||||
|       if (fmt_specs.align == align::none || fmt_specs.align == align::numeric) | ||||
|         fmt_specs.align = align::right; | ||||
|       return write<Char>(this->out, static_cast<Char>(value), fmt_specs); | ||||
|     } | ||||
|     return base::operator()(value); | ||||
|   } | ||||
| 
 | ||||
|   template <typename T, FMT_ENABLE_IF(std::is_floating_point<T>::value)> | ||||
|   OutputIt operator()(T value) { | ||||
|     return base::operator()(value); | ||||
|   } | ||||
| 
 | ||||
|   /** Formats a null-terminated C string. */ | ||||
|   OutputIt operator()(const char* value) { | ||||
|     if (value) return base::operator()(value); | ||||
|     return write_null_pointer(this->specs.type != presentation_type::pointer); | ||||
|   } | ||||
| 
 | ||||
|   /** Formats a null-terminated wide C string. */ | ||||
|   OutputIt operator()(const wchar_t* value) { | ||||
|     if (value) return base::operator()(value); | ||||
|     return write_null_pointer(this->specs.type != presentation_type::pointer); | ||||
|   } | ||||
| 
 | ||||
|   OutputIt operator()(basic_string_view<Char> value) { | ||||
|     return base::operator()(value); | ||||
|   } | ||||
| 
 | ||||
|   /** Formats a pointer. */ | ||||
|   OutputIt operator()(const void* value) { | ||||
|     return value ? base::operator()(value) : write_null_pointer(); | ||||
|   } | ||||
| 
 | ||||
|   /** Formats an argument of a custom (user-defined) type. */ | ||||
|   OutputIt operator()(typename basic_format_arg<context_type>::handle handle) { | ||||
|     auto parse_ctx = | ||||
|         basic_printf_parse_context<Char>(basic_string_view<Char>()); | ||||
|     handle.format(parse_ctx, context_); | ||||
|     return this->out; | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| template <typename Char> | ||||
| void parse_flags(basic_format_specs<Char>& specs, const Char*& it, | ||||
|                  const Char* end) { | ||||
|   for (; it != end; ++it) { | ||||
|     switch (*it) { | ||||
|     case '-': | ||||
|       specs.align = align::left; | ||||
|       break; | ||||
|     case '+': | ||||
|       specs.sign = sign::plus; | ||||
|       break; | ||||
|     case '0': | ||||
|       specs.fill[0] = '0'; | ||||
|       break; | ||||
|     case ' ': | ||||
|       if (specs.sign != sign::plus) { | ||||
|         specs.sign = sign::space; | ||||
|       } | ||||
|       break; | ||||
|     case '#': | ||||
|       specs.alt = true; | ||||
|       break; | ||||
|     default: | ||||
|       return; | ||||
|     } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| template <typename Char, typename GetArg> | ||||
| int parse_header(const Char*& it, const Char* end, | ||||
|                  basic_format_specs<Char>& specs, GetArg get_arg) { | ||||
|   int arg_index = -1; | ||||
|   Char c = *it; | ||||
|   if (c >= '0' && c <= '9') { | ||||
|     // Parse an argument index (if followed by '$') or a width possibly
 | ||||
|     // preceded with '0' flag(s).
 | ||||
|     int value = parse_nonnegative_int(it, end, -1); | ||||
|     if (it != end && *it == '$') {  // value is an argument index
 | ||||
|       ++it; | ||||
|       arg_index = value != -1 ? value : max_value<int>(); | ||||
|     } else { | ||||
|       if (c == '0') specs.fill[0] = '0'; | ||||
|       if (value != 0) { | ||||
|         // Nonzero value means that we parsed width and don't need to
 | ||||
|         // parse it or flags again, so return now.
 | ||||
|         if (value == -1) FMT_THROW(format_error("number is too big")); | ||||
|         specs.width = value; | ||||
|         return arg_index; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|   parse_flags(specs, it, end); | ||||
|   // Parse width.
 | ||||
|   if (it != end) { | ||||
|     if (*it >= '0' && *it <= '9') { | ||||
|       specs.width = parse_nonnegative_int(it, end, -1); | ||||
|       if (specs.width == -1) FMT_THROW(format_error("number is too big")); | ||||
|     } else if (*it == '*') { | ||||
|       ++it; | ||||
|       specs.width = static_cast<int>(visit_format_arg( | ||||
|           detail::printf_width_handler<Char>(specs), get_arg(-1))); | ||||
|     } | ||||
|   } | ||||
|   return arg_index; | ||||
| } | ||||
| 
 | ||||
| template <typename Char, typename Context> | ||||
| void vprintf(buffer<Char>& buf, basic_string_view<Char> format, | ||||
|              basic_format_args<Context> args) { | ||||
|   using OutputIt = buffer_appender<Char>; | ||||
|   auto out = OutputIt(buf); | ||||
|   auto context = basic_printf_context<OutputIt, Char>(out, args); | ||||
|   auto parse_ctx = basic_printf_parse_context<Char>(format); | ||||
| 
 | ||||
|   // Returns the argument with specified index or, if arg_index is -1, the next
 | ||||
|   // argument.
 | ||||
|   auto get_arg = [&](int arg_index) { | ||||
|     if (arg_index < 0) | ||||
|       arg_index = parse_ctx.next_arg_id(); | ||||
|     else | ||||
|       parse_ctx.check_arg_id(--arg_index); | ||||
|     return detail::get_arg(context, arg_index); | ||||
|   }; | ||||
| 
 | ||||
|   const Char* start = parse_ctx.begin(); | ||||
|   const Char* end = parse_ctx.end(); | ||||
|   auto it = start; | ||||
|   while (it != end) { | ||||
|     if (!detail::find<false, Char>(it, end, '%', it)) { | ||||
|       it = end;  // detail::find leaves it == nullptr if it doesn't find '%'
 | ||||
|       break; | ||||
|     } | ||||
|     Char c = *it++; | ||||
|     if (it != end && *it == c) { | ||||
|       out = detail::write( | ||||
|           out, basic_string_view<Char>(start, detail::to_unsigned(it - start))); | ||||
|       start = ++it; | ||||
|       continue; | ||||
|     } | ||||
|     out = detail::write(out, basic_string_view<Char>( | ||||
|                                  start, detail::to_unsigned(it - 1 - start))); | ||||
| 
 | ||||
|     basic_format_specs<Char> specs; | ||||
|     specs.align = align::right; | ||||
| 
 | ||||
|     // Parse argument index, flags and width.
 | ||||
|     int arg_index = parse_header(it, end, specs, get_arg); | ||||
|     if (arg_index == 0) parse_ctx.on_error("argument not found"); | ||||
| 
 | ||||
|     // Parse precision.
 | ||||
|     if (it != end && *it == '.') { | ||||
|       ++it; | ||||
|       c = it != end ? *it : 0; | ||||
|       if ('0' <= c && c <= '9') { | ||||
|         specs.precision = parse_nonnegative_int(it, end, 0); | ||||
|       } else if (c == '*') { | ||||
|         ++it; | ||||
|         specs.precision = static_cast<int>( | ||||
|             visit_format_arg(detail::printf_precision_handler(), get_arg(-1))); | ||||
|       } else { | ||||
|         specs.precision = 0; | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|     auto arg = get_arg(arg_index); | ||||
|     // For d, i, o, u, x, and X conversion specifiers, if a precision is
 | ||||
|     // specified, the '0' flag is ignored
 | ||||
|     if (specs.precision >= 0 && arg.is_integral()) | ||||
|       specs.fill[0] = | ||||
|           ' ';  // Ignore '0' flag for non-numeric types or if '-' present.
 | ||||
|     if (specs.precision >= 0 && arg.type() == detail::type::cstring_type) { | ||||
|       auto str = visit_format_arg(detail::get_cstring<Char>(), arg); | ||||
|       auto str_end = str + specs.precision; | ||||
|       auto nul = std::find(str, str_end, Char()); | ||||
|       arg = detail::make_arg<basic_printf_context<OutputIt, Char>>( | ||||
|           basic_string_view<Char>( | ||||
|               str, detail::to_unsigned(nul != str_end ? nul - str | ||||
|                                                       : specs.precision))); | ||||
|     } | ||||
|     if (specs.alt && visit_format_arg(detail::is_zero_int(), arg)) | ||||
|       specs.alt = false; | ||||
|     if (specs.fill[0] == '0') { | ||||
|       if (arg.is_arithmetic() && specs.align != align::left) | ||||
|         specs.align = align::numeric; | ||||
|       else | ||||
|         specs.fill[0] = ' ';  // Ignore '0' flag for non-numeric types or if '-'
 | ||||
|                               // flag is also present.
 | ||||
|     } | ||||
| 
 | ||||
|     // Parse length and convert the argument to the required type.
 | ||||
|     c = it != end ? *it++ : 0; | ||||
|     Char t = it != end ? *it : 0; | ||||
|     using detail::convert_arg; | ||||
|     switch (c) { | ||||
|     case 'h': | ||||
|       if (t == 'h') { | ||||
|         ++it; | ||||
|         t = it != end ? *it : 0; | ||||
|         convert_arg<signed char>(arg, t); | ||||
|       } else { | ||||
|         convert_arg<short>(arg, t); | ||||
|       } | ||||
|       break; | ||||
|     case 'l': | ||||
|       if (t == 'l') { | ||||
|         ++it; | ||||
|         t = it != end ? *it : 0; | ||||
|         convert_arg<long long>(arg, t); | ||||
|       } else { | ||||
|         convert_arg<long>(arg, t); | ||||
|       } | ||||
|       break; | ||||
|     case 'j': | ||||
|       convert_arg<intmax_t>(arg, t); | ||||
|       break; | ||||
|     case 'z': | ||||
|       convert_arg<size_t>(arg, t); | ||||
|       break; | ||||
|     case 't': | ||||
|       convert_arg<std::ptrdiff_t>(arg, t); | ||||
|       break; | ||||
|     case 'L': | ||||
|       // printf produces garbage when 'L' is omitted for long double, no
 | ||||
|       // need to do the same.
 | ||||
|       break; | ||||
|     default: | ||||
|       --it; | ||||
|       convert_arg<void>(arg, c); | ||||
|     } | ||||
| 
 | ||||
|     // Parse type.
 | ||||
|     if (it == end) FMT_THROW(format_error("invalid format string")); | ||||
|     char type = static_cast<char>(*it++); | ||||
|     if (arg.is_integral()) { | ||||
|       // Normalize type.
 | ||||
|       switch (type) { | ||||
|       case 'i': | ||||
|       case 'u': | ||||
|         type = 'd'; | ||||
|         break; | ||||
|       case 'c': | ||||
|         visit_format_arg( | ||||
|             detail::char_converter<basic_printf_context<OutputIt, Char>>(arg), | ||||
|             arg); | ||||
|         break; | ||||
|       } | ||||
|     } | ||||
|     specs.type = parse_presentation_type(type); | ||||
|     if (specs.type == presentation_type::none) | ||||
|       parse_ctx.on_error("invalid type specifier"); | ||||
| 
 | ||||
|     start = it; | ||||
| 
 | ||||
|     // Format argument.
 | ||||
|     out = visit_format_arg( | ||||
|         detail::printf_arg_formatter<OutputIt, Char>(out, specs, context), arg); | ||||
|   } | ||||
|   detail::write(out, basic_string_view<Char>(start, to_unsigned(it - start))); | ||||
| } | ||||
| FMT_END_DETAIL_NAMESPACE | ||||
| 
 | ||||
| template <typename Char> | ||||
| using basic_printf_context_t = | ||||
|     basic_printf_context<detail::buffer_appender<Char>, Char>; | ||||
| 
 | ||||
| using printf_context = basic_printf_context_t<char>; | ||||
| using wprintf_context = basic_printf_context_t<wchar_t>; | ||||
| 
 | ||||
| using printf_args = basic_format_args<printf_context>; | ||||
| using wprintf_args = basic_format_args<wprintf_context>; | ||||
| 
 | ||||
| /**
 | ||||
|   \rst | ||||
|   Constructs an `~fmt::format_arg_store` object that contains references to | ||||
|   arguments and can be implicitly converted to `~fmt::printf_args`. | ||||
|   \endrst | ||||
|  */ | ||||
| template <typename... T> | ||||
| inline auto make_printf_args(const T&... args) | ||||
|     -> format_arg_store<printf_context, T...> { | ||||
|   return {args...}; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|   \rst | ||||
|   Constructs an `~fmt::format_arg_store` object that contains references to | ||||
|   arguments and can be implicitly converted to `~fmt::wprintf_args`. | ||||
|   \endrst | ||||
|  */ | ||||
| template <typename... T> | ||||
| inline auto make_wprintf_args(const T&... args) | ||||
|     -> format_arg_store<wprintf_context, T...> { | ||||
|   return {args...}; | ||||
| } | ||||
| 
 | ||||
| template <typename S, typename Char = char_t<S>> | ||||
| inline auto vsprintf( | ||||
|     const S& fmt, | ||||
|     basic_format_args<basic_printf_context_t<type_identity_t<Char>>> args) | ||||
|     -> std::basic_string<Char> { | ||||
|   basic_memory_buffer<Char> buffer; | ||||
|   vprintf(buffer, to_string_view(fmt), args); | ||||
|   return to_string(buffer); | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|   \rst | ||||
|   Formats arguments and returns the result as a string. | ||||
| 
 | ||||
|   **Example**:: | ||||
| 
 | ||||
|     std::string message = fmt::sprintf("The answer is %d", 42); | ||||
|   \endrst | ||||
| */ | ||||
| template <typename S, typename... T, | ||||
|           typename Char = enable_if_t<detail::is_string<S>::value, char_t<S>>> | ||||
| inline auto sprintf(const S& fmt, const T&... args) -> std::basic_string<Char> { | ||||
|   using context = basic_printf_context_t<Char>; | ||||
|   return vsprintf(to_string_view(fmt), fmt::make_format_args<context>(args...)); | ||||
| } | ||||
| 
 | ||||
| template <typename S, typename Char = char_t<S>> | ||||
| inline auto vfprintf( | ||||
|     std::FILE* f, const S& fmt, | ||||
|     basic_format_args<basic_printf_context_t<type_identity_t<Char>>> args) | ||||
|     -> int { | ||||
|   basic_memory_buffer<Char> buffer; | ||||
|   vprintf(buffer, to_string_view(fmt), args); | ||||
|   size_t size = buffer.size(); | ||||
|   return std::fwrite(buffer.data(), sizeof(Char), size, f) < size | ||||
|              ? -1 | ||||
|              : static_cast<int>(size); | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|   \rst | ||||
|   Prints formatted data to the file *f*. | ||||
| 
 | ||||
|   **Example**:: | ||||
| 
 | ||||
|     fmt::fprintf(stderr, "Don't %s!", "panic"); | ||||
|   \endrst | ||||
|  */ | ||||
| template <typename S, typename... T, typename Char = char_t<S>> | ||||
| inline auto fprintf(std::FILE* f, const S& fmt, const T&... args) -> int { | ||||
|   using context = basic_printf_context_t<Char>; | ||||
|   return vfprintf(f, to_string_view(fmt), | ||||
|                   fmt::make_format_args<context>(args...)); | ||||
| } | ||||
| 
 | ||||
| template <typename S, typename Char = char_t<S>> | ||||
| inline auto vprintf( | ||||
|     const S& fmt, | ||||
|     basic_format_args<basic_printf_context_t<type_identity_t<Char>>> args) | ||||
|     -> int { | ||||
|   return vfprintf(stdout, to_string_view(fmt), args); | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|   \rst | ||||
|   Prints formatted data to ``stdout``. | ||||
| 
 | ||||
|   **Example**:: | ||||
| 
 | ||||
|     fmt::printf("Elapsed time: %.2f seconds", 1.23); | ||||
|   \endrst | ||||
|  */ | ||||
| template <typename S, typename... T, FMT_ENABLE_IF(detail::is_string<S>::value)> | ||||
| inline auto printf(const S& fmt, const T&... args) -> int { | ||||
|   return vprintf( | ||||
|       to_string_view(fmt), | ||||
|       fmt::make_format_args<basic_printf_context_t<char_t<S>>>(args...)); | ||||
| } | ||||
| 
 | ||||
| template <typename S, typename Char = char_t<S>> | ||||
| FMT_DEPRECATED auto vfprintf( | ||||
|     std::basic_ostream<Char>& os, const S& fmt, | ||||
|     basic_format_args<basic_printf_context_t<type_identity_t<Char>>> args) | ||||
|     -> int { | ||||
|   basic_memory_buffer<Char> buffer; | ||||
|   vprintf(buffer, to_string_view(fmt), args); | ||||
|   os.write(buffer.data(), static_cast<std::streamsize>(buffer.size())); | ||||
|   return static_cast<int>(buffer.size()); | ||||
| } | ||||
| template <typename S, typename... T, typename Char = char_t<S>> | ||||
| FMT_DEPRECATED auto fprintf(std::basic_ostream<Char>& os, const S& fmt, | ||||
|                             const T&... args) -> int { | ||||
|   return vfprintf(os, to_string_view(fmt), | ||||
|                   fmt::make_format_args<basic_printf_context_t<Char>>(args...)); | ||||
| } | ||||
| 
 | ||||
| FMT_MODULE_EXPORT_END | ||||
| FMT_END_NAMESPACE | ||||
| 
 | ||||
| #endif  // FMT_PRINTF_H_
 | ||||
|  | @ -1,793 +0,0 @@ | |||
| // Formatting library for C++ - experimental range support
 | ||||
| //
 | ||||
| // Copyright (c) 2012 - present, Victor Zverovich
 | ||||
| // All rights reserved.
 | ||||
| //
 | ||||
| // For the license information refer to format.h.
 | ||||
| //
 | ||||
| // Copyright (c) 2018 - present, Remotion (Igor Schulz)
 | ||||
| // All Rights Reserved
 | ||||
| // {fmt} support for ranges, containers and types tuple interface.
 | ||||
| 
 | ||||
| #ifndef FMT_RANGES_H_ | ||||
| #define FMT_RANGES_H_ | ||||
| 
 | ||||
| #include <initializer_list> | ||||
| #include <tuple> | ||||
| #include <type_traits> | ||||
| 
 | ||||
| #include "format.h" | ||||
| 
 | ||||
| FMT_BEGIN_NAMESPACE | ||||
| 
 | ||||
| namespace detail { | ||||
| 
 | ||||
| template <typename RangeT, typename OutputIterator> | ||||
| OutputIterator copy(const RangeT& range, OutputIterator out) { | ||||
|   for (auto it = range.begin(), end = range.end(); it != end; ++it) | ||||
|     *out++ = *it; | ||||
|   return out; | ||||
| } | ||||
| 
 | ||||
| template <typename OutputIterator> | ||||
| OutputIterator copy(const char* str, OutputIterator out) { | ||||
|   while (*str) *out++ = *str++; | ||||
|   return out; | ||||
| } | ||||
| 
 | ||||
| template <typename OutputIterator> | ||||
| OutputIterator copy(char ch, OutputIterator out) { | ||||
|   *out++ = ch; | ||||
|   return out; | ||||
| } | ||||
| 
 | ||||
| template <typename OutputIterator> | ||||
| OutputIterator copy(wchar_t ch, OutputIterator out) { | ||||
|   *out++ = ch; | ||||
|   return out; | ||||
| } | ||||
| 
 | ||||
| // Returns true if T has a std::string-like interface, like std::string_view.
 | ||||
| template <typename T> class is_std_string_like { | ||||
|   template <typename U> | ||||
|   static auto check(U* p) | ||||
|       -> decltype((void)p->find('a'), p->length(), (void)p->data(), int()); | ||||
|   template <typename> static void check(...); | ||||
| 
 | ||||
|  public: | ||||
|   static FMT_CONSTEXPR_DECL const bool value = | ||||
|       is_string<T>::value || | ||||
|       std::is_convertible<T, std_string_view<char>>::value || | ||||
|       !std::is_void<decltype(check<T>(nullptr))>::value; | ||||
| }; | ||||
| 
 | ||||
| template <typename Char> | ||||
| struct is_std_string_like<fmt::basic_string_view<Char>> : std::true_type {}; | ||||
| 
 | ||||
| template <typename T> class is_map { | ||||
|   template <typename U> static auto check(U*) -> typename U::mapped_type; | ||||
|   template <typename> static void check(...); | ||||
| 
 | ||||
|  public: | ||||
| #ifdef FMT_FORMAT_MAP_AS_LIST | ||||
|   static FMT_CONSTEXPR_DECL const bool value = false; | ||||
| #else | ||||
|   static FMT_CONSTEXPR_DECL const bool value = | ||||
|       !std::is_void<decltype(check<T>(nullptr))>::value; | ||||
| #endif | ||||
| }; | ||||
| 
 | ||||
| template <typename T> class is_set { | ||||
|   template <typename U> static auto check(U*) -> typename U::key_type; | ||||
|   template <typename> static void check(...); | ||||
| 
 | ||||
|  public: | ||||
| #ifdef FMT_FORMAT_SET_AS_LIST | ||||
|   static FMT_CONSTEXPR_DECL const bool value = false; | ||||
| #else | ||||
|   static FMT_CONSTEXPR_DECL const bool value = | ||||
|       !std::is_void<decltype(check<T>(nullptr))>::value && !is_map<T>::value; | ||||
| #endif | ||||
| }; | ||||
| 
 | ||||
| template <typename... Ts> struct conditional_helper {}; | ||||
| 
 | ||||
| template <typename T, typename _ = void> struct is_range_ : std::false_type {}; | ||||
| 
 | ||||
| #if !FMT_MSC_VER || FMT_MSC_VER > 1800 | ||||
| 
 | ||||
| #  define FMT_DECLTYPE_RETURN(val)  \ | ||||
|     ->decltype(val) { return val; } \ | ||||
|     static_assert(                  \ | ||||
|         true, "")  // This makes it so that a semicolon is required after the
 | ||||
|                    // macro, which helps clang-format handle the formatting.
 | ||||
| 
 | ||||
| // C array overload
 | ||||
| template <typename T, std::size_t N> | ||||
| auto range_begin(const T (&arr)[N]) -> const T* { | ||||
|   return arr; | ||||
| } | ||||
| template <typename T, std::size_t N> | ||||
| auto range_end(const T (&arr)[N]) -> const T* { | ||||
|   return arr + N; | ||||
| } | ||||
| 
 | ||||
| template <typename T, typename Enable = void> | ||||
| struct has_member_fn_begin_end_t : std::false_type {}; | ||||
| 
 | ||||
| template <typename T> | ||||
| struct has_member_fn_begin_end_t<T, void_t<decltype(std::declval<T>().begin()), | ||||
|                                            decltype(std::declval<T>().end())>> | ||||
|     : std::true_type {}; | ||||
| 
 | ||||
| // Member function overload
 | ||||
| template <typename T> | ||||
| auto range_begin(T&& rng) FMT_DECLTYPE_RETURN(static_cast<T&&>(rng).begin()); | ||||
| template <typename T> | ||||
| auto range_end(T&& rng) FMT_DECLTYPE_RETURN(static_cast<T&&>(rng).end()); | ||||
| 
 | ||||
| // ADL overload. Only participates in overload resolution if member functions
 | ||||
| // are not found.
 | ||||
| template <typename T> | ||||
| auto range_begin(T&& rng) | ||||
|     -> enable_if_t<!has_member_fn_begin_end_t<T&&>::value, | ||||
|                    decltype(begin(static_cast<T&&>(rng)))> { | ||||
|   return begin(static_cast<T&&>(rng)); | ||||
| } | ||||
| template <typename T> | ||||
| auto range_end(T&& rng) -> enable_if_t<!has_member_fn_begin_end_t<T&&>::value, | ||||
|                                        decltype(end(static_cast<T&&>(rng)))> { | ||||
|   return end(static_cast<T&&>(rng)); | ||||
| } | ||||
| 
 | ||||
| template <typename T, typename Enable = void> | ||||
| struct has_const_begin_end : std::false_type {}; | ||||
| template <typename T, typename Enable = void> | ||||
| struct has_mutable_begin_end : std::false_type {}; | ||||
| 
 | ||||
| template <typename T> | ||||
| struct has_const_begin_end< | ||||
|     T, | ||||
|     void_t< | ||||
|         decltype(detail::range_begin(std::declval<const remove_cvref_t<T>&>())), | ||||
|         decltype(detail::range_end(std::declval<const remove_cvref_t<T>&>()))>> | ||||
|     : std::true_type {}; | ||||
| 
 | ||||
| template <typename T> | ||||
| struct has_mutable_begin_end< | ||||
|     T, void_t<decltype(detail::range_begin(std::declval<T>())), | ||||
|               decltype(detail::range_end(std::declval<T>())), | ||||
|               enable_if_t<std::is_copy_constructible<T>::value>>> | ||||
|     : std::true_type {}; | ||||
| 
 | ||||
| template <typename T> | ||||
| struct is_range_<T, void> | ||||
|     : std::integral_constant<bool, (has_const_begin_end<T>::value || | ||||
|                                     has_mutable_begin_end<T>::value)> {}; | ||||
| #  undef FMT_DECLTYPE_RETURN | ||||
| #endif | ||||
| 
 | ||||
| // tuple_size and tuple_element check.
 | ||||
| template <typename T> class is_tuple_like_ { | ||||
|   template <typename U> | ||||
|   static auto check(U* p) -> decltype(std::tuple_size<U>::value, int()); | ||||
|   template <typename> static void check(...); | ||||
| 
 | ||||
|  public: | ||||
|   static FMT_CONSTEXPR_DECL const bool value = | ||||
|       !std::is_void<decltype(check<T>(nullptr))>::value; | ||||
| }; | ||||
| 
 | ||||
| // Check for integer_sequence
 | ||||
| #if defined(__cpp_lib_integer_sequence) || FMT_MSC_VER >= 1900 | ||||
| template <typename T, T... N> | ||||
| using integer_sequence = std::integer_sequence<T, N...>; | ||||
| template <size_t... N> using index_sequence = std::index_sequence<N...>; | ||||
| template <size_t N> using make_index_sequence = std::make_index_sequence<N>; | ||||
| #else | ||||
| template <typename T, T... N> struct integer_sequence { | ||||
|   using value_type = T; | ||||
| 
 | ||||
|   static FMT_CONSTEXPR size_t size() { return sizeof...(N); } | ||||
| }; | ||||
| 
 | ||||
| template <size_t... N> using index_sequence = integer_sequence<size_t, N...>; | ||||
| 
 | ||||
| template <typename T, size_t N, T... Ns> | ||||
| struct make_integer_sequence : make_integer_sequence<T, N - 1, N - 1, Ns...> {}; | ||||
| template <typename T, T... Ns> | ||||
| struct make_integer_sequence<T, 0, Ns...> : integer_sequence<T, Ns...> {}; | ||||
| 
 | ||||
| template <size_t N> | ||||
| using make_index_sequence = make_integer_sequence<size_t, N>; | ||||
| #endif | ||||
| 
 | ||||
| template <class Tuple, class F, size_t... Is> | ||||
| void for_each(index_sequence<Is...>, Tuple&& tup, F&& f) FMT_NOEXCEPT { | ||||
|   using std::get; | ||||
|   // using free function get<I>(T) now.
 | ||||
|   const int _[] = {0, ((void)f(get<Is>(tup)), 0)...}; | ||||
|   (void)_;  // blocks warnings
 | ||||
| } | ||||
| 
 | ||||
| template <class T> | ||||
| FMT_CONSTEXPR make_index_sequence<std::tuple_size<T>::value> get_indexes( | ||||
|     T const&) { | ||||
|   return {}; | ||||
| } | ||||
| 
 | ||||
| template <class Tuple, class F> void for_each(Tuple&& tup, F&& f) { | ||||
|   const auto indexes = get_indexes(tup); | ||||
|   for_each(indexes, std::forward<Tuple>(tup), std::forward<F>(f)); | ||||
| } | ||||
| 
 | ||||
| template <typename Range> | ||||
| using value_type = | ||||
|     remove_cvref_t<decltype(*detail::range_begin(std::declval<Range>()))>; | ||||
| 
 | ||||
| template <typename OutputIt> OutputIt write_delimiter(OutputIt out) { | ||||
|   *out++ = ','; | ||||
|   *out++ = ' '; | ||||
|   return out; | ||||
| } | ||||
| 
 | ||||
| struct singleton { | ||||
|   unsigned char upper; | ||||
|   unsigned char lower_count; | ||||
| }; | ||||
| 
 | ||||
| inline auto is_printable(uint16_t x, const singleton* singletons, | ||||
|                          size_t singletons_size, | ||||
|                          const unsigned char* singleton_lowers, | ||||
|                          const unsigned char* normal, size_t normal_size) | ||||
|     -> bool { | ||||
|   auto upper = x >> 8; | ||||
|   auto lower_start = 0; | ||||
|   for (size_t i = 0; i < singletons_size; ++i) { | ||||
|     auto s = singletons[i]; | ||||
|     auto lower_end = lower_start + s.lower_count; | ||||
|     if (upper < s.upper) break; | ||||
|     if (upper == s.upper) { | ||||
|       for (auto j = lower_start; j < lower_end; ++j) { | ||||
|         if (singleton_lowers[j] == (x & 0xff)) return false; | ||||
|       } | ||||
|     } | ||||
|     lower_start = lower_end; | ||||
|   } | ||||
| 
 | ||||
|   auto xsigned = static_cast<int>(x); | ||||
|   auto current = true; | ||||
|   for (size_t i = 0; i < normal_size; ++i) { | ||||
|     auto v = static_cast<int>(normal[i]); | ||||
|     auto len = (v & 0x80) != 0 ? (v & 0x7f) << 8 | normal[++i] : v; | ||||
|     xsigned -= len; | ||||
|     if (xsigned < 0) break; | ||||
|     current = !current; | ||||
|   } | ||||
|   return current; | ||||
| } | ||||
| 
 | ||||
| // Returns true iff the code point cp is printable.
 | ||||
| // This code is generated by support/printable.py.
 | ||||
| inline auto is_printable(uint32_t cp) -> bool { | ||||
|   static constexpr singleton singletons0[] = { | ||||
|       {0x00, 1},  {0x03, 5},  {0x05, 6},  {0x06, 3},  {0x07, 6},  {0x08, 8}, | ||||
|       {0x09, 17}, {0x0a, 28}, {0x0b, 25}, {0x0c, 20}, {0x0d, 16}, {0x0e, 13}, | ||||
|       {0x0f, 4},  {0x10, 3},  {0x12, 18}, {0x13, 9},  {0x16, 1},  {0x17, 5}, | ||||
|       {0x18, 2},  {0x19, 3},  {0x1a, 7},  {0x1c, 2},  {0x1d, 1},  {0x1f, 22}, | ||||
|       {0x20, 3},  {0x2b, 3},  {0x2c, 2},  {0x2d, 11}, {0x2e, 1},  {0x30, 3}, | ||||
|       {0x31, 2},  {0x32, 1},  {0xa7, 2},  {0xa9, 2},  {0xaa, 4},  {0xab, 8}, | ||||
|       {0xfa, 2},  {0xfb, 5},  {0xfd, 4},  {0xfe, 3},  {0xff, 9}, | ||||
|   }; | ||||
|   static constexpr unsigned char singletons0_lower[] = { | ||||
|       0xad, 0x78, 0x79, 0x8b, 0x8d, 0xa2, 0x30, 0x57, 0x58, 0x8b, 0x8c, 0x90, | ||||
|       0x1c, 0x1d, 0xdd, 0x0e, 0x0f, 0x4b, 0x4c, 0xfb, 0xfc, 0x2e, 0x2f, 0x3f, | ||||
|       0x5c, 0x5d, 0x5f, 0xb5, 0xe2, 0x84, 0x8d, 0x8e, 0x91, 0x92, 0xa9, 0xb1, | ||||
|       0xba, 0xbb, 0xc5, 0xc6, 0xc9, 0xca, 0xde, 0xe4, 0xe5, 0xff, 0x00, 0x04, | ||||
|       0x11, 0x12, 0x29, 0x31, 0x34, 0x37, 0x3a, 0x3b, 0x3d, 0x49, 0x4a, 0x5d, | ||||
|       0x84, 0x8e, 0x92, 0xa9, 0xb1, 0xb4, 0xba, 0xbb, 0xc6, 0xca, 0xce, 0xcf, | ||||
|       0xe4, 0xe5, 0x00, 0x04, 0x0d, 0x0e, 0x11, 0x12, 0x29, 0x31, 0x34, 0x3a, | ||||
|       0x3b, 0x45, 0x46, 0x49, 0x4a, 0x5e, 0x64, 0x65, 0x84, 0x91, 0x9b, 0x9d, | ||||
|       0xc9, 0xce, 0xcf, 0x0d, 0x11, 0x29, 0x45, 0x49, 0x57, 0x64, 0x65, 0x8d, | ||||
|       0x91, 0xa9, 0xb4, 0xba, 0xbb, 0xc5, 0xc9, 0xdf, 0xe4, 0xe5, 0xf0, 0x0d, | ||||
|       0x11, 0x45, 0x49, 0x64, 0x65, 0x80, 0x84, 0xb2, 0xbc, 0xbe, 0xbf, 0xd5, | ||||
|       0xd7, 0xf0, 0xf1, 0x83, 0x85, 0x8b, 0xa4, 0xa6, 0xbe, 0xbf, 0xc5, 0xc7, | ||||
|       0xce, 0xcf, 0xda, 0xdb, 0x48, 0x98, 0xbd, 0xcd, 0xc6, 0xce, 0xcf, 0x49, | ||||
|       0x4e, 0x4f, 0x57, 0x59, 0x5e, 0x5f, 0x89, 0x8e, 0x8f, 0xb1, 0xb6, 0xb7, | ||||
|       0xbf, 0xc1, 0xc6, 0xc7, 0xd7, 0x11, 0x16, 0x17, 0x5b, 0x5c, 0xf6, 0xf7, | ||||
|       0xfe, 0xff, 0x80, 0x0d, 0x6d, 0x71, 0xde, 0xdf, 0x0e, 0x0f, 0x1f, 0x6e, | ||||
|       0x6f, 0x1c, 0x1d, 0x5f, 0x7d, 0x7e, 0xae, 0xaf, 0xbb, 0xbc, 0xfa, 0x16, | ||||
|       0x17, 0x1e, 0x1f, 0x46, 0x47, 0x4e, 0x4f, 0x58, 0x5a, 0x5c, 0x5e, 0x7e, | ||||
|       0x7f, 0xb5, 0xc5, 0xd4, 0xd5, 0xdc, 0xf0, 0xf1, 0xf5, 0x72, 0x73, 0x8f, | ||||
|       0x74, 0x75, 0x96, 0x2f, 0x5f, 0x26, 0x2e, 0x2f, 0xa7, 0xaf, 0xb7, 0xbf, | ||||
|       0xc7, 0xcf, 0xd7, 0xdf, 0x9a, 0x40, 0x97, 0x98, 0x30, 0x8f, 0x1f, 0xc0, | ||||
|       0xc1, 0xce, 0xff, 0x4e, 0x4f, 0x5a, 0x5b, 0x07, 0x08, 0x0f, 0x10, 0x27, | ||||
|       0x2f, 0xee, 0xef, 0x6e, 0x6f, 0x37, 0x3d, 0x3f, 0x42, 0x45, 0x90, 0x91, | ||||
|       0xfe, 0xff, 0x53, 0x67, 0x75, 0xc8, 0xc9, 0xd0, 0xd1, 0xd8, 0xd9, 0xe7, | ||||
|       0xfe, 0xff, | ||||
|   }; | ||||
|   static constexpr singleton singletons1[] = { | ||||
|       {0x00, 6},  {0x01, 1}, {0x03, 1},  {0x04, 2}, {0x08, 8},  {0x09, 2}, | ||||
|       {0x0a, 5},  {0x0b, 2}, {0x0e, 4},  {0x10, 1}, {0x11, 2},  {0x12, 5}, | ||||
|       {0x13, 17}, {0x14, 1}, {0x15, 2},  {0x17, 2}, {0x19, 13}, {0x1c, 5}, | ||||
|       {0x1d, 8},  {0x24, 1}, {0x6a, 3},  {0x6b, 2}, {0xbc, 2},  {0xd1, 2}, | ||||
|       {0xd4, 12}, {0xd5, 9}, {0xd6, 2},  {0xd7, 2}, {0xda, 1},  {0xe0, 5}, | ||||
|       {0xe1, 2},  {0xe8, 2}, {0xee, 32}, {0xf0, 4}, {0xf8, 2},  {0xf9, 2}, | ||||
|       {0xfa, 2},  {0xfb, 1}, | ||||
|   }; | ||||
|   static constexpr unsigned char singletons1_lower[] = { | ||||
|       0x0c, 0x27, 0x3b, 0x3e, 0x4e, 0x4f, 0x8f, 0x9e, 0x9e, 0x9f, 0x06, 0x07, | ||||
|       0x09, 0x36, 0x3d, 0x3e, 0x56, 0xf3, 0xd0, 0xd1, 0x04, 0x14, 0x18, 0x36, | ||||
|       0x37, 0x56, 0x57, 0x7f, 0xaa, 0xae, 0xaf, 0xbd, 0x35, 0xe0, 0x12, 0x87, | ||||
|       0x89, 0x8e, 0x9e, 0x04, 0x0d, 0x0e, 0x11, 0x12, 0x29, 0x31, 0x34, 0x3a, | ||||
|       0x45, 0x46, 0x49, 0x4a, 0x4e, 0x4f, 0x64, 0x65, 0x5c, 0xb6, 0xb7, 0x1b, | ||||
|       0x1c, 0x07, 0x08, 0x0a, 0x0b, 0x14, 0x17, 0x36, 0x39, 0x3a, 0xa8, 0xa9, | ||||
|       0xd8, 0xd9, 0x09, 0x37, 0x90, 0x91, 0xa8, 0x07, 0x0a, 0x3b, 0x3e, 0x66, | ||||
|       0x69, 0x8f, 0x92, 0x6f, 0x5f, 0xee, 0xef, 0x5a, 0x62, 0x9a, 0x9b, 0x27, | ||||
|       0x28, 0x55, 0x9d, 0xa0, 0xa1, 0xa3, 0xa4, 0xa7, 0xa8, 0xad, 0xba, 0xbc, | ||||
|       0xc4, 0x06, 0x0b, 0x0c, 0x15, 0x1d, 0x3a, 0x3f, 0x45, 0x51, 0xa6, 0xa7, | ||||
|       0xcc, 0xcd, 0xa0, 0x07, 0x19, 0x1a, 0x22, 0x25, 0x3e, 0x3f, 0xc5, 0xc6, | ||||
|       0x04, 0x20, 0x23, 0x25, 0x26, 0x28, 0x33, 0x38, 0x3a, 0x48, 0x4a, 0x4c, | ||||
|       0x50, 0x53, 0x55, 0x56, 0x58, 0x5a, 0x5c, 0x5e, 0x60, 0x63, 0x65, 0x66, | ||||
|       0x6b, 0x73, 0x78, 0x7d, 0x7f, 0x8a, 0xa4, 0xaa, 0xaf, 0xb0, 0xc0, 0xd0, | ||||
|       0xae, 0xaf, 0x79, 0xcc, 0x6e, 0x6f, 0x93, | ||||
|   }; | ||||
|   static constexpr unsigned char normal0[] = { | ||||
|       0x00, 0x20, 0x5f, 0x22, 0x82, 0xdf, 0x04, 0x82, 0x44, 0x08, 0x1b, 0x04, | ||||
|       0x06, 0x11, 0x81, 0xac, 0x0e, 0x80, 0xab, 0x35, 0x28, 0x0b, 0x80, 0xe0, | ||||
|       0x03, 0x19, 0x08, 0x01, 0x04, 0x2f, 0x04, 0x34, 0x04, 0x07, 0x03, 0x01, | ||||
|       0x07, 0x06, 0x07, 0x11, 0x0a, 0x50, 0x0f, 0x12, 0x07, 0x55, 0x07, 0x03, | ||||
|       0x04, 0x1c, 0x0a, 0x09, 0x03, 0x08, 0x03, 0x07, 0x03, 0x02, 0x03, 0x03, | ||||
|       0x03, 0x0c, 0x04, 0x05, 0x03, 0x0b, 0x06, 0x01, 0x0e, 0x15, 0x05, 0x3a, | ||||
|       0x03, 0x11, 0x07, 0x06, 0x05, 0x10, 0x07, 0x57, 0x07, 0x02, 0x07, 0x15, | ||||
|       0x0d, 0x50, 0x04, 0x43, 0x03, 0x2d, 0x03, 0x01, 0x04, 0x11, 0x06, 0x0f, | ||||
|       0x0c, 0x3a, 0x04, 0x1d, 0x25, 0x5f, 0x20, 0x6d, 0x04, 0x6a, 0x25, 0x80, | ||||
|       0xc8, 0x05, 0x82, 0xb0, 0x03, 0x1a, 0x06, 0x82, 0xfd, 0x03, 0x59, 0x07, | ||||
|       0x15, 0x0b, 0x17, 0x09, 0x14, 0x0c, 0x14, 0x0c, 0x6a, 0x06, 0x0a, 0x06, | ||||
|       0x1a, 0x06, 0x59, 0x07, 0x2b, 0x05, 0x46, 0x0a, 0x2c, 0x04, 0x0c, 0x04, | ||||
|       0x01, 0x03, 0x31, 0x0b, 0x2c, 0x04, 0x1a, 0x06, 0x0b, 0x03, 0x80, 0xac, | ||||
|       0x06, 0x0a, 0x06, 0x21, 0x3f, 0x4c, 0x04, 0x2d, 0x03, 0x74, 0x08, 0x3c, | ||||
|       0x03, 0x0f, 0x03, 0x3c, 0x07, 0x38, 0x08, 0x2b, 0x05, 0x82, 0xff, 0x11, | ||||
|       0x18, 0x08, 0x2f, 0x11, 0x2d, 0x03, 0x20, 0x10, 0x21, 0x0f, 0x80, 0x8c, | ||||
|       0x04, 0x82, 0x97, 0x19, 0x0b, 0x15, 0x88, 0x94, 0x05, 0x2f, 0x05, 0x3b, | ||||
|       0x07, 0x02, 0x0e, 0x18, 0x09, 0x80, 0xb3, 0x2d, 0x74, 0x0c, 0x80, 0xd6, | ||||
|       0x1a, 0x0c, 0x05, 0x80, 0xff, 0x05, 0x80, 0xdf, 0x0c, 0xee, 0x0d, 0x03, | ||||
|       0x84, 0x8d, 0x03, 0x37, 0x09, 0x81, 0x5c, 0x14, 0x80, 0xb8, 0x08, 0x80, | ||||
|       0xcb, 0x2a, 0x38, 0x03, 0x0a, 0x06, 0x38, 0x08, 0x46, 0x08, 0x0c, 0x06, | ||||
|       0x74, 0x0b, 0x1e, 0x03, 0x5a, 0x04, 0x59, 0x09, 0x80, 0x83, 0x18, 0x1c, | ||||
|       0x0a, 0x16, 0x09, 0x4c, 0x04, 0x80, 0x8a, 0x06, 0xab, 0xa4, 0x0c, 0x17, | ||||
|       0x04, 0x31, 0xa1, 0x04, 0x81, 0xda, 0x26, 0x07, 0x0c, 0x05, 0x05, 0x80, | ||||
|       0xa5, 0x11, 0x81, 0x6d, 0x10, 0x78, 0x28, 0x2a, 0x06, 0x4c, 0x04, 0x80, | ||||
|       0x8d, 0x04, 0x80, 0xbe, 0x03, 0x1b, 0x03, 0x0f, 0x0d, | ||||
|   }; | ||||
|   static constexpr unsigned char normal1[] = { | ||||
|       0x5e, 0x22, 0x7b, 0x05, 0x03, 0x04, 0x2d, 0x03, 0x66, 0x03, 0x01, 0x2f, | ||||
|       0x2e, 0x80, 0x82, 0x1d, 0x03, 0x31, 0x0f, 0x1c, 0x04, 0x24, 0x09, 0x1e, | ||||
|       0x05, 0x2b, 0x05, 0x44, 0x04, 0x0e, 0x2a, 0x80, 0xaa, 0x06, 0x24, 0x04, | ||||
|       0x24, 0x04, 0x28, 0x08, 0x34, 0x0b, 0x01, 0x80, 0x90, 0x81, 0x37, 0x09, | ||||
|       0x16, 0x0a, 0x08, 0x80, 0x98, 0x39, 0x03, 0x63, 0x08, 0x09, 0x30, 0x16, | ||||
|       0x05, 0x21, 0x03, 0x1b, 0x05, 0x01, 0x40, 0x38, 0x04, 0x4b, 0x05, 0x2f, | ||||
|       0x04, 0x0a, 0x07, 0x09, 0x07, 0x40, 0x20, 0x27, 0x04, 0x0c, 0x09, 0x36, | ||||
|       0x03, 0x3a, 0x05, 0x1a, 0x07, 0x04, 0x0c, 0x07, 0x50, 0x49, 0x37, 0x33, | ||||
|       0x0d, 0x33, 0x07, 0x2e, 0x08, 0x0a, 0x81, 0x26, 0x52, 0x4e, 0x28, 0x08, | ||||
|       0x2a, 0x56, 0x1c, 0x14, 0x17, 0x09, 0x4e, 0x04, 0x1e, 0x0f, 0x43, 0x0e, | ||||
|       0x19, 0x07, 0x0a, 0x06, 0x48, 0x08, 0x27, 0x09, 0x75, 0x0b, 0x3f, 0x41, | ||||
|       0x2a, 0x06, 0x3b, 0x05, 0x0a, 0x06, 0x51, 0x06, 0x01, 0x05, 0x10, 0x03, | ||||
|       0x05, 0x80, 0x8b, 0x62, 0x1e, 0x48, 0x08, 0x0a, 0x80, 0xa6, 0x5e, 0x22, | ||||
|       0x45, 0x0b, 0x0a, 0x06, 0x0d, 0x13, 0x39, 0x07, 0x0a, 0x36, 0x2c, 0x04, | ||||
|       0x10, 0x80, 0xc0, 0x3c, 0x64, 0x53, 0x0c, 0x48, 0x09, 0x0a, 0x46, 0x45, | ||||
|       0x1b, 0x48, 0x08, 0x53, 0x1d, 0x39, 0x81, 0x07, 0x46, 0x0a, 0x1d, 0x03, | ||||
|       0x47, 0x49, 0x37, 0x03, 0x0e, 0x08, 0x0a, 0x06, 0x39, 0x07, 0x0a, 0x81, | ||||
|       0x36, 0x19, 0x80, 0xb7, 0x01, 0x0f, 0x32, 0x0d, 0x83, 0x9b, 0x66, 0x75, | ||||
|       0x0b, 0x80, 0xc4, 0x8a, 0xbc, 0x84, 0x2f, 0x8f, 0xd1, 0x82, 0x47, 0xa1, | ||||
|       0xb9, 0x82, 0x39, 0x07, 0x2a, 0x04, 0x02, 0x60, 0x26, 0x0a, 0x46, 0x0a, | ||||
|       0x28, 0x05, 0x13, 0x82, 0xb0, 0x5b, 0x65, 0x4b, 0x04, 0x39, 0x07, 0x11, | ||||
|       0x40, 0x05, 0x0b, 0x02, 0x0e, 0x97, 0xf8, 0x08, 0x84, 0xd6, 0x2a, 0x09, | ||||
|       0xa2, 0xf7, 0x81, 0x1f, 0x31, 0x03, 0x11, 0x04, 0x08, 0x81, 0x8c, 0x89, | ||||
|       0x04, 0x6b, 0x05, 0x0d, 0x03, 0x09, 0x07, 0x10, 0x93, 0x60, 0x80, 0xf6, | ||||
|       0x0a, 0x73, 0x08, 0x6e, 0x17, 0x46, 0x80, 0x9a, 0x14, 0x0c, 0x57, 0x09, | ||||
|       0x19, 0x80, 0x87, 0x81, 0x47, 0x03, 0x85, 0x42, 0x0f, 0x15, 0x85, 0x50, | ||||
|       0x2b, 0x80, 0xd5, 0x2d, 0x03, 0x1a, 0x04, 0x02, 0x81, 0x70, 0x3a, 0x05, | ||||
|       0x01, 0x85, 0x00, 0x80, 0xd7, 0x29, 0x4c, 0x04, 0x0a, 0x04, 0x02, 0x83, | ||||
|       0x11, 0x44, 0x4c, 0x3d, 0x80, 0xc2, 0x3c, 0x06, 0x01, 0x04, 0x55, 0x05, | ||||
|       0x1b, 0x34, 0x02, 0x81, 0x0e, 0x2c, 0x04, 0x64, 0x0c, 0x56, 0x0a, 0x80, | ||||
|       0xae, 0x38, 0x1d, 0x0d, 0x2c, 0x04, 0x09, 0x07, 0x02, 0x0e, 0x06, 0x80, | ||||
|       0x9a, 0x83, 0xd8, 0x08, 0x0d, 0x03, 0x0d, 0x03, 0x74, 0x0c, 0x59, 0x07, | ||||
|       0x0c, 0x14, 0x0c, 0x04, 0x38, 0x08, 0x0a, 0x06, 0x28, 0x08, 0x22, 0x4e, | ||||
|       0x81, 0x54, 0x0c, 0x15, 0x03, 0x03, 0x05, 0x07, 0x09, 0x19, 0x07, 0x07, | ||||
|       0x09, 0x03, 0x0d, 0x07, 0x29, 0x80, 0xcb, 0x25, 0x0a, 0x84, 0x06, | ||||
|   }; | ||||
|   auto lower = static_cast<uint16_t>(cp); | ||||
|   if (cp < 0x10000) { | ||||
|     return is_printable(lower, singletons0, | ||||
|                         sizeof(singletons0) / sizeof(*singletons0), | ||||
|                         singletons0_lower, normal0, sizeof(normal0)); | ||||
|   } | ||||
|   if (cp < 0x20000) { | ||||
|     return is_printable(lower, singletons1, | ||||
|                         sizeof(singletons1) / sizeof(*singletons1), | ||||
|                         singletons1_lower, normal1, sizeof(normal1)); | ||||
|   } | ||||
|   if (0x2a6de <= cp && cp < 0x2a700) return false; | ||||
|   if (0x2b735 <= cp && cp < 0x2b740) return false; | ||||
|   if (0x2b81e <= cp && cp < 0x2b820) return false; | ||||
|   if (0x2cea2 <= cp && cp < 0x2ceb0) return false; | ||||
|   if (0x2ebe1 <= cp && cp < 0x2f800) return false; | ||||
|   if (0x2fa1e <= cp && cp < 0x30000) return false; | ||||
|   if (0x3134b <= cp && cp < 0xe0100) return false; | ||||
|   if (0xe01f0 <= cp && cp < 0x110000) return false; | ||||
|   return cp < 0x110000; | ||||
| } | ||||
| 
 | ||||
| inline auto needs_escape(uint32_t cp) -> bool { | ||||
|   return cp < 0x20 || cp == 0x7f || cp == '"' || cp == '\\' || | ||||
|          !is_printable(cp); | ||||
| } | ||||
| 
 | ||||
| template <typename Char> struct find_escape_result { | ||||
|   const Char* begin; | ||||
|   const Char* end; | ||||
|   uint32_t cp; | ||||
| }; | ||||
| 
 | ||||
| template <typename Char> | ||||
| auto find_escape(const Char* begin, const Char* end) | ||||
|     -> find_escape_result<Char> { | ||||
|   for (; begin != end; ++begin) { | ||||
|     auto cp = static_cast<typename std::make_unsigned<Char>::type>(*begin); | ||||
|     if (sizeof(Char) == 1 && cp >= 0x80) continue; | ||||
|     if (needs_escape(cp)) return {begin, begin + 1, cp}; | ||||
|   } | ||||
|   return {begin, nullptr, 0}; | ||||
| } | ||||
| 
 | ||||
| inline auto find_escape(const char* begin, const char* end) | ||||
|     -> find_escape_result<char> { | ||||
|   if (!is_utf8()) return find_escape<char>(begin, end); | ||||
|   auto result = find_escape_result<char>{end, nullptr, 0}; | ||||
|   for_each_codepoint(string_view(begin, to_unsigned(end - begin)), | ||||
|                      [&](uint32_t cp, string_view sv) { | ||||
|                        if (needs_escape(cp)) { | ||||
|                          result = {sv.begin(), sv.end(), cp}; | ||||
|                          return false; | ||||
|                        } | ||||
|                        return true; | ||||
|                      }); | ||||
|   return result; | ||||
| } | ||||
| 
 | ||||
| template <typename Char, typename OutputIt> | ||||
| auto write_range_entry(OutputIt out, basic_string_view<Char> str) -> OutputIt { | ||||
|   *out++ = '"'; | ||||
|   auto begin = str.begin(), end = str.end(); | ||||
|   do { | ||||
|     auto escape = find_escape(begin, end); | ||||
|     out = copy_str<Char>(begin, escape.begin, out); | ||||
|     begin = escape.end; | ||||
|     if (!begin) break; | ||||
|     auto c = static_cast<Char>(escape.cp); | ||||
|     switch (escape.cp) { | ||||
|     case '\n': | ||||
|       *out++ = '\\'; | ||||
|       c = 'n'; | ||||
|       break; | ||||
|     case '\r': | ||||
|       *out++ = '\\'; | ||||
|       c = 'r'; | ||||
|       break; | ||||
|     case '\t': | ||||
|       *out++ = '\\'; | ||||
|       c = 't'; | ||||
|       break; | ||||
|     case '"': | ||||
|       FMT_FALLTHROUGH; | ||||
|     case '\\': | ||||
|       *out++ = '\\'; | ||||
|       break; | ||||
|     default: | ||||
|       if (is_utf8()) { | ||||
|         if (escape.cp < 0x100) { | ||||
|           out = format_to(out, "\\x{:02x}", escape.cp); | ||||
|           continue; | ||||
|         } | ||||
|         if (escape.cp < 0x10000) { | ||||
|           out = format_to(out, "\\u{:04x}", escape.cp); | ||||
|           continue; | ||||
|         } | ||||
|         if (escape.cp < 0x110000) { | ||||
|           out = format_to(out, "\\U{:08x}", escape.cp); | ||||
|           continue; | ||||
|         } | ||||
|       } | ||||
|       for (Char escape_char : basic_string_view<Char>( | ||||
|                escape.begin, to_unsigned(escape.end - escape.begin))) { | ||||
|         out = format_to( | ||||
|             out, "\\x{:02x}", | ||||
|             static_cast<typename std::make_unsigned<Char>::type>(escape_char)); | ||||
|       } | ||||
|       continue; | ||||
|     } | ||||
|     *out++ = c; | ||||
|   } while (begin != end); | ||||
|   *out++ = '"'; | ||||
|   return out; | ||||
| } | ||||
| 
 | ||||
| template <typename Char, typename OutputIt, typename T, | ||||
|           FMT_ENABLE_IF(std::is_convertible<T, std_string_view<char>>::value)> | ||||
| inline auto write_range_entry(OutputIt out, const T& str) -> OutputIt { | ||||
|   auto sv = std_string_view<Char>(str); | ||||
|   return write_range_entry<Char>(out, basic_string_view<Char>(sv)); | ||||
| } | ||||
| 
 | ||||
| template <typename Char, typename OutputIt, typename Arg, | ||||
|           FMT_ENABLE_IF(std::is_same<Arg, Char>::value)> | ||||
| OutputIt write_range_entry(OutputIt out, const Arg v) { | ||||
|   *out++ = '\''; | ||||
|   *out++ = v; | ||||
|   *out++ = '\''; | ||||
|   return out; | ||||
| } | ||||
| 
 | ||||
| template < | ||||
|     typename Char, typename OutputIt, typename Arg, | ||||
|     FMT_ENABLE_IF(!is_std_string_like<typename std::decay<Arg>::type>::value && | ||||
|                   !std::is_same<Arg, Char>::value)> | ||||
| OutputIt write_range_entry(OutputIt out, const Arg& v) { | ||||
|   return write<Char>(out, v); | ||||
| } | ||||
| 
 | ||||
| }  // namespace detail
 | ||||
| 
 | ||||
| template <typename T> struct is_tuple_like { | ||||
|   static FMT_CONSTEXPR_DECL const bool value = | ||||
|       detail::is_tuple_like_<T>::value && !detail::is_range_<T>::value; | ||||
| }; | ||||
| 
 | ||||
| template <typename TupleT, typename Char> | ||||
| struct formatter<TupleT, Char, enable_if_t<fmt::is_tuple_like<TupleT>::value>> { | ||||
|  private: | ||||
|   // C++11 generic lambda for format().
 | ||||
|   template <typename FormatContext> struct format_each { | ||||
|     template <typename T> void operator()(const T& v) { | ||||
|       if (i > 0) out = detail::write_delimiter(out); | ||||
|       out = detail::write_range_entry<Char>(out, v); | ||||
|       ++i; | ||||
|     } | ||||
|     int i; | ||||
|     typename FormatContext::iterator& out; | ||||
|   }; | ||||
| 
 | ||||
|  public: | ||||
|   template <typename ParseContext> | ||||
|   FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { | ||||
|     return ctx.begin(); | ||||
|   } | ||||
| 
 | ||||
|   template <typename FormatContext = format_context> | ||||
|   auto format(const TupleT& values, FormatContext& ctx) -> decltype(ctx.out()) { | ||||
|     auto out = ctx.out(); | ||||
|     *out++ = '('; | ||||
|     detail::for_each(values, format_each<FormatContext>{0, out}); | ||||
|     *out++ = ')'; | ||||
|     return out; | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| template <typename T, typename Char> struct is_range { | ||||
|   static FMT_CONSTEXPR_DECL const bool value = | ||||
|       detail::is_range_<T>::value && !detail::is_std_string_like<T>::value && | ||||
|       !detail::is_map<T>::value && | ||||
|       !std::is_convertible<T, std::basic_string<Char>>::value && | ||||
|       !std::is_constructible<detail::std_string_view<Char>, T>::value; | ||||
| }; | ||||
| 
 | ||||
| template <typename T, typename Char> | ||||
| struct formatter< | ||||
|     T, Char, | ||||
|     enable_if_t< | ||||
|         fmt::is_range<T, Char>::value | ||||
| // Workaround a bug in MSVC 2019 and earlier.
 | ||||
| #if !FMT_MSC_VER | ||||
|         && (is_formattable<detail::value_type<T>, Char>::value || | ||||
|             detail::has_fallback_formatter<detail::value_type<T>, Char>::value) | ||||
| #endif | ||||
|         >> { | ||||
|   template <typename ParseContext> | ||||
|   FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { | ||||
|     return ctx.begin(); | ||||
|   } | ||||
| 
 | ||||
|   template < | ||||
|       typename FormatContext, typename U, | ||||
|       FMT_ENABLE_IF( | ||||
|           std::is_same<U, conditional_t<detail::has_const_begin_end<T>::value, | ||||
|                                         const T, T>>::value)> | ||||
|   auto format(U& range, FormatContext& ctx) -> decltype(ctx.out()) { | ||||
| #ifdef FMT_DEPRECATED_BRACED_RANGES | ||||
|     Char prefix = '{'; | ||||
|     Char postfix = '}'; | ||||
| #else | ||||
|     Char prefix = detail::is_set<T>::value ? '{' : '['; | ||||
|     Char postfix = detail::is_set<T>::value ? '}' : ']'; | ||||
| #endif | ||||
|     auto out = ctx.out(); | ||||
|     *out++ = prefix; | ||||
|     int i = 0; | ||||
|     auto it = std::begin(range); | ||||
|     auto end = std::end(range); | ||||
|     for (; it != end; ++it) { | ||||
|       if (i > 0) out = detail::write_delimiter(out); | ||||
|       out = detail::write_range_entry<Char>(out, *it); | ||||
|       ++i; | ||||
|     } | ||||
|     *out++ = postfix; | ||||
|     return out; | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| template <typename T, typename Char> | ||||
| struct formatter< | ||||
|     T, Char, | ||||
|     enable_if_t< | ||||
|         detail::is_map<T>::value | ||||
| // Workaround a bug in MSVC 2019 and earlier.
 | ||||
| #if !FMT_MSC_VER | ||||
|         && (is_formattable<detail::value_type<T>, Char>::value || | ||||
|             detail::has_fallback_formatter<detail::value_type<T>, Char>::value) | ||||
| #endif | ||||
|         >> { | ||||
|   template <typename ParseContext> | ||||
|   FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { | ||||
|     return ctx.begin(); | ||||
|   } | ||||
| 
 | ||||
|   template < | ||||
|       typename FormatContext, typename U, | ||||
|       FMT_ENABLE_IF( | ||||
|           std::is_same<U, conditional_t<detail::has_const_begin_end<T>::value, | ||||
|                                         const T, T>>::value)> | ||||
|   auto format(U& map, FormatContext& ctx) -> decltype(ctx.out()) { | ||||
|     auto out = ctx.out(); | ||||
|     *out++ = '{'; | ||||
|     int i = 0; | ||||
|     for (const auto& item : map) { | ||||
|       if (i > 0) out = detail::write_delimiter(out); | ||||
|       out = detail::write_range_entry<Char>(out, item.first); | ||||
|       *out++ = ':'; | ||||
|       *out++ = ' '; | ||||
|       out = detail::write_range_entry<Char>(out, item.second); | ||||
|       ++i; | ||||
|     } | ||||
|     *out++ = '}'; | ||||
|     return out; | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| template <typename Char, typename... T> struct tuple_join_view : detail::view { | ||||
|   const std::tuple<T...>& tuple; | ||||
|   basic_string_view<Char> sep; | ||||
| 
 | ||||
|   tuple_join_view(const std::tuple<T...>& t, basic_string_view<Char> s) | ||||
|       : tuple(t), sep{s} {} | ||||
| }; | ||||
| 
 | ||||
| template <typename Char, typename... T> | ||||
| using tuple_arg_join = tuple_join_view<Char, T...>; | ||||
| 
 | ||||
| // Define FMT_TUPLE_JOIN_SPECIFIERS to enable experimental format specifiers
 | ||||
| // support in tuple_join. It is disabled by default because of issues with
 | ||||
| // the dynamic width and precision.
 | ||||
| #ifndef FMT_TUPLE_JOIN_SPECIFIERS | ||||
| #  define FMT_TUPLE_JOIN_SPECIFIERS 0 | ||||
| #endif | ||||
| 
 | ||||
| template <typename Char, typename... T> | ||||
| struct formatter<tuple_join_view<Char, T...>, Char> { | ||||
|   template <typename ParseContext> | ||||
|   FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { | ||||
|     return do_parse(ctx, std::integral_constant<size_t, sizeof...(T)>()); | ||||
|   } | ||||
| 
 | ||||
|   template <typename FormatContext> | ||||
|   auto format(const tuple_join_view<Char, T...>& value, | ||||
|               FormatContext& ctx) const -> typename FormatContext::iterator { | ||||
|     return do_format(value, ctx, | ||||
|                      std::integral_constant<size_t, sizeof...(T)>()); | ||||
|   } | ||||
| 
 | ||||
|  private: | ||||
|   std::tuple<formatter<typename std::decay<T>::type, Char>...> formatters_; | ||||
| 
 | ||||
|   template <typename ParseContext> | ||||
|   FMT_CONSTEXPR auto do_parse(ParseContext& ctx, | ||||
|                               std::integral_constant<size_t, 0>) | ||||
|       -> decltype(ctx.begin()) { | ||||
|     return ctx.begin(); | ||||
|   } | ||||
| 
 | ||||
|   template <typename ParseContext, size_t N> | ||||
|   FMT_CONSTEXPR auto do_parse(ParseContext& ctx, | ||||
|                               std::integral_constant<size_t, N>) | ||||
|       -> decltype(ctx.begin()) { | ||||
|     auto end = ctx.begin(); | ||||
| #if FMT_TUPLE_JOIN_SPECIFIERS | ||||
|     end = std::get<sizeof...(T) - N>(formatters_).parse(ctx); | ||||
|     if (N > 1) { | ||||
|       auto end1 = do_parse(ctx, std::integral_constant<size_t, N - 1>()); | ||||
|       if (end != end1) | ||||
|         FMT_THROW(format_error("incompatible format specs for tuple elements")); | ||||
|     } | ||||
| #endif | ||||
|     return end; | ||||
|   } | ||||
| 
 | ||||
|   template <typename FormatContext> | ||||
|   auto do_format(const tuple_join_view<Char, T...>&, FormatContext& ctx, | ||||
|                  std::integral_constant<size_t, 0>) const -> | ||||
|       typename FormatContext::iterator { | ||||
|     return ctx.out(); | ||||
|   } | ||||
| 
 | ||||
|   template <typename FormatContext, size_t N> | ||||
|   auto do_format(const tuple_join_view<Char, T...>& value, FormatContext& ctx, | ||||
|                  std::integral_constant<size_t, N>) const -> | ||||
|       typename FormatContext::iterator { | ||||
|     auto out = std::get<sizeof...(T) - N>(formatters_) | ||||
|                    .format(std::get<sizeof...(T) - N>(value.tuple), ctx); | ||||
|     if (N > 1) { | ||||
|       out = std::copy(value.sep.begin(), value.sep.end(), out); | ||||
|       ctx.advance_to(out); | ||||
|       return do_format(value, ctx, std::integral_constant<size_t, N - 1>()); | ||||
|     } | ||||
|     return out; | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| FMT_MODULE_EXPORT_BEGIN | ||||
| 
 | ||||
| /**
 | ||||
|   \rst | ||||
|   Returns an object that formats `tuple` with elements separated by `sep`. | ||||
| 
 | ||||
|   **Example**:: | ||||
| 
 | ||||
|     std::tuple<int, char> t = {1, 'a'}; | ||||
|     fmt::print("{}", fmt::join(t, ", ")); | ||||
|     // Output: "1, a"
 | ||||
|   \endrst | ||||
|  */ | ||||
| template <typename... T> | ||||
| FMT_CONSTEXPR auto join(const std::tuple<T...>& tuple, string_view sep) | ||||
|     -> tuple_join_view<char, T...> { | ||||
|   return {tuple, sep}; | ||||
| } | ||||
| 
 | ||||
| template <typename... T> | ||||
| FMT_CONSTEXPR auto join(const std::tuple<T...>& tuple, | ||||
|                         basic_string_view<wchar_t> sep) | ||||
|     -> tuple_join_view<wchar_t, T...> { | ||||
|   return {tuple, sep}; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|   \rst | ||||
|   Returns an object that formats `initializer_list` with elements separated by | ||||
|   `sep`. | ||||
| 
 | ||||
|   **Example**:: | ||||
| 
 | ||||
|     fmt::print("{}", fmt::join({1, 2, 3}, ", ")); | ||||
|     // Output: "1, 2, 3"
 | ||||
|   \endrst | ||||
|  */ | ||||
| template <typename T> | ||||
| auto join(std::initializer_list<T> list, string_view sep) | ||||
|     -> join_view<const T*, const T*> { | ||||
|   return join(std::begin(list), std::end(list), sep); | ||||
| } | ||||
| 
 | ||||
| FMT_MODULE_EXPORT_END | ||||
| FMT_END_NAMESPACE | ||||
| 
 | ||||
| #endif  // FMT_RANGES_H_
 | ||||
|  | @ -1,236 +0,0 @@ | |||
| // Formatting library for C++ - optional wchar_t and exotic character support
 | ||||
| //
 | ||||
| // Copyright (c) 2012 - present, Victor Zverovich
 | ||||
| // All rights reserved.
 | ||||
| //
 | ||||
| // For the license information refer to format.h.
 | ||||
| 
 | ||||
| #ifndef FMT_XCHAR_H_ | ||||
| #define FMT_XCHAR_H_ | ||||
| 
 | ||||
| #include <cwchar> | ||||
| #include <tuple> | ||||
| 
 | ||||
| #include "format.h" | ||||
| 
 | ||||
| FMT_BEGIN_NAMESPACE | ||||
| namespace detail { | ||||
| template <typename T> | ||||
| using is_exotic_char = bool_constant<!std::is_same<T, char>::value>; | ||||
| } | ||||
| 
 | ||||
| FMT_MODULE_EXPORT_BEGIN | ||||
| 
 | ||||
| using wstring_view = basic_string_view<wchar_t>; | ||||
| using wformat_parse_context = basic_format_parse_context<wchar_t>; | ||||
| using wformat_context = buffer_context<wchar_t>; | ||||
| using wformat_args = basic_format_args<wformat_context>; | ||||
| using wmemory_buffer = basic_memory_buffer<wchar_t>; | ||||
| 
 | ||||
| #if FMT_GCC_VERSION && FMT_GCC_VERSION < 409 | ||||
| // Workaround broken conversion on older gcc.
 | ||||
| template <typename... Args> using wformat_string = wstring_view; | ||||
| #else | ||||
| template <typename... Args> | ||||
| using wformat_string = basic_format_string<wchar_t, type_identity_t<Args>...>; | ||||
| #endif | ||||
| 
 | ||||
| template <> struct is_char<wchar_t> : std::true_type {}; | ||||
| template <> struct is_char<detail::char8_type> : std::true_type {}; | ||||
| template <> struct is_char<char16_t> : std::true_type {}; | ||||
| template <> struct is_char<char32_t> : std::true_type {}; | ||||
| 
 | ||||
| template <typename... Args> | ||||
| constexpr format_arg_store<wformat_context, Args...> make_wformat_args( | ||||
|     const Args&... args) { | ||||
|   return {args...}; | ||||
| } | ||||
| 
 | ||||
| inline namespace literals { | ||||
| constexpr auto operator"" _format(const wchar_t* s, size_t n) | ||||
|     -> detail::udl_formatter<wchar_t> { | ||||
|   return {{s, n}}; | ||||
| } | ||||
| 
 | ||||
| #if FMT_USE_USER_DEFINED_LITERALS && !FMT_USE_NONTYPE_TEMPLATE_PARAMETERS | ||||
| constexpr detail::udl_arg<wchar_t> operator"" _a(const wchar_t* s, size_t) { | ||||
|   return {s}; | ||||
| } | ||||
| #endif | ||||
| }  // namespace literals
 | ||||
| 
 | ||||
| template <typename It, typename Sentinel> | ||||
| auto join(It begin, Sentinel end, wstring_view sep) | ||||
|     -> join_view<It, Sentinel, wchar_t> { | ||||
|   return {begin, end, sep}; | ||||
| } | ||||
| 
 | ||||
| template <typename Range> | ||||
| auto join(Range&& range, wstring_view sep) | ||||
|     -> join_view<detail::iterator_t<Range>, detail::sentinel_t<Range>, | ||||
|                  wchar_t> { | ||||
|   return join(std::begin(range), std::end(range), sep); | ||||
| } | ||||
| 
 | ||||
| template <typename T> | ||||
| auto join(std::initializer_list<T> list, wstring_view sep) | ||||
|     -> join_view<const T*, const T*, wchar_t> { | ||||
|   return join(std::begin(list), std::end(list), sep); | ||||
| } | ||||
| 
 | ||||
| template <typename Char, FMT_ENABLE_IF(!std::is_same<Char, char>::value)> | ||||
| auto vformat(basic_string_view<Char> format_str, | ||||
|              basic_format_args<buffer_context<type_identity_t<Char>>> args) | ||||
|     -> std::basic_string<Char> { | ||||
|   basic_memory_buffer<Char> buffer; | ||||
|   detail::vformat_to(buffer, format_str, args); | ||||
|   return to_string(buffer); | ||||
| } | ||||
| 
 | ||||
| // Pass char_t as a default template parameter instead of using
 | ||||
| // std::basic_string<char_t<S>> to reduce the symbol size.
 | ||||
| template <typename S, typename... Args, typename Char = char_t<S>, | ||||
|           FMT_ENABLE_IF(!std::is_same<Char, char>::value)> | ||||
| auto format(const S& format_str, Args&&... args) -> std::basic_string<Char> { | ||||
|   const auto& vargs = fmt::make_args_checked<Args...>(format_str, args...); | ||||
|   return vformat(to_string_view(format_str), vargs); | ||||
| } | ||||
| 
 | ||||
| template <typename Locale, typename S, typename Char = char_t<S>, | ||||
|           FMT_ENABLE_IF(detail::is_locale<Locale>::value&& | ||||
|                             detail::is_exotic_char<Char>::value)> | ||||
| inline auto vformat( | ||||
|     const Locale& loc, const S& format_str, | ||||
|     basic_format_args<buffer_context<type_identity_t<Char>>> args) | ||||
|     -> std::basic_string<Char> { | ||||
|   return detail::vformat(loc, to_string_view(format_str), args); | ||||
| } | ||||
| 
 | ||||
| template <typename Locale, typename S, typename... Args, | ||||
|           typename Char = char_t<S>, | ||||
|           FMT_ENABLE_IF(detail::is_locale<Locale>::value&& | ||||
|                             detail::is_exotic_char<Char>::value)> | ||||
| inline auto format(const Locale& loc, const S& format_str, Args&&... args) | ||||
|     -> std::basic_string<Char> { | ||||
|   return detail::vformat(loc, to_string_view(format_str), | ||||
|                          fmt::make_args_checked<Args...>(format_str, args...)); | ||||
| } | ||||
| 
 | ||||
| template <typename OutputIt, typename S, typename Char = char_t<S>, | ||||
|           FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value&& | ||||
|                             detail::is_exotic_char<Char>::value)> | ||||
| auto vformat_to(OutputIt out, const S& format_str, | ||||
|                 basic_format_args<buffer_context<type_identity_t<Char>>> args) | ||||
|     -> OutputIt { | ||||
|   auto&& buf = detail::get_buffer<Char>(out); | ||||
|   detail::vformat_to(buf, to_string_view(format_str), args); | ||||
|   return detail::get_iterator(buf); | ||||
| } | ||||
| 
 | ||||
| template <typename OutputIt, typename S, typename... Args, | ||||
|           typename Char = char_t<S>, | ||||
|           FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value&& | ||||
|                             detail::is_exotic_char<Char>::value)> | ||||
| inline auto format_to(OutputIt out, const S& fmt, Args&&... args) -> OutputIt { | ||||
|   const auto& vargs = fmt::make_args_checked<Args...>(fmt, args...); | ||||
|   return vformat_to(out, to_string_view(fmt), vargs); | ||||
| } | ||||
| 
 | ||||
| template <typename S, typename... Args, typename Char, size_t SIZE, | ||||
|           typename Allocator, FMT_ENABLE_IF(detail::is_string<S>::value)> | ||||
| FMT_DEPRECATED auto format_to(basic_memory_buffer<Char, SIZE, Allocator>& buf, | ||||
|                               const S& format_str, Args&&... args) -> | ||||
|     typename buffer_context<Char>::iterator { | ||||
|   const auto& vargs = fmt::make_args_checked<Args...>(format_str, args...); | ||||
|   detail::vformat_to(buf, to_string_view(format_str), vargs, {}); | ||||
|   return detail::buffer_appender<Char>(buf); | ||||
| } | ||||
| 
 | ||||
| template <typename Locale, typename S, typename OutputIt, typename... Args, | ||||
|           typename Char = char_t<S>, | ||||
|           FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value&& | ||||
|                             detail::is_locale<Locale>::value&& | ||||
|                                 detail::is_exotic_char<Char>::value)> | ||||
| inline auto vformat_to( | ||||
|     OutputIt out, const Locale& loc, const S& format_str, | ||||
|     basic_format_args<buffer_context<type_identity_t<Char>>> args) -> OutputIt { | ||||
|   auto&& buf = detail::get_buffer<Char>(out); | ||||
|   vformat_to(buf, to_string_view(format_str), args, detail::locale_ref(loc)); | ||||
|   return detail::get_iterator(buf); | ||||
| } | ||||
| 
 | ||||
| template < | ||||
|     typename OutputIt, typename Locale, typename S, typename... Args, | ||||
|     typename Char = char_t<S>, | ||||
|     bool enable = detail::is_output_iterator<OutputIt, Char>::value&& | ||||
|         detail::is_locale<Locale>::value&& detail::is_exotic_char<Char>::value> | ||||
| inline auto format_to(OutputIt out, const Locale& loc, const S& format_str, | ||||
|                       Args&&... args) -> | ||||
|     typename std::enable_if<enable, OutputIt>::type { | ||||
|   const auto& vargs = fmt::make_args_checked<Args...>(format_str, args...); | ||||
|   return vformat_to(out, loc, to_string_view(format_str), vargs); | ||||
| } | ||||
| 
 | ||||
| template <typename OutputIt, typename Char, typename... Args, | ||||
|           FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value&& | ||||
|                             detail::is_exotic_char<Char>::value)> | ||||
| inline auto vformat_to_n( | ||||
|     OutputIt out, size_t n, basic_string_view<Char> format_str, | ||||
|     basic_format_args<buffer_context<type_identity_t<Char>>> args) | ||||
|     -> format_to_n_result<OutputIt> { | ||||
|   detail::iterator_buffer<OutputIt, Char, detail::fixed_buffer_traits> buf(out, | ||||
|                                                                            n); | ||||
|   detail::vformat_to(buf, format_str, args); | ||||
|   return {buf.out(), buf.count()}; | ||||
| } | ||||
| 
 | ||||
| template <typename OutputIt, typename S, typename... Args, | ||||
|           typename Char = char_t<S>, | ||||
|           FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value&& | ||||
|                             detail::is_exotic_char<Char>::value)> | ||||
| inline auto format_to_n(OutputIt out, size_t n, const S& fmt, | ||||
|                         const Args&... args) -> format_to_n_result<OutputIt> { | ||||
|   const auto& vargs = fmt::make_args_checked<Args...>(fmt, args...); | ||||
|   return vformat_to_n(out, n, to_string_view(fmt), vargs); | ||||
| } | ||||
| 
 | ||||
| template <typename S, typename... Args, typename Char = char_t<S>, | ||||
|           FMT_ENABLE_IF(detail::is_exotic_char<Char>::value)> | ||||
| inline auto formatted_size(const S& fmt, Args&&... args) -> size_t { | ||||
|   detail::counting_buffer<Char> buf; | ||||
|   const auto& vargs = fmt::make_args_checked<Args...>(fmt, args...); | ||||
|   detail::vformat_to(buf, to_string_view(fmt), vargs); | ||||
|   return buf.count(); | ||||
| } | ||||
| 
 | ||||
| inline void vprint(std::FILE* f, wstring_view fmt, wformat_args args) { | ||||
|   wmemory_buffer buffer; | ||||
|   detail::vformat_to(buffer, fmt, args); | ||||
|   buffer.push_back(L'\0'); | ||||
|   if (std::fputws(buffer.data(), f) == -1) | ||||
|     FMT_THROW(system_error(errno, FMT_STRING("cannot write to file"))); | ||||
| } | ||||
| 
 | ||||
| inline void vprint(wstring_view fmt, wformat_args args) { | ||||
|   vprint(stdout, fmt, args); | ||||
| } | ||||
| 
 | ||||
| template <typename... T> | ||||
| void print(std::FILE* f, wformat_string<T...> fmt, T&&... args) { | ||||
|   return vprint(f, wstring_view(fmt), fmt::make_wformat_args(args...)); | ||||
| } | ||||
| 
 | ||||
| template <typename... T> void print(wformat_string<T...> fmt, T&&... args) { | ||||
|   return vprint(wstring_view(fmt), fmt::make_wformat_args(args...)); | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|   Converts *value* to ``std::wstring`` using the default format for type *T*. | ||||
|  */ | ||||
| template <typename T> inline auto to_wstring(const T& value) -> std::wstring { | ||||
|   return format(FMT_STRING(L"{}"), value); | ||||
| } | ||||
| FMT_MODULE_EXPORT_END | ||||
| FMT_END_NAMESPACE | ||||
| 
 | ||||
| #endif  // FMT_XCHAR_H_
 | ||||
							
								
								
									
										22
									
								
								Dependencies/spdlog/include/spdlog/fmt/chrono.h
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										22
									
								
								Dependencies/spdlog/include/spdlog/fmt/chrono.h
									
										
									
									
										vendored
									
									
								
							|  | @ -1,22 +0,0 @@ | |||
| //
 | ||||
| // Copyright(c) 2016 Gabi Melman.
 | ||||
| // Distributed under the MIT License (http://opensource.org/licenses/MIT)
 | ||||
| //
 | ||||
| 
 | ||||
| #pragma once | ||||
| //
 | ||||
| // include bundled or external copy of fmtlib's chrono support
 | ||||
| //
 | ||||
| 
 | ||||
| #if !defined(SPDLOG_USE_STD_FORMAT) | ||||
| #    if !defined(SPDLOG_FMT_EXTERNAL) | ||||
| #        ifdef SPDLOG_HEADER_ONLY | ||||
| #            ifndef FMT_HEADER_ONLY | ||||
| #                define FMT_HEADER_ONLY | ||||
| #            endif | ||||
| #        endif | ||||
| #        include <spdlog/fmt/bundled/chrono.h> | ||||
| #    else | ||||
| #        include <fmt/chrono.h> | ||||
| #    endif | ||||
| #endif | ||||
							
								
								
									
										22
									
								
								Dependencies/spdlog/include/spdlog/fmt/compile.h
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										22
									
								
								Dependencies/spdlog/include/spdlog/fmt/compile.h
									
										
									
									
										vendored
									
									
								
							|  | @ -1,22 +0,0 @@ | |||
| //
 | ||||
| // Copyright(c) 2016 Gabi Melman.
 | ||||
| // Distributed under the MIT License (http://opensource.org/licenses/MIT)
 | ||||
| //
 | ||||
| 
 | ||||
| #pragma once | ||||
| //
 | ||||
| // include bundled or external copy of fmtlib's compile-time support
 | ||||
| //
 | ||||
| 
 | ||||
| #if !defined(SPDLOG_USE_STD_FORMAT) | ||||
| #    if !defined(SPDLOG_FMT_EXTERNAL) | ||||
| #        ifdef SPDLOG_HEADER_ONLY | ||||
| #            ifndef FMT_HEADER_ONLY | ||||
| #                define FMT_HEADER_ONLY | ||||
| #            endif | ||||
| #        endif | ||||
| #        include <spdlog/fmt/bundled/compile.h> | ||||
| #    else | ||||
| #        include <fmt/compile.h> | ||||
| #    endif | ||||
| #endif | ||||
							
								
								
									
										29
									
								
								Dependencies/spdlog/include/spdlog/fmt/fmt.h
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										29
									
								
								Dependencies/spdlog/include/spdlog/fmt/fmt.h
									
										
									
									
										vendored
									
									
								
							|  | @ -1,29 +0,0 @@ | |||
| //
 | ||||
| // Copyright(c) 2016-2018 Gabi Melman.
 | ||||
| // Distributed under the MIT License (http://opensource.org/licenses/MIT)
 | ||||
| //
 | ||||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| //
 | ||||
| // Include a bundled header-only copy of fmtlib or an external one.
 | ||||
| // By default spdlog include its own copy.
 | ||||
| //
 | ||||
| 
 | ||||
| #if defined(SPDLOG_USE_STD_FORMAT) // SPDLOG_USE_STD_FORMAT is defined - use std::format
 | ||||
| #    include <format> | ||||
| #elif !defined(SPDLOG_FMT_EXTERNAL) | ||||
| #    if !defined(SPDLOG_COMPILED_LIB) && !defined(FMT_HEADER_ONLY) | ||||
| #        define FMT_HEADER_ONLY | ||||
| #    endif | ||||
| #    ifndef FMT_USE_WINDOWS_H | ||||
| #        define FMT_USE_WINDOWS_H 0 | ||||
| #    endif | ||||
| // enable the 'n' flag in for backward compatibility with fmt 6.x
 | ||||
| #    define FMT_DEPRECATED_N_SPECIFIER | ||||
| #    include <spdlog/fmt/bundled/core.h> | ||||
| #    include <spdlog/fmt/bundled/format.h> | ||||
| #else // SPDLOG_FMT_EXTERNAL is defined - use external fmtlib
 | ||||
| #    include <fmt/core.h> | ||||
| #    include <fmt/format.h> | ||||
| #endif | ||||
							
								
								
									
										22
									
								
								Dependencies/spdlog/include/spdlog/fmt/ostr.h
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										22
									
								
								Dependencies/spdlog/include/spdlog/fmt/ostr.h
									
										
									
									
										vendored
									
									
								
							|  | @ -1,22 +0,0 @@ | |||
| //
 | ||||
| // Copyright(c) 2016 Gabi Melman.
 | ||||
| // Distributed under the MIT License (http://opensource.org/licenses/MIT)
 | ||||
| //
 | ||||
| 
 | ||||
| #pragma once | ||||
| //
 | ||||
| // include bundled or external copy of fmtlib's ostream support
 | ||||
| //
 | ||||
| 
 | ||||
| #if !defined(SPDLOG_USE_STD_FORMAT) | ||||
| #    if !defined(SPDLOG_FMT_EXTERNAL) | ||||
| #        ifdef SPDLOG_HEADER_ONLY | ||||
| #            ifndef FMT_HEADER_ONLY | ||||
| #                define FMT_HEADER_ONLY | ||||
| #            endif | ||||
| #        endif | ||||
| #        include <spdlog/fmt/bundled/ostream.h> | ||||
| #    else | ||||
| #        include <fmt/ostream.h> | ||||
| #    endif | ||||
| #endif | ||||
							
								
								
									
										22
									
								
								Dependencies/spdlog/include/spdlog/fmt/ranges.h
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										22
									
								
								Dependencies/spdlog/include/spdlog/fmt/ranges.h
									
										
									
									
										vendored
									
									
								
							|  | @ -1,22 +0,0 @@ | |||
| //
 | ||||
| // Copyright(c) 2016 Gabi Melman.
 | ||||
| // Distributed under the MIT License (http://opensource.org/licenses/MIT)
 | ||||
| //
 | ||||
| 
 | ||||
| #pragma once | ||||
| //
 | ||||
| // include bundled or external copy of fmtlib's ranges support
 | ||||
| //
 | ||||
| 
 | ||||
| #if !defined(SPDLOG_USE_STD_FORMAT) | ||||
| #    if !defined(SPDLOG_FMT_EXTERNAL) | ||||
| #        ifdef SPDLOG_HEADER_ONLY | ||||
| #            ifndef FMT_HEADER_ONLY | ||||
| #                define FMT_HEADER_ONLY | ||||
| #            endif | ||||
| #        endif | ||||
| #        include <spdlog/fmt/bundled/ranges.h> | ||||
| #    else | ||||
| #        include <fmt/ranges.h> | ||||
| #    endif | ||||
| #endif | ||||
							
								
								
									
										22
									
								
								Dependencies/spdlog/include/spdlog/fmt/xchar.h
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										22
									
								
								Dependencies/spdlog/include/spdlog/fmt/xchar.h
									
										
									
									
										vendored
									
									
								
							|  | @ -1,22 +0,0 @@ | |||
| //
 | ||||
| // Copyright(c) 2016 Gabi Melman.
 | ||||
| // Distributed under the MIT License (http://opensource.org/licenses/MIT)
 | ||||
| //
 | ||||
| 
 | ||||
| #pragma once | ||||
| //
 | ||||
| // include bundled or external copy of fmtlib's xchar support
 | ||||
| //
 | ||||
| 
 | ||||
| #if !defined(SPDLOG_USE_STD_FORMAT) | ||||
| #    if !defined(SPDLOG_FMT_EXTERNAL) | ||||
| #        ifdef SPDLOG_HEADER_ONLY | ||||
| #            ifndef FMT_HEADER_ONLY | ||||
| #                define FMT_HEADER_ONLY | ||||
| #            endif | ||||
| #        endif | ||||
| #        include <spdlog/fmt/bundled/xchar.h> | ||||
| #    else | ||||
| #        include <fmt/xchar.h> | ||||
| #    endif | ||||
| #endif | ||||
							
								
								
									
										18
									
								
								Dependencies/spdlog/include/spdlog/formatter.h
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										18
									
								
								Dependencies/spdlog/include/spdlog/formatter.h
									
										
									
									
										vendored
									
									
								
							|  | @ -1,18 +0,0 @@ | |||
| // Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
 | ||||
| // Distributed under the MIT License (http://opensource.org/licenses/MIT)
 | ||||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| #include <spdlog/fmt/fmt.h> | ||||
| #include <spdlog/details/log_msg.h> | ||||
| 
 | ||||
| namespace spdlog { | ||||
| 
 | ||||
| class formatter | ||||
| { | ||||
| public: | ||||
|     virtual ~formatter() = default; | ||||
|     virtual void format(const details::log_msg &msg, memory_buf_t &dest) = 0; | ||||
|     virtual std::unique_ptr<formatter> clone() const = 0; | ||||
| }; | ||||
| } // namespace spdlog
 | ||||
							
								
								
									
										18
									
								
								Dependencies/spdlog/include/spdlog/fwd.h
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										18
									
								
								Dependencies/spdlog/include/spdlog/fwd.h
									
										
									
									
										vendored
									
									
								
							|  | @ -1,18 +0,0 @@ | |||
| // Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
 | ||||
| // Distributed under the MIT License (http://opensource.org/licenses/MIT)
 | ||||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| namespace spdlog { | ||||
| class logger; | ||||
| class formatter; | ||||
| 
 | ||||
| namespace sinks { | ||||
| class sink; | ||||
| } | ||||
| 
 | ||||
| namespace level { | ||||
| enum level_enum : int; | ||||
| } | ||||
| 
 | ||||
| } // namespace spdlog
 | ||||
							
								
								
									
										257
									
								
								Dependencies/spdlog/include/spdlog/logger-inl.h
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										257
									
								
								Dependencies/spdlog/include/spdlog/logger-inl.h
									
										
									
									
										vendored
									
									
								
							|  | @ -1,257 +0,0 @@ | |||
| // 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/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 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 separate 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)); | ||||
|             break; // to prevent clang-tidy warning
 | ||||
|         } | ||||
|         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_ = std::move(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::log_it_(const spdlog::details::log_msg &log_msg, bool log_enabled, bool traceback_enabled) | ||||
| { | ||||
|     if (log_enabled) | ||||
|     { | ||||
|         sink_it_(log_msg); | ||||
|     } | ||||
|     if (traceback_enabled) | ||||
|     { | ||||
|         tracer_.push_back(log_msg); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| SPDLOG_INLINE void logger::sink_it_(const details::log_msg &msg) | ||||
| { | ||||
|     for (auto &sink : sinks_) | ||||
|     { | ||||
|         if (sink->should_log(msg.level)) | ||||
|         { | ||||
|             SPDLOG_TRY | ||||
|             { | ||||
|                 sink->log(msg); | ||||
|             } | ||||
|             SPDLOG_LOGGER_CATCH(msg.source) | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     if (should_flush_(msg)) | ||||
|     { | ||||
|         flush_(); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| SPDLOG_INLINE void logger::flush_() | ||||
| { | ||||
|     for (auto &sink : sinks_) | ||||
|     { | ||||
|         SPDLOG_TRY | ||||
|         { | ||||
|             sink->flush(); | ||||
|         } | ||||
|         SPDLOG_LOGGER_CATCH(source_loc()) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| SPDLOG_INLINE void logger::dump_backtrace_() | ||||
| { | ||||
|     using details::log_msg; | ||||
|     if (tracer_.enabled()) | ||||
|     { | ||||
|         sink_it_(log_msg{name(), level::info, "****************** Backtrace Start ******************"}); | ||||
|         tracer_.foreach_pop([this](const 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); | ||||
| #if defined(USING_R) && defined(R_R_H) // if in R environment
 | ||||
|         REprintf("[*** LOG ERROR #%04zu ***] [%s] [%s] {%s}\n", err_counter, date_buf, name().c_str(), msg.c_str()); | ||||
| #else | ||||
|         std::fprintf(stderr, "[*** LOG ERROR #%04zu ***] [%s] [%s] {%s}\n", err_counter, date_buf, name().c_str(), msg.c_str()); | ||||
| #endif | ||||
|     } | ||||
| } | ||||
| } // namespace spdlog
 | ||||
							
								
								
									
										447
									
								
								Dependencies/spdlog/include/spdlog/logger.h
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										447
									
								
								Dependencies/spdlog/include/spdlog/logger.h
									
										
									
									
										vendored
									
									
								
							|  | @ -1,447 +0,0 @@ | |||
| // Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
 | ||||
| // Distributed under the MIT License (http://opensource.org/licenses/MIT)
 | ||||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| // Thread safe logger (except for set_error_handler())
 | ||||
| // Has name, log level, vector of std::shared sink pointers and formatter
 | ||||
| // Upon each log write the logger:
 | ||||
| // 1. Checks if its log level is enough to log the message and if yes:
 | ||||
| // 2. Call the underlying sinks to do the job.
 | ||||
| // 3. Each sink use its own private copy of a formatter to format the message
 | ||||
| // and send to its destination.
 | ||||
| //
 | ||||
| // The use of private formatter per sink provides the opportunity to cache some
 | ||||
| // formatted data, and support for different format per sink.
 | ||||
| 
 | ||||
| #include <spdlog/common.h> | ||||
| #include <spdlog/details/log_msg.h> | ||||
| #include <spdlog/details/backtracer.h> | ||||
| 
 | ||||
| #ifdef SPDLOG_WCHAR_TO_UTF8_SUPPORT | ||||
| #    ifndef _WIN32 | ||||
| #        error SPDLOG_WCHAR_TO_UTF8_SUPPORT only supported on windows | ||||
| #    endif | ||||
| #    include <spdlog/details/os.h> | ||||
| #endif | ||||
| 
 | ||||
| #include <vector> | ||||
| 
 | ||||
| #ifndef SPDLOG_NO_EXCEPTIONS | ||||
| #    define SPDLOG_LOGGER_CATCH(location)                                                                                                  \ | ||||
|         catch (const std::exception &ex)                                                                                                   \ | ||||
|         {                                                                                                                                  \ | ||||
|             if (location.filename)                                                                                                         \ | ||||
|             {                                                                                                                              \ | ||||
|                 err_handler_(fmt_lib::format("{} [{}({})]", ex.what(), location.filename, location.line));                                 \ | ||||
|             }                                                                                                                              \ | ||||
|             else                                                                                                                           \ | ||||
|             {                                                                                                                              \ | ||||
|                 err_handler_(ex.what());                                                                                                   \ | ||||
|             }                                                                                                                              \ | ||||
|         }                                                                                                                                  \ | ||||
|         catch (...)                                                                                                                        \ | ||||
|         {                                                                                                                                  \ | ||||
|             err_handler_("Rethrowing unknown exception in logger");                                                                        \ | ||||
|             throw;                                                                                                                         \ | ||||
|         } | ||||
| #else | ||||
| #    define SPDLOG_LOGGER_CATCH(location) | ||||
| #endif | ||||
| 
 | ||||
| namespace spdlog { | ||||
| 
 | ||||
| class SPDLOG_API logger | ||||
| { | ||||
| public: | ||||
|     // Empty logger
 | ||||
|     explicit logger(std::string name) | ||||
|         : name_(std::move(name)) | ||||
|         , sinks_() | ||||
|     {} | ||||
| 
 | ||||
|     // Logger with range on sinks
 | ||||
|     template<typename It> | ||||
|     logger(std::string name, It begin, It end) | ||||
|         : name_(std::move(name)) | ||||
|         , sinks_(begin, end) | ||||
|     {} | ||||
| 
 | ||||
|     // Logger with single sink
 | ||||
|     logger(std::string name, sink_ptr single_sink) | ||||
|         : logger(std::move(name), {std::move(single_sink)}) | ||||
|     {} | ||||
| 
 | ||||
|     // Logger with sinks init list
 | ||||
|     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> | ||||
|     void log(source_loc loc, level::level_enum lvl, format_string_t<Args...> fmt, Args &&... args) | ||||
|     { | ||||
|         log_(loc, lvl, fmt, std::forward<Args>(args)...); | ||||
|     } | ||||
| 
 | ||||
|     template<typename... Args> | ||||
|     void log(level::level_enum lvl, format_string_t<Args...> fmt, Args &&... args) | ||||
|     { | ||||
|         log(source_loc{}, lvl, fmt, std::forward<Args>(args)...); | ||||
|     } | ||||
| 
 | ||||
|     template<typename T> | ||||
|     void log(level::level_enum lvl, const T &msg) | ||||
|     { | ||||
|         log(source_loc{}, lvl, msg); | ||||
|     } | ||||
| 
 | ||||
|     // T cannot be statically converted to format string (including string_view/wstring_view)
 | ||||
|     template<class T, typename std::enable_if<!is_convertible_to_any_format_string<const T &>::value, int>::type = 0> | ||||
|     void log(source_loc loc, level::level_enum lvl, const T &msg) | ||||
|     { | ||||
|         log(loc, lvl, "{}", msg); | ||||
|     } | ||||
| 
 | ||||
|     void log(log_clock::time_point log_time, source_loc loc, level::level_enum lvl, string_view_t msg) | ||||
|     { | ||||
|         bool log_enabled = should_log(lvl); | ||||
|         bool traceback_enabled = tracer_.enabled(); | ||||
|         if (!log_enabled && !traceback_enabled) | ||||
|         { | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         details::log_msg log_msg(log_time, loc, name_, lvl, msg); | ||||
|         log_it_(log_msg, log_enabled, traceback_enabled); | ||||
|     } | ||||
| 
 | ||||
|     void log(source_loc loc, level::level_enum lvl, string_view_t msg) | ||||
|     { | ||||
|         bool log_enabled = should_log(lvl); | ||||
|         bool traceback_enabled = tracer_.enabled(); | ||||
|         if (!log_enabled && !traceback_enabled) | ||||
|         { | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         details::log_msg log_msg(loc, name_, lvl, msg); | ||||
|         log_it_(log_msg, log_enabled, traceback_enabled); | ||||
|     } | ||||
| 
 | ||||
|     void log(level::level_enum lvl, string_view_t msg) | ||||
|     { | ||||
|         log(source_loc{}, lvl, msg); | ||||
|     } | ||||
| 
 | ||||
|     template<typename... Args> | ||||
|     void trace(format_string_t<Args...> fmt, Args &&... args) | ||||
|     { | ||||
|         log(level::trace, fmt, std::forward<Args>(args)...); | ||||
|     } | ||||
| 
 | ||||
|     template<typename... Args> | ||||
|     void debug(format_string_t<Args...> fmt, Args &&... args) | ||||
|     { | ||||
|         log(level::debug, fmt, std::forward<Args>(args)...); | ||||
|     } | ||||
| 
 | ||||
|     template<typename... Args> | ||||
|     void info(format_string_t<Args...> fmt, Args &&... args) | ||||
|     { | ||||
|         log(level::info, fmt, std::forward<Args>(args)...); | ||||
|     } | ||||
| 
 | ||||
|     template<typename... Args> | ||||
|     void warn(format_string_t<Args...> fmt, Args &&... args) | ||||
|     { | ||||
|         log(level::warn, fmt, std::forward<Args>(args)...); | ||||
|     } | ||||
| 
 | ||||
|     template<typename... Args> | ||||
|     void error(format_string_t<Args...> fmt, Args &&... args) | ||||
|     { | ||||
|         log(level::err, fmt, std::forward<Args>(args)...); | ||||
|     } | ||||
| 
 | ||||
|     template<typename... Args> | ||||
|     void critical(format_string_t<Args...> fmt, Args &&... args) | ||||
|     { | ||||
|         log(level::critical, fmt, std::forward<Args>(args)...); | ||||
|     } | ||||
| 
 | ||||
| #ifdef SPDLOG_WCHAR_TO_UTF8_SUPPORT | ||||
|     template<typename... Args> | ||||
|     void log(source_loc loc, level::level_enum lvl, wformat_string_t<Args...> fmt, Args &&... args) | ||||
|     { | ||||
|         log_(loc, lvl, fmt, std::forward<Args>(args)...); | ||||
|     } | ||||
| 
 | ||||
|     template<typename... Args> | ||||
|     void log(level::level_enum lvl, wformat_string_t<Args...> fmt, Args &&... args) | ||||
|     { | ||||
|         log(source_loc{}, lvl, fmt, std::forward<Args>(args)...); | ||||
|     } | ||||
| 
 | ||||
|     void log(log_clock::time_point log_time, source_loc loc, level::level_enum lvl, wstring_view_t msg) | ||||
|     { | ||||
|         bool log_enabled = should_log(lvl); | ||||
|         bool traceback_enabled = tracer_.enabled(); | ||||
|         if (!log_enabled && !traceback_enabled) | ||||
|         { | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         memory_buf_t buf; | ||||
|         details::os::wstr_to_utf8buf(wstring_view_t(msg.data(), msg.size()), buf); | ||||
|         details::log_msg log_msg(log_time, loc, name_, lvl, string_view_t(buf.data(), buf.size())); | ||||
|         log_it_(log_msg, log_enabled, traceback_enabled); | ||||
|     } | ||||
| 
 | ||||
|     void log(source_loc loc, level::level_enum lvl, wstring_view_t msg) | ||||
|     { | ||||
|         bool log_enabled = should_log(lvl); | ||||
|         bool traceback_enabled = tracer_.enabled(); | ||||
|         if (!log_enabled && !traceback_enabled) | ||||
|         { | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         memory_buf_t buf; | ||||
|         details::os::wstr_to_utf8buf(wstring_view_t(msg.data(), msg.size()), buf); | ||||
|         details::log_msg log_msg(loc, name_, lvl, string_view_t(buf.data(), buf.size())); | ||||
|         log_it_(log_msg, log_enabled, traceback_enabled); | ||||
|     } | ||||
| 
 | ||||
|     void log(level::level_enum lvl, wstring_view_t msg) | ||||
|     { | ||||
|         log(source_loc{}, lvl, msg); | ||||
|     } | ||||
| 
 | ||||
|     template<typename... Args> | ||||
|     void trace(wformat_string_t<Args...> fmt, Args &&... args) | ||||
|     { | ||||
|         log(level::trace, fmt, std::forward<Args>(args)...); | ||||
|     } | ||||
| 
 | ||||
|     template<typename... Args> | ||||
|     void debug(wformat_string_t<Args...> fmt, Args &&... args) | ||||
|     { | ||||
|         log(level::debug, fmt, std::forward<Args>(args)...); | ||||
|     } | ||||
| 
 | ||||
|     template<typename... Args> | ||||
|     void info(wformat_string_t<Args...> fmt, Args &&... args) | ||||
|     { | ||||
|         log(level::info, fmt, std::forward<Args>(args)...); | ||||
|     } | ||||
| 
 | ||||
|     template<typename... Args> | ||||
|     void warn(wformat_string_t<Args...> fmt, Args &&... args) | ||||
|     { | ||||
|         log(level::warn, fmt, std::forward<Args>(args)...); | ||||
|     } | ||||
| 
 | ||||
|     template<typename... Args> | ||||
|     void error(wformat_string_t<Args...> fmt, Args &&... args) | ||||
|     { | ||||
|         log(level::err, fmt, std::forward<Args>(args)...); | ||||
|     } | ||||
| 
 | ||||
|     template<typename... Args> | ||||
|     void critical(wformat_string_t<Args...> fmt, Args &&... args) | ||||
|     { | ||||
|         log(level::critical, fmt, std::forward<Args>(args)...); | ||||
|     } | ||||
| #endif | ||||
| 
 | ||||
|     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); | ||||
|     } | ||||
| 
 | ||||
|     // return true logging is enabled for the given level.
 | ||||
|     bool should_log(level::level_enum msg_level) const | ||||
|     { | ||||
|         return msg_level >= level_.load(std::memory_order_relaxed); | ||||
|     } | ||||
| 
 | ||||
|     // return true if backtrace logging is enabled.
 | ||||
|     bool should_backtrace() const | ||||
|     { | ||||
|         return tracer_.enabled(); | ||||
|     } | ||||
| 
 | ||||
|     void set_level(level::level_enum log_level); | ||||
| 
 | ||||
|     level::level_enum level() const; | ||||
| 
 | ||||
|     const std::string &name() const; | ||||
| 
 | ||||
|     // set formatting for the sinks in this logger.
 | ||||
|     // each sink will get a separate instance of the formatter object.
 | ||||
|     void set_formatter(std::unique_ptr<formatter> f); | ||||
| 
 | ||||
|     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
 | ||||
|     void flush(); | ||||
|     void flush_on(level::level_enum log_level); | ||||
|     level::level_enum flush_level() const; | ||||
| 
 | ||||
|     // sinks
 | ||||
|     const std::vector<sink_ptr> &sinks() const; | ||||
| 
 | ||||
|     std::vector<sink_ptr> &sinks(); | ||||
| 
 | ||||
|     // error handler
 | ||||
|     void set_error_handler(err_handler); | ||||
| 
 | ||||
|     // create new logger with same sinks and configuration.
 | ||||
|     virtual std::shared_ptr<logger> clone(std::string logger_name); | ||||
| 
 | ||||
| protected: | ||||
|     std::string name_; | ||||
|     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_; | ||||
| 
 | ||||
|     // common implementation for after templated public api has been resolved
 | ||||
|     template<typename... Args> | ||||
|     void log_(source_loc loc, level::level_enum lvl, string_view_t fmt, Args &&... args) | ||||
|     { | ||||
|         bool log_enabled = should_log(lvl); | ||||
|         bool traceback_enabled = tracer_.enabled(); | ||||
|         if (!log_enabled && !traceback_enabled) | ||||
|         { | ||||
|             return; | ||||
|         } | ||||
|         SPDLOG_TRY | ||||
|         { | ||||
| #ifdef SPDLOG_USE_STD_FORMAT | ||||
|             memory_buf_t buf = std::vformat(fmt, std::make_format_args(std::forward<Args>(args)...)); | ||||
| #else | ||||
|             memory_buf_t buf; | ||||
|             fmt::detail::vformat_to(buf, fmt, fmt::make_format_args(std::forward<Args>(args)...)); | ||||
| #endif | ||||
|             details::log_msg log_msg(loc, name_, lvl, string_view_t(buf.data(), buf.size())); | ||||
|             log_it_(log_msg, log_enabled, traceback_enabled); | ||||
|         } | ||||
|         SPDLOG_LOGGER_CATCH(loc) | ||||
|     } | ||||
| 
 | ||||
| #ifdef SPDLOG_WCHAR_TO_UTF8_SUPPORT | ||||
|     template<typename... Args> | ||||
|     void log_(source_loc loc, level::level_enum lvl, wstring_view_t fmt, Args &&... args) | ||||
|     { | ||||
|         bool log_enabled = should_log(lvl); | ||||
|         bool traceback_enabled = tracer_.enabled(); | ||||
|         if (!log_enabled && !traceback_enabled) | ||||
|         { | ||||
|             return; | ||||
|         } | ||||
|         SPDLOG_TRY | ||||
|         { | ||||
|             // format to wmemory_buffer and convert to utf8
 | ||||
|             ; | ||||
| #    ifdef SPDLOG_USE_STD_FORMAT | ||||
|             wmemory_buf_t wbuf = std::vformat(fmt, std::make_wformat_args(std::forward<Args>(args)...)); | ||||
| #    else | ||||
|             wmemory_buf_t wbuf; | ||||
|             fmt::detail::vformat_to(wbuf, fmt, fmt::make_format_args<fmt::wformat_context>(std::forward<Args>(args)...)); | ||||
| #    endif | ||||
|             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())); | ||||
|             log_it_(log_msg, log_enabled, traceback_enabled); | ||||
|         } | ||||
|         SPDLOG_LOGGER_CATCH(loc) | ||||
|     } | ||||
| 
 | ||||
|     // T can be statically converted to wstring_view, and no formatting needed.
 | ||||
|     template<class T, typename std::enable_if<std::is_convertible<const T &, spdlog::wstring_view_t>::value, int>::type = 0> | ||||
|     void log_(source_loc loc, level::level_enum lvl, const T &msg) | ||||
|     { | ||||
|         bool log_enabled = should_log(lvl); | ||||
|         bool traceback_enabled = tracer_.enabled(); | ||||
|         if (!log_enabled && !traceback_enabled) | ||||
|         { | ||||
|             return; | ||||
|         } | ||||
|         SPDLOG_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())); | ||||
|             log_it_(log_msg, log_enabled, traceback_enabled); | ||||
|         } | ||||
|         SPDLOG_LOGGER_CATCH(loc) | ||||
|     } | ||||
| 
 | ||||
| #endif // SPDLOG_WCHAR_TO_UTF8_SUPPORT
 | ||||
| 
 | ||||
|     // log the given message (if the given log level is high enough),
 | ||||
|     // and save backtrace (if backtrace is enabled).
 | ||||
|     void log_it_(const details::log_msg &log_msg, bool log_enabled, bool traceback_enabled); | ||||
|     virtual void sink_it_(const details::log_msg &msg); | ||||
|     virtual void flush_(); | ||||
|     void dump_backtrace_(); | ||||
|     bool should_flush_(const details::log_msg &msg); | ||||
| 
 | ||||
|     // handle errors during logging.
 | ||||
|     // default handler prints the error to stderr at max rate of 1 message/sec.
 | ||||
|     void err_handler_(const std::string &msg); | ||||
| }; | ||||
| 
 | ||||
| void swap(logger &a, logger &b); | ||||
| 
 | ||||
| } // namespace spdlog
 | ||||
| 
 | ||||
| #ifdef SPDLOG_HEADER_ONLY | ||||
| #    include "logger-inl.h" | ||||
| #endif | ||||
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							|  | @ -1,127 +0,0 @@ | |||
| // Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
 | ||||
| // Distributed under the MIT License (http://opensource.org/licenses/MIT)
 | ||||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| #include <spdlog/common.h> | ||||
| #include <spdlog/details/log_msg.h> | ||||
| #include <spdlog/details/os.h> | ||||
| #include <spdlog/formatter.h> | ||||
| 
 | ||||
| #include <chrono> | ||||
| #include <ctime> | ||||
| #include <memory> | ||||
| 
 | ||||
| #include <string> | ||||
| #include <vector> | ||||
| #include <unordered_map> | ||||
| 
 | ||||
| namespace spdlog { | ||||
| namespace details { | ||||
| 
 | ||||
| // padding information.
 | ||||
| struct padding_info | ||||
| { | ||||
|     enum class pad_side | ||||
|     { | ||||
|         left, | ||||
|         right, | ||||
|         center | ||||
|     }; | ||||
| 
 | ||||
|     padding_info() = default; | ||||
|     padding_info(size_t width, padding_info::pad_side side, bool truncate) | ||||
|         : width_(width) | ||||
|         , side_(side) | ||||
|         , truncate_(truncate) | ||||
|         , enabled_(true) | ||||
|     {} | ||||
| 
 | ||||
|     bool enabled() const | ||||
|     { | ||||
|         return enabled_; | ||||
|     } | ||||
|     size_t width_ = 0; | ||||
|     pad_side side_ = pad_side::left; | ||||
|     bool truncate_ = false; | ||||
|     bool enabled_ = false; | ||||
| }; | ||||
| 
 | ||||
| class SPDLOG_API flag_formatter | ||||
| { | ||||
| public: | ||||
|     explicit flag_formatter(padding_info padinfo) | ||||
|         : padinfo_(padinfo) | ||||
|     {} | ||||
|     flag_formatter() = default; | ||||
|     virtual ~flag_formatter() = default; | ||||
|     virtual void format(const details::log_msg &msg, const std::tm &tm_time, memory_buf_t &dest) = 0; | ||||
| 
 | ||||
| protected: | ||||
|     padding_info padinfo_; | ||||
| }; | ||||
| 
 | ||||
| } // namespace details
 | ||||
| 
 | ||||
| class SPDLOG_API custom_flag_formatter : public details::flag_formatter | ||||
| { | ||||
| public: | ||||
|     virtual std::unique_ptr<custom_flag_formatter> clone() const = 0; | ||||
| 
 | ||||
|     void set_padding_info(const details::padding_info &padding) | ||||
|     { | ||||
|         flag_formatter::padinfo_ = padding; | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| class SPDLOG_API pattern_formatter final : public formatter | ||||
| { | ||||
| public: | ||||
|     using custom_flags = std::unordered_map<char, std::unique_ptr<custom_flag_formatter>>; | ||||
| 
 | ||||
|     explicit pattern_formatter(std::string pattern, pattern_time_type time_type = pattern_time_type::local, | ||||
|         std::string eol = spdlog::details::os::default_eol, custom_flags custom_user_flags = custom_flags()); | ||||
| 
 | ||||
|     // use default pattern is not given
 | ||||
|     explicit pattern_formatter(pattern_time_type time_type = pattern_time_type::local, std::string eol = spdlog::details::os::default_eol); | ||||
| 
 | ||||
|     pattern_formatter(const pattern_formatter &other) = delete; | ||||
|     pattern_formatter &operator=(const pattern_formatter &other) = delete; | ||||
| 
 | ||||
|     std::unique_ptr<formatter> clone() const override; | ||||
|     void format(const details::log_msg &msg, memory_buf_t &dest) override; | ||||
| 
 | ||||
|     template<typename T, typename... Args> | ||||
|     pattern_formatter &add_flag(char flag, Args &&... args) | ||||
|     { | ||||
|         custom_handlers_[flag] = details::make_unique<T>(std::forward<Args>(args)...); | ||||
|         return *this; | ||||
|     } | ||||
|     void set_pattern(std::string pattern); | ||||
| 
 | ||||
| private: | ||||
|     std::string pattern_; | ||||
|     std::string eol_; | ||||
|     pattern_time_type pattern_time_type_; | ||||
|     bool need_localtime_; | ||||
|     std::tm cached_tm_; | ||||
|     std::chrono::seconds last_log_secs_; | ||||
|     std::vector<std::unique_ptr<details::flag_formatter>> formatters_; | ||||
|     custom_flags custom_handlers_; | ||||
| 
 | ||||
|     std::tm get_time_(const details::log_msg &msg); | ||||
|     template<typename Padder> | ||||
|     void handle_flag_(char flag, details::padding_info padding); | ||||
| 
 | ||||
|     // Extract given pad spec (e.g. %8X)
 | ||||
|     // Advance the given it pass the end of the padding spec found (if any)
 | ||||
|     // Return padding.
 | ||||
|     static details::padding_info handle_padspec_(std::string::const_iterator &it, std::string::const_iterator end); | ||||
| 
 | ||||
|     void compile_pattern_(const std::string &pattern); | ||||
| }; | ||||
| } // namespace spdlog
 | ||||
| 
 | ||||
| #ifdef SPDLOG_HEADER_ONLY | ||||
| #    include "pattern_formatter-inl.h" | ||||
| #endif | ||||
|  | @ -1,119 +0,0 @@ | |||
| // Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
 | ||||
| // Distributed under the MIT License (http://opensource.org/licenses/MIT)
 | ||||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| #ifdef __ANDROID__ | ||||
| 
 | ||||
| #    include <spdlog/details/fmt_helper.h> | ||||
| #    include <spdlog/details/null_mutex.h> | ||||
| #    include <spdlog/details/os.h> | ||||
| #    include <spdlog/sinks/base_sink.h> | ||||
| #    include <spdlog/details/synchronous_factory.h> | ||||
| 
 | ||||
| #    include <android/log.h> | ||||
| #    include <chrono> | ||||
| #    include <mutex> | ||||
| #    include <string> | ||||
| #    include <thread> | ||||
| 
 | ||||
| #    if !defined(SPDLOG_ANDROID_RETRIES) | ||||
| #        define SPDLOG_ANDROID_RETRIES 2 | ||||
| #    endif | ||||
| 
 | ||||
| namespace spdlog { | ||||
| namespace sinks { | ||||
| 
 | ||||
| /*
 | ||||
|  * Android sink (logging using __android_log_write) | ||||
|  */ | ||||
| template<typename Mutex> | ||||
| class android_sink final : public base_sink<Mutex> | ||||
| { | ||||
| public: | ||||
|     explicit android_sink(std::string tag = "spdlog", bool use_raw_msg = false) | ||||
|         : tag_(std::move(tag)) | ||||
|         , use_raw_msg_(use_raw_msg) | ||||
|     {} | ||||
| 
 | ||||
| protected: | ||||
|     void sink_it_(const details::log_msg &msg) override | ||||
|     { | ||||
|         const android_LogPriority priority = convert_to_android_(msg.level); | ||||
|         memory_buf_t formatted; | ||||
|         if (use_raw_msg_) | ||||
|         { | ||||
|             details::fmt_helper::append_string_view(msg.payload, formatted); | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             base_sink<Mutex>::formatter_->format(msg, formatted); | ||||
|         } | ||||
|         formatted.push_back('\0'); | ||||
|         const char *msg_output = formatted.data(); | ||||
| 
 | ||||
|         // See system/core/liblog/logger_write.c for explanation of return value
 | ||||
|         int ret = __android_log_write(priority, tag_.c_str(), msg_output); | ||||
|         int retry_count = 0; | ||||
|         while ((ret == -11 /*EAGAIN*/) && (retry_count < SPDLOG_ANDROID_RETRIES)) | ||||
|         { | ||||
|             details::os::sleep_for_millis(5); | ||||
|             ret = __android_log_write(priority, tag_.c_str(), msg_output); | ||||
|             retry_count++; | ||||
|         } | ||||
| 
 | ||||
|         if (ret < 0) | ||||
|         { | ||||
|             throw_spdlog_ex("__android_log_write() failed", ret); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     void flush_() override {} | ||||
| 
 | ||||
| private: | ||||
|     static android_LogPriority convert_to_android_(spdlog::level::level_enum level) | ||||
|     { | ||||
|         switch (level) | ||||
|         { | ||||
|         case spdlog::level::trace: | ||||
|             return ANDROID_LOG_VERBOSE; | ||||
|         case spdlog::level::debug: | ||||
|             return ANDROID_LOG_DEBUG; | ||||
|         case spdlog::level::info: | ||||
|             return ANDROID_LOG_INFO; | ||||
|         case spdlog::level::warn: | ||||
|             return ANDROID_LOG_WARN; | ||||
|         case spdlog::level::err: | ||||
|             return ANDROID_LOG_ERROR; | ||||
|         case spdlog::level::critical: | ||||
|             return ANDROID_LOG_FATAL; | ||||
|         default: | ||||
|             return ANDROID_LOG_DEFAULT; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     std::string tag_; | ||||
|     bool use_raw_msg_; | ||||
| }; | ||||
| 
 | ||||
| using android_sink_mt = android_sink<std::mutex>; | ||||
| using android_sink_st = android_sink<details::null_mutex>; | ||||
| } // namespace sinks
 | ||||
| 
 | ||||
| // Create and register android syslog logger
 | ||||
| 
 | ||||
| template<typename Factory = spdlog::synchronous_factory> | ||||
| 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); | ||||
| } | ||||
| 
 | ||||
| template<typename Factory = spdlog::synchronous_factory> | ||||
| 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); | ||||
| } | ||||
| 
 | ||||
| } // namespace spdlog
 | ||||
| 
 | ||||
| #endif // __ANDROID__
 | ||||
|  | @ -1,145 +0,0 @@ | |||
| // 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/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] = to_string_(white); | ||||
|     colors_[level::debug] = to_string_(cyan); | ||||
|     colors_[level::info] = to_string_(green); | ||||
|     colors_[level::warn] = to_string_(yellow_bold); | ||||
|     colors_[level::err] = to_string_(red_bold); | ||||
|     colors_[level::critical] = to_string_(bold_on_red); | ||||
|     colors_[level::off] = to_string_(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_[static_cast<size_t>(color_level)] = to_string_(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_); | ||||
|     msg.color_range_start = 0; | ||||
|     msg.color_range_end = 0; | ||||
|     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_[static_cast<size_t>(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; | ||||
|     default: | ||||
|         should_do_colors_ = false; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| template<typename ConsoleMutex> | ||||
| SPDLOG_INLINE void ansicolor_sink<ConsoleMutex>::print_ccode_(const string_view_t &color_code) | ||||
| { | ||||
|     fwrite(color_code.data(), sizeof(char), 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_); | ||||
| } | ||||
| 
 | ||||
| template<typename ConsoleMutex> | ||||
| SPDLOG_INLINE std::string ansicolor_sink<ConsoleMutex>::to_string_(const string_view_t &sv) | ||||
| { | ||||
|     return std::string(sv.data(), sv.size()); | ||||
| } | ||||
| 
 | ||||
| // 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,118 +0,0 @@ | |||
| // Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
 | ||||
| // Distributed under the MIT License (http://opensource.org/licenses/MIT)
 | ||||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| #include <spdlog/details/console_globals.h> | ||||
| #include <spdlog/details/null_mutex.h> | ||||
| #include <spdlog/sinks/sink.h> | ||||
| #include <memory> | ||||
| #include <mutex> | ||||
| #include <string> | ||||
| #include <array> | ||||
| 
 | ||||
| namespace spdlog { | ||||
| namespace sinks { | ||||
| 
 | ||||
| /**
 | ||||
|  * This sink prefixes the output with an ANSI escape sequence color code | ||||
|  * depending on the severity | ||||
|  * of the message. | ||||
|  * If no color terminal detected, omit the escape codes. | ||||
|  */ | ||||
| 
 | ||||
| template<typename ConsoleMutex> | ||||
| class ansicolor_sink : public sink | ||||
| { | ||||
| public: | ||||
|     using mutex_t = typename ConsoleMutex::mutex_t; | ||||
|     ansicolor_sink(FILE *target_file, color_mode mode); | ||||
|     ~ansicolor_sink() override = default; | ||||
| 
 | ||||
|     ansicolor_sink(const ansicolor_sink &other) = delete; | ||||
|     ansicolor_sink(ansicolor_sink &&other) = delete; | ||||
| 
 | ||||
|     ansicolor_sink &operator=(const ansicolor_sink &other) = delete; | ||||
|     ansicolor_sink &operator=(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 log(const details::log_msg &msg) override; | ||||
|     void flush() override; | ||||
|     void set_pattern(const std::string &pattern) final; | ||||
|     void set_formatter(std::unique_ptr<spdlog::formatter> sink_formatter) override; | ||||
| 
 | ||||
|     // Formatting codes
 | ||||
|     const string_view_t reset = "\033[m"; | ||||
|     const string_view_t bold = "\033[1m"; | ||||
|     const string_view_t dark = "\033[2m"; | ||||
|     const string_view_t underline = "\033[4m"; | ||||
|     const string_view_t blink = "\033[5m"; | ||||
|     const string_view_t reverse = "\033[7m"; | ||||
|     const string_view_t concealed = "\033[8m"; | ||||
|     const string_view_t clear_line = "\033[K"; | ||||
| 
 | ||||
|     // Foreground colors
 | ||||
|     const string_view_t black = "\033[30m"; | ||||
|     const string_view_t red = "\033[31m"; | ||||
|     const string_view_t green = "\033[32m"; | ||||
|     const string_view_t yellow = "\033[33m"; | ||||
|     const string_view_t blue = "\033[34m"; | ||||
|     const string_view_t magenta = "\033[35m"; | ||||
|     const string_view_t cyan = "\033[36m"; | ||||
|     const string_view_t white = "\033[37m"; | ||||
| 
 | ||||
|     /// Background colors
 | ||||
|     const string_view_t on_black = "\033[40m"; | ||||
|     const string_view_t on_red = "\033[41m"; | ||||
|     const string_view_t on_green = "\033[42m"; | ||||
|     const string_view_t on_yellow = "\033[43m"; | ||||
|     const string_view_t on_blue = "\033[44m"; | ||||
|     const string_view_t on_magenta = "\033[45m"; | ||||
|     const string_view_t on_cyan = "\033[46m"; | ||||
|     const string_view_t on_white = "\033[47m"; | ||||
| 
 | ||||
|     /// Bold colors
 | ||||
|     const string_view_t yellow_bold = "\033[33m\033[1m"; | ||||
|     const string_view_t red_bold = "\033[31m\033[1m"; | ||||
|     const string_view_t bold_on_red = "\033[1m\033[41m"; | ||||
| 
 | ||||
| private: | ||||
|     FILE *target_file_; | ||||
|     mutex_t &mutex_; | ||||
|     bool should_do_colors_; | ||||
|     std::unique_ptr<spdlog::formatter> formatter_; | ||||
|     std::array<std::string, level::n_levels> colors_; | ||||
|     void print_ccode_(const string_view_t &color_code); | ||||
|     void print_range_(const memory_buf_t &formatted, size_t start, size_t end); | ||||
|     static std::string to_string_(const string_view_t &sv); | ||||
| }; | ||||
| 
 | ||||
| template<typename ConsoleMutex> | ||||
| class ansicolor_stdout_sink : public ansicolor_sink<ConsoleMutex> | ||||
| { | ||||
| public: | ||||
|     explicit ansicolor_stdout_sink(color_mode mode = color_mode::automatic); | ||||
| }; | ||||
| 
 | ||||
| template<typename ConsoleMutex> | ||||
| 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 spdlog
 | ||||
| 
 | ||||
| #ifdef SPDLOG_HEADER_ONLY | ||||
| #    include "ansicolor_sink-inl.h" | ||||
| #endif | ||||
|  | @ -1,63 +0,0 @@ | |||
| // 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/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,52 +0,0 @@ | |||
| // Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
 | ||||
| // Distributed under the MIT License (http://opensource.org/licenses/MIT)
 | ||||
| 
 | ||||
| #pragma once | ||||
| //
 | ||||
| // base sink templated over a mutex (either dummy or real)
 | ||||
| // concrete implementation should override the sink_it_() and flush_()  methods.
 | ||||
| // locking is taken care of in this class - no locking needed by the
 | ||||
| // implementers..
 | ||||
| //
 | ||||
| 
 | ||||
| #include <spdlog/common.h> | ||||
| #include <spdlog/details/log_msg.h> | ||||
| #include <spdlog/sinks/sink.h> | ||||
| 
 | ||||
| namespace spdlog { | ||||
| namespace sinks { | ||||
| template<typename Mutex> | ||||
| class SPDLOG_API base_sink : public sink | ||||
| { | ||||
| public: | ||||
|     base_sink(); | ||||
|     explicit base_sink(std::unique_ptr<spdlog::formatter> formatter); | ||||
|     ~base_sink() override = default; | ||||
| 
 | ||||
|     base_sink(const base_sink &) = delete; | ||||
|     base_sink(base_sink &&) = delete; | ||||
| 
 | ||||
|     base_sink &operator=(const base_sink &) = delete; | ||||
|     base_sink &operator=(base_sink &&) = delete; | ||||
| 
 | ||||
|     void log(const details::log_msg &msg) final; | ||||
|     void flush() final; | ||||
|     void set_pattern(const std::string &pattern) final; | ||||
|     void set_formatter(std::unique_ptr<spdlog::formatter> sink_formatter) final; | ||||
| 
 | ||||
| protected: | ||||
|     // sink formatter
 | ||||
|     std::unique_ptr<spdlog::formatter> formatter_; | ||||
|     Mutex mutex_; | ||||
| 
 | ||||
|     virtual void sink_it_(const details::log_msg &msg) = 0; | ||||
|     virtual void flush_() = 0; | ||||
|     virtual void set_pattern_(const std::string &pattern); | ||||
|     virtual void set_formatter_(std::unique_ptr<spdlog::formatter> sink_formatter); | ||||
| }; | ||||
| } // namespace sinks
 | ||||
| } // namespace spdlog
 | ||||
| 
 | ||||
| #ifdef SPDLOG_HEADER_ONLY | ||||
| #    include "base_sink-inl.h" | ||||
| #endif | ||||
|  | @ -1,44 +0,0 @@ | |||
| // 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, const file_event_handlers &event_handlers) | ||||
|     : file_helper_{event_handlers} | ||||
| { | ||||
|     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,60 +0,0 @@ | |||
| // Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
 | ||||
| // Distributed under the MIT License (http://opensource.org/licenses/MIT)
 | ||||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| #include <spdlog/details/file_helper.h> | ||||
| #include <spdlog/details/null_mutex.h> | ||||
| #include <spdlog/sinks/base_sink.h> | ||||
| #include <spdlog/details/synchronous_factory.h> | ||||
| 
 | ||||
| #include <mutex> | ||||
| #include <string> | ||||
| 
 | ||||
| namespace spdlog { | ||||
| namespace sinks { | ||||
| /*
 | ||||
|  * Trivial file sink with single file as target | ||||
|  */ | ||||
| template<typename Mutex> | ||||
| class basic_file_sink final : public base_sink<Mutex> | ||||
| { | ||||
| public: | ||||
|     explicit basic_file_sink(const filename_t &filename, bool truncate = false, const file_event_handlers &event_handlers = {}); | ||||
|     const filename_t &filename() const; | ||||
| 
 | ||||
| protected: | ||||
|     void sink_it_(const details::log_msg &msg) override; | ||||
|     void flush_() override; | ||||
| 
 | ||||
| private: | ||||
|     details::file_helper file_helper_; | ||||
| }; | ||||
| 
 | ||||
| using basic_file_sink_mt = basic_file_sink<std::mutex>; | ||||
| using basic_file_sink_st = basic_file_sink<details::null_mutex>; | ||||
| 
 | ||||
| } // namespace sinks
 | ||||
| 
 | ||||
| //
 | ||||
| // factory functions
 | ||||
| //
 | ||||
| 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, const file_event_handlers &event_handlers = {}) | ||||
| { | ||||
|     return Factory::template create<sinks::basic_file_sink_mt>(logger_name, filename, truncate, event_handlers); | ||||
| } | ||||
| 
 | ||||
| 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, const file_event_handlers &event_handlers = {}) | ||||
| { | ||||
|     return Factory::template create<sinks::basic_file_sink_st>(logger_name, filename, truncate, event_handlers); | ||||
| } | ||||
| 
 | ||||
| } // namespace spdlog
 | ||||
| 
 | ||||
| #ifdef SPDLOG_HEADER_ONLY | ||||
| #    include "basic_file_sink-inl.h" | ||||
| #endif | ||||
|  | @ -1,294 +0,0 @@ | |||
| // Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
 | ||||
| // Distributed under the MIT License (http://opensource.org/licenses/MIT)
 | ||||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| #include <spdlog/common.h> | ||||
| #include <spdlog/details/file_helper.h> | ||||
| #include <spdlog/details/null_mutex.h> | ||||
| #include <spdlog/fmt/fmt.h> | ||||
| #include <spdlog/fmt/chrono.h> | ||||
| #include <spdlog/sinks/base_sink.h> | ||||
| #include <spdlog/details/os.h> | ||||
| #include <spdlog/details/circular_q.h> | ||||
| #include <spdlog/details/synchronous_factory.h> | ||||
| 
 | ||||
| #include <chrono> | ||||
| #include <cstdio> | ||||
| #include <ctime> | ||||
| #include <mutex> | ||||
| #include <string> | ||||
| 
 | ||||
| namespace spdlog { | ||||
| namespace sinks { | ||||
| 
 | ||||
| /*
 | ||||
|  * Generator of daily log file names in format basename.YYYY-MM-DD.ext | ||||
|  */ | ||||
| struct daily_filename_calculator | ||||
| { | ||||
|     // Create filename for the form basename.YYYY-MM-DD
 | ||||
|     static filename_t calc_filename(const filename_t &filename, const tm &now_tm) | ||||
|     { | ||||
|         filename_t basename, ext; | ||||
|         std::tie(basename, ext) = details::file_helper::split_by_extension(filename); | ||||
|         return fmt_lib::format( | ||||
|             SPDLOG_FILENAME_T("{}_{:04d}-{:02d}-{:02d}{}"), basename, now_tm.tm_year + 1900, now_tm.tm_mon + 1, now_tm.tm_mday, ext); | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| /*
 | ||||
|  * Generator of daily log file names with strftime format. | ||||
|  * Usages: | ||||
|  *    auto sink =  std::make_shared<spdlog::sinks::daily_file_format_sink_mt>("myapp-%Y-%m-%d:%H:%M:%S.log", hour, minute);" | ||||
|  *    auto logger = spdlog::daily_logger_format_mt("loggername, "myapp-%Y-%m-%d:%X.log", hour,  minute)" | ||||
|  * | ||||
|  */ | ||||
| struct daily_filename_format_calculator | ||||
| { | ||||
|     static filename_t calc_filename(const filename_t &filename, const tm &now_tm) | ||||
|     { | ||||
| #ifdef SPDLOG_USE_STD_FORMAT | ||||
|         // adapted from fmtlib: https://github.com/fmtlib/fmt/blob/8.0.1/include/fmt/chrono.h#L522-L546
 | ||||
| 
 | ||||
|         filename_t tm_format; | ||||
|         tm_format.append(filename); | ||||
|         // By appending an extra space we can distinguish an empty result that
 | ||||
|         // indicates insufficient buffer size from a guaranteed non-empty result
 | ||||
|         // https://github.com/fmtlib/fmt/issues/2238
 | ||||
|         tm_format.push_back(' '); | ||||
| 
 | ||||
|         const size_t MIN_SIZE = 10; | ||||
|         filename_t buf; | ||||
|         buf.resize(MIN_SIZE); | ||||
|         for (;;) | ||||
|         { | ||||
|             size_t count = strftime(buf.data(), buf.size(), tm_format.c_str(), &now_tm); | ||||
|             if (count != 0) | ||||
|             { | ||||
|                 // Remove the extra space.
 | ||||
|                 buf.resize(count - 1); | ||||
|                 break; | ||||
|             } | ||||
|             buf.resize(buf.size() * 2); | ||||
|         } | ||||
| 
 | ||||
|         return buf; | ||||
| #else | ||||
|         // generate fmt datetime format string, e.g. {:%Y-%m-%d}.
 | ||||
|         filename_t fmt_filename = fmt::format(SPDLOG_FILENAME_T("{{:{}}}"), filename); | ||||
| #    if defined(_MSC_VER) && defined(SPDLOG_WCHAR_FILENAMES) // for some reason msvc doesn't allow fmt::runtime(..) with wchar here
 | ||||
|         return fmt::format(fmt_filename, now_tm); | ||||
| #    else | ||||
|         return fmt::format(SPDLOG_FMT_RUNTIME(fmt_filename), now_tm); | ||||
| #    endif | ||||
| #endif | ||||
|     } | ||||
| 
 | ||||
| private: | ||||
| #if defined __GNUC__ | ||||
| #    pragma GCC diagnostic push | ||||
| #    pragma GCC diagnostic ignored "-Wformat-nonliteral" | ||||
| #endif | ||||
| 
 | ||||
|     static size_t strftime(char *str, size_t count, const char *format, const std::tm *time) | ||||
|     { | ||||
|         return std::strftime(str, count, format, time); | ||||
|     } | ||||
| 
 | ||||
|     static size_t strftime(wchar_t *str, size_t count, const wchar_t *format, const std::tm *time) | ||||
|     { | ||||
|         return std::wcsftime(str, count, format, time); | ||||
|     } | ||||
| 
 | ||||
| #if defined(__GNUC__) | ||||
| #    pragma GCC diagnostic pop | ||||
| #endif | ||||
| }; | ||||
| 
 | ||||
| /*
 | ||||
|  * 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> | ||||
| class daily_file_sink final : public base_sink<Mutex> | ||||
| { | ||||
| public: | ||||
|     // 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, uint16_t max_files = 0, | ||||
|         const file_event_handlers &event_handlers = {}) | ||||
|         : base_filename_(std::move(base_filename)) | ||||
|         , rotation_h_(rotation_hour) | ||||
|         , rotation_m_(rotation_minute) | ||||
|         , file_helper_{event_handlers} | ||||
|         , truncate_(truncate) | ||||
|         , max_files_(max_files) | ||||
|         , filenames_q_() | ||||
|     { | ||||
|         if (rotation_hour < 0 || rotation_hour > 23 || rotation_minute < 0 || rotation_minute > 59) | ||||
|         { | ||||
|             throw_spdlog_ex("daily_file_sink: Invalid rotation time in ctor"); | ||||
|         } | ||||
| 
 | ||||
|         auto now = log_clock::now(); | ||||
|         auto filename = FileNameCalc::calc_filename(base_filename_, now_tm(now)); | ||||
|         file_helper_.open(filename, truncate_); | ||||
|         rotation_tp_ = next_rotation_tp_(); | ||||
| 
 | ||||
|         if (max_files_ > 0) | ||||
|         { | ||||
|             init_filenames_q_(); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     filename_t filename() | ||||
|     { | ||||
|         std::lock_guard<Mutex> lock(base_sink<Mutex>::mutex_); | ||||
|         return file_helper_.filename(); | ||||
|     } | ||||
| 
 | ||||
| protected: | ||||
|     void sink_it_(const details::log_msg &msg) override | ||||
|     { | ||||
|         auto time = msg.time; | ||||
|         bool should_rotate = time >= rotation_tp_; | ||||
|         if (should_rotate) | ||||
|         { | ||||
|             auto filename = FileNameCalc::calc_filename(base_filename_, now_tm(time)); | ||||
|             file_helper_.open(filename, truncate_); | ||||
|             rotation_tp_ = next_rotation_tp_(); | ||||
|         } | ||||
|         memory_buf_t formatted; | ||||
|         base_sink<Mutex>::formatter_->format(msg, formatted); | ||||
|         file_helper_.write(formatted); | ||||
| 
 | ||||
|         // Do the cleaning only at the end because it might throw on failure.
 | ||||
|         if (should_rotate && max_files_ > 0) | ||||
|         { | ||||
|             delete_old_(); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     void flush_() override | ||||
|     { | ||||
|         file_helper_.flush(); | ||||
|     } | ||||
| 
 | ||||
| private: | ||||
|     void init_filenames_q_() | ||||
|     { | ||||
|         using details::os::path_exists; | ||||
| 
 | ||||
|         filenames_q_ = details::circular_q<filename_t>(static_cast<size_t>(max_files_)); | ||||
|         std::vector<filename_t> filenames; | ||||
|         auto now = log_clock::now(); | ||||
|         while (filenames.size() < max_files_) | ||||
|         { | ||||
|             auto filename = FileNameCalc::calc_filename(base_filename_, now_tm(now)); | ||||
|             if (!path_exists(filename)) | ||||
|             { | ||||
|                 break; | ||||
|             } | ||||
|             filenames.emplace_back(filename); | ||||
|             now -= std::chrono::hours(24); | ||||
|         } | ||||
|         for (auto iter = filenames.rbegin(); iter != filenames.rend(); ++iter) | ||||
|         { | ||||
|             filenames_q_.push_back(std::move(*iter)); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     tm now_tm(log_clock::time_point tp) | ||||
|     { | ||||
|         time_t tnow = log_clock::to_time_t(tp); | ||||
|         return spdlog::details::os::localtime(tnow); | ||||
|     } | ||||
| 
 | ||||
|     log_clock::time_point next_rotation_tp_() | ||||
|     { | ||||
|         auto now = log_clock::now(); | ||||
|         tm date = now_tm(now); | ||||
|         date.tm_hour = rotation_h_; | ||||
|         date.tm_min = rotation_m_; | ||||
|         date.tm_sec = 0; | ||||
|         auto rotation_time = log_clock::from_time_t(std::mktime(&date)); | ||||
|         if (rotation_time > now) | ||||
|         { | ||||
|             return rotation_time; | ||||
|         } | ||||
|         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 = file_helper_.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)); | ||||
|                 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_; | ||||
|     int rotation_h_; | ||||
|     int rotation_m_; | ||||
|     log_clock::time_point rotation_tp_; | ||||
|     details::file_helper file_helper_; | ||||
|     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_st = daily_file_sink<details::null_mutex>; | ||||
| using daily_file_format_sink_mt = daily_file_sink<std::mutex, daily_filename_format_calculator>; | ||||
| using daily_file_format_sink_st = daily_file_sink<details::null_mutex, daily_filename_format_calculator>; | ||||
| 
 | ||||
| } // namespace sinks
 | ||||
| 
 | ||||
| //
 | ||||
| // factory functions
 | ||||
| //
 | ||||
| template<typename Factory = spdlog::synchronous_factory> | ||||
| 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, uint16_t max_files = 0, const file_event_handlers &event_handlers = {}) | ||||
| { | ||||
|     return Factory::template create<sinks::daily_file_sink_mt>(logger_name, filename, hour, minute, truncate, max_files, event_handlers); | ||||
| } | ||||
| 
 | ||||
| template<typename Factory = spdlog::synchronous_factory> | ||||
| inline std::shared_ptr<logger> daily_logger_format_mt(const std::string &logger_name, const filename_t &filename, int hour = 0, | ||||
|     int minute = 0, bool truncate = false, uint16_t max_files = 0, const file_event_handlers &event_handlers = {}) | ||||
| { | ||||
|     return Factory::template create<sinks::daily_file_format_sink_mt>( | ||||
|         logger_name, filename, hour, minute, truncate, max_files, event_handlers); | ||||
| } | ||||
| 
 | ||||
| template<typename Factory = spdlog::synchronous_factory> | ||||
| 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, uint16_t max_files = 0, const file_event_handlers &event_handlers = {}) | ||||
| { | ||||
|     return Factory::template create<sinks::daily_file_sink_st>(logger_name, filename, hour, minute, truncate, max_files, event_handlers); | ||||
| } | ||||
| 
 | ||||
| template<typename Factory = spdlog::synchronous_factory> | ||||
| inline std::shared_ptr<logger> daily_logger_format_st(const std::string &logger_name, const filename_t &filename, int hour = 0, | ||||
|     int minute = 0, bool truncate = false, uint16_t max_files = 0, const file_event_handlers &event_handlers = {}) | ||||
| { | ||||
|     return Factory::template create<sinks::daily_file_format_sink_st>( | ||||
|         logger_name, filename, hour, minute, truncate, max_files, event_handlers); | ||||
| } | ||||
| } // namespace spdlog
 | ||||
|  | @ -1,97 +0,0 @@ | |||
| // Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
 | ||||
| // Distributed under the MIT License (http://opensource.org/licenses/MIT)
 | ||||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| #include "base_sink.h" | ||||
| #include <spdlog/details/log_msg.h> | ||||
| #include <spdlog/details/null_mutex.h> | ||||
| #include <spdlog/pattern_formatter.h> | ||||
| 
 | ||||
| #include <algorithm> | ||||
| #include <memory> | ||||
| #include <mutex> | ||||
| #include <vector> | ||||
| 
 | ||||
| // Distribution sink (mux). Stores a vector of sinks which get called when log
 | ||||
| // is called
 | ||||
| 
 | ||||
| namespace spdlog { | ||||
| namespace sinks { | ||||
| 
 | ||||
| template<typename Mutex> | ||||
| class dist_sink : public base_sink<Mutex> | ||||
| { | ||||
| public: | ||||
|     dist_sink() = default; | ||||
|     explicit dist_sink(std::vector<std::shared_ptr<sink>> sinks) | ||||
|         : sinks_(sinks) | ||||
|     {} | ||||
| 
 | ||||
|     dist_sink(const dist_sink &) = delete; | ||||
|     dist_sink &operator=(const dist_sink &) = delete; | ||||
| 
 | ||||
|     void add_sink(std::shared_ptr<sink> sink) | ||||
|     { | ||||
|         std::lock_guard<Mutex> lock(base_sink<Mutex>::mutex_); | ||||
|         sinks_.push_back(sink); | ||||
|     } | ||||
| 
 | ||||
|     void remove_sink(std::shared_ptr<sink> sink) | ||||
|     { | ||||
|         std::lock_guard<Mutex> lock(base_sink<Mutex>::mutex_); | ||||
|         sinks_.erase(std::remove(sinks_.begin(), sinks_.end(), sink), sinks_.end()); | ||||
|     } | ||||
| 
 | ||||
|     void set_sinks(std::vector<std::shared_ptr<sink>> sinks) | ||||
|     { | ||||
|         std::lock_guard<Mutex> lock(base_sink<Mutex>::mutex_); | ||||
|         sinks_ = std::move(sinks); | ||||
|     } | ||||
| 
 | ||||
|     std::vector<std::shared_ptr<sink>> &sinks() | ||||
|     { | ||||
|         return sinks_; | ||||
|     } | ||||
| 
 | ||||
| protected: | ||||
|     void sink_it_(const details::log_msg &msg) override | ||||
|     { | ||||
|         for (auto &sink : sinks_) | ||||
|         { | ||||
|             if (sink->should_log(msg.level)) | ||||
|             { | ||||
|                 sink->log(msg); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     void flush_() override | ||||
|     { | ||||
|         for (auto &sink : sinks_) | ||||
|         { | ||||
|             sink->flush(); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     void set_pattern_(const std::string &pattern) override | ||||
|     { | ||||
|         set_formatter_(details::make_unique<spdlog::pattern_formatter>(pattern)); | ||||
|     } | ||||
| 
 | ||||
|     void set_formatter_(std::unique_ptr<spdlog::formatter> sink_formatter) override | ||||
|     { | ||||
|         base_sink<Mutex>::formatter_ = std::move(sink_formatter); | ||||
|         for (auto &sink : sinks_) | ||||
|         { | ||||
|             sink->set_formatter(base_sink<Mutex>::formatter_->clone()); | ||||
|         } | ||||
|     } | ||||
|     std::vector<std::shared_ptr<sink>> sinks_; | ||||
| }; | ||||
| 
 | ||||
| using dist_sink_mt = dist_sink<std::mutex>; | ||||
| using dist_sink_st = dist_sink<details::null_mutex>; | ||||
| 
 | ||||
| } // namespace sinks
 | ||||
| } // namespace spdlog
 | ||||
|  | @ -1,94 +0,0 @@ | |||
| // 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 <cstdio> | ||||
| #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
 | ||||
| 
 | ||||
| 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) | ||||
|         { | ||||
|             char buf[64]; | ||||
|             auto msg_size = ::snprintf(buf, sizeof(buf), "Skipped %u duplicate messages..", static_cast<unsigned>(skip_counter_)); | ||||
|             if (msg_size > 0 && static_cast<size_t>(msg_size) < sizeof(buf)) | ||||
|             { | ||||
|                 details::log_msg skipped_msg{msg.logger_name, level::info, string_view_t{buf, static_cast<size_t>(msg_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,196 +0,0 @@ | |||
| // Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
 | ||||
| // Distributed under the MIT License (http://opensource.org/licenses/MIT)
 | ||||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| #include <spdlog/common.h> | ||||
| #include <spdlog/details/file_helper.h> | ||||
| #include <spdlog/details/null_mutex.h> | ||||
| #include <spdlog/fmt/fmt.h> | ||||
| #include <spdlog/sinks/base_sink.h> | ||||
| #include <spdlog/details/os.h> | ||||
| #include <spdlog/details/circular_q.h> | ||||
| #include <spdlog/details/synchronous_factory.h> | ||||
| 
 | ||||
| #include <chrono> | ||||
| #include <cstdio> | ||||
| #include <ctime> | ||||
| #include <mutex> | ||||
| #include <string> | ||||
| 
 | ||||
| namespace spdlog { | ||||
| namespace sinks { | ||||
| 
 | ||||
| /*
 | ||||
|  * Generator of Hourly log file names in format basename.YYYY-MM-DD-HH.ext | ||||
|  */ | ||||
| struct hourly_filename_calculator | ||||
| { | ||||
|     // Create filename for the form basename.YYYY-MM-DD-H
 | ||||
|     static filename_t calc_filename(const filename_t &filename, const tm &now_tm) | ||||
|     { | ||||
|         filename_t basename, ext; | ||||
|         std::tie(basename, ext) = details::file_helper::split_by_extension(filename); | ||||
|         return fmt_lib::format(SPDLOG_FILENAME_T("{}_{:04d}-{:02d}-{:02d}_{:02d}{}"), basename, now_tm.tm_year + 1900, now_tm.tm_mon + 1, | ||||
|             now_tm.tm_mday, now_tm.tm_hour, ext); | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| /*
 | ||||
|  * Rotating file sink based on time. | ||||
|  * 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 = hourly_filename_calculator> | ||||
| class hourly_file_sink final : public base_sink<Mutex> | ||||
| { | ||||
| public: | ||||
|     // create hourly file sink which rotates on given time
 | ||||
|     hourly_file_sink( | ||||
|         filename_t base_filename, bool truncate = false, uint16_t max_files = 0, const file_event_handlers &event_handlers = {}) | ||||
|         : base_filename_(std::move(base_filename)) | ||||
|         , file_helper_{event_handlers} | ||||
|         , truncate_(truncate) | ||||
|         , max_files_(max_files) | ||||
|         , filenames_q_() | ||||
|     { | ||||
|         auto now = log_clock::now(); | ||||
|         auto filename = FileNameCalc::calc_filename(base_filename_, now_tm(now)); | ||||
|         file_helper_.open(filename, truncate_); | ||||
|         rotation_tp_ = next_rotation_tp_(); | ||||
| 
 | ||||
|         if (max_files_ > 0) | ||||
|         { | ||||
|             init_filenames_q_(); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     filename_t filename() | ||||
|     { | ||||
|         std::lock_guard<Mutex> lock(base_sink<Mutex>::mutex_); | ||||
|         return file_helper_.filename(); | ||||
|     } | ||||
| 
 | ||||
| protected: | ||||
|     void sink_it_(const details::log_msg &msg) override | ||||
|     { | ||||
|         auto time = msg.time; | ||||
|         bool should_rotate = time >= rotation_tp_; | ||||
|         if (should_rotate) | ||||
|         { | ||||
|             auto filename = FileNameCalc::calc_filename(base_filename_, now_tm(time)); | ||||
|             file_helper_.open(filename, truncate_); | ||||
|             rotation_tp_ = next_rotation_tp_(); | ||||
|         } | ||||
|         memory_buf_t formatted; | ||||
|         base_sink<Mutex>::formatter_->format(msg, formatted); | ||||
|         file_helper_.write(formatted); | ||||
| 
 | ||||
|         // Do the cleaning only at the end because it might throw on failure.
 | ||||
|         if (should_rotate && max_files_ > 0) | ||||
|         { | ||||
|             delete_old_(); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     void flush_() override | ||||
|     { | ||||
|         file_helper_.flush(); | ||||
|     } | ||||
| 
 | ||||
| private: | ||||
|     void init_filenames_q_() | ||||
|     { | ||||
|         using details::os::path_exists; | ||||
| 
 | ||||
|         filenames_q_ = details::circular_q<filename_t>(static_cast<size_t>(max_files_)); | ||||
|         std::vector<filename_t> filenames; | ||||
|         auto now = log_clock::now(); | ||||
|         while (filenames.size() < max_files_) | ||||
|         { | ||||
|             auto filename = FileNameCalc::calc_filename(base_filename_, now_tm(now)); | ||||
|             if (!path_exists(filename)) | ||||
|             { | ||||
|                 break; | ||||
|             } | ||||
|             filenames.emplace_back(filename); | ||||
|             now -= std::chrono::hours(1); | ||||
|         } | ||||
|         for (auto iter = filenames.rbegin(); iter != filenames.rend(); ++iter) | ||||
|         { | ||||
|             filenames_q_.push_back(std::move(*iter)); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     tm now_tm(log_clock::time_point tp) | ||||
|     { | ||||
|         time_t tnow = log_clock::to_time_t(tp); | ||||
|         return spdlog::details::os::localtime(tnow); | ||||
|     } | ||||
| 
 | ||||
|     log_clock::time_point next_rotation_tp_() | ||||
|     { | ||||
|         auto now = log_clock::now(); | ||||
|         tm date = now_tm(now); | ||||
|         date.tm_min = 0; | ||||
|         date.tm_sec = 0; | ||||
|         auto rotation_time = log_clock::from_time_t(std::mktime(&date)); | ||||
|         if (rotation_time > now) | ||||
|         { | ||||
|             return rotation_time; | ||||
|         } | ||||
|         return {rotation_time + std::chrono::hours(1)}; | ||||
|     } | ||||
| 
 | ||||
|     // 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 = file_helper_.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 hourly file " + filename_to_str(old_filename), errno)); | ||||
|             } | ||||
|         } | ||||
|         filenames_q_.push_back(std::move(current_file)); | ||||
|     } | ||||
| 
 | ||||
|     filename_t base_filename_; | ||||
|     log_clock::time_point rotation_tp_; | ||||
|     details::file_helper file_helper_; | ||||
|     bool truncate_; | ||||
|     uint16_t max_files_; | ||||
|     details::circular_q<filename_t> filenames_q_; | ||||
| }; | ||||
| 
 | ||||
| using hourly_file_sink_mt = hourly_file_sink<std::mutex>; | ||||
| using hourly_file_sink_st = hourly_file_sink<details::null_mutex>; | ||||
| 
 | ||||
| } // namespace sinks
 | ||||
| 
 | ||||
| //
 | ||||
| // factory functions
 | ||||
| //
 | ||||
| template<typename Factory = spdlog::synchronous_factory> | ||||
| inline std::shared_ptr<logger> hourly_logger_mt(const std::string &logger_name, const filename_t &filename, bool truncate = false, | ||||
|     uint16_t max_files = 0, const file_event_handlers &event_handlers = {}) | ||||
| { | ||||
|     return Factory::template create<sinks::hourly_file_sink_mt>(logger_name, filename, truncate, max_files, event_handlers); | ||||
| } | ||||
| 
 | ||||
| template<typename Factory = spdlog::synchronous_factory> | ||||
| inline std::shared_ptr<logger> hourly_logger_st(const std::string &logger_name, const filename_t &filename, bool truncate = false, | ||||
|     uint16_t max_files = 0, const file_event_handlers &event_handlers = {}) | ||||
| { | ||||
|     return Factory::template create<sinks::hourly_file_sink_st>(logger_name, filename, truncate, max_files, event_handlers); | ||||
| } | ||||
| } // namespace spdlog
 | ||||
Some files were not shown because too many files have changed in this diff Show more
		Loading…
	
	Add table
		
		Reference in a new issue