mirror of
https://github.com/gabime/spdlog.git
synced 2026-01-02 01:47:54 +08:00
Compare commits
26 Commits
codex/fix-
...
0209b12c50
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0209b12c50 | ||
|
|
d2100d5d0e | ||
|
|
3f03542d2e | ||
|
|
2c1eafc884 | ||
|
|
878ad2e30b | ||
|
|
c5061bb970 | ||
|
|
ea3e747eea | ||
|
|
b3688ba102 | ||
|
|
6004e3d14a | ||
|
|
8806ca6509 | ||
|
|
cdbd64e230 | ||
|
|
88a0e07ad5 | ||
|
|
3f7e502859 | ||
|
|
dd3ca04a7a | ||
|
|
486b55554f | ||
|
|
1bea38edcc | ||
|
|
4418909af2 | ||
|
|
f1d748e5e3 | ||
|
|
3edc8036db | ||
|
|
9ecdf5c8a1 | ||
|
|
737347d2df | ||
|
|
4f2b3d52f9 | ||
|
|
4397dac510 | ||
|
|
6fd67ce169 | ||
|
|
4619e18a16 | ||
|
|
a6215527f4 |
@@ -13,7 +13,6 @@ AlignEscapedNewlines: Left
|
||||
AlwaysBreakTemplateDeclarations: Yes
|
||||
PackConstructorInitializers: Never
|
||||
BreakConstructorInitializersBeforeComma: false
|
||||
IndentPPDirectives: BeforeHash
|
||||
IndentPPDirectives: None
|
||||
SortIncludes: Never
|
||||
...
|
||||
|
||||
|
||||
5
.github/workflows/linux.yml
vendored
5
.github/workflows/linux.yml
vendored
@@ -18,9 +18,8 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
config:
|
||||
- { compiler: gcc, version: 7, build_type: Release, cppstd: 11 }
|
||||
- { compiler: gcc, version: 9, build_type: Release, cppstd: 17 }
|
||||
- { compiler: gcc, version: 11, build_type: Debug, cppstd: 20 }
|
||||
- { compiler: gcc, version: 9, build_type: Release, cppstd: 11 }
|
||||
- { compiler: gcc, version: 11, build_type: Debug, cppstd: 17 }
|
||||
- { compiler: gcc, version: 12, build_type: Release, cppstd: 20 }
|
||||
- { compiler: gcc, version: 12, build_type: Debug, cppstd: 20, asan: ON }
|
||||
- { compiler: clang, version: 12, build_type: Debug, cppstd: 17 }
|
||||
|
||||
71
.github/workflows/windows.yml
vendored
71
.github/workflows/windows.yml
vendored
@@ -75,74 +75,5 @@ jobs:
|
||||
run: |
|
||||
build\tests\${{ matrix.config.BUILD_TYPE }}\spdlog-utests.exe
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
# MSVC 2019 build matrix
|
||||
# -----------------------------------------------------------------------
|
||||
build_2019:
|
||||
runs-on: windows-2019
|
||||
strategy:
|
||||
fail-fast: true
|
||||
matrix:
|
||||
config:
|
||||
- GENERATOR: "Visual Studio 16 2019"
|
||||
BUILD_TYPE: Release
|
||||
BUILD_SHARED: 'ON'
|
||||
FATAL_ERRORS: 'ON'
|
||||
WCHAR: 'OFF'
|
||||
WCHAR_FILES: 'OFF'
|
||||
BUILD_EXAMPLE: 'ON'
|
||||
USE_STD_FORMAT: 'OFF'
|
||||
CXX_STANDARD: 17
|
||||
- GENERATOR: "Visual Studio 16 2019"
|
||||
BUILD_TYPE: Release
|
||||
BUILD_SHARED: 'ON'
|
||||
FATAL_ERRORS: 'ON'
|
||||
WCHAR: 'OFF'
|
||||
WCHAR_FILES: 'OFF'
|
||||
BUILD_EXAMPLE: 'ON'
|
||||
USE_STD_FORMAT: 'OFF'
|
||||
CXX_STANDARD: 14
|
||||
- GENERATOR: "Visual Studio 16 2019"
|
||||
BUILD_TYPE: Release
|
||||
BUILD_SHARED: 'ON'
|
||||
FATAL_ERRORS: 'ON'
|
||||
WCHAR: 'OFF'
|
||||
WCHAR_FILES: 'OFF'
|
||||
BUILD_EXAMPLE: 'ON'
|
||||
USE_STD_FORMAT: 'OFF'
|
||||
CXX_STANDARD: 11
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: CMake ${{ matrix.config.GENERATOR }} CXX=${{matrix.config.CXX_STANDARD}} WCHAR=${{matrix.config.WCHAR_FILES}} STD_FORMAT=${{matrix.config.USE_STD_FORMAT}}
|
||||
shell: pwsh
|
||||
run: |
|
||||
mkdir build
|
||||
cd build
|
||||
cmake -G "${{ matrix.config.GENERATOR }}" -A x64 `
|
||||
-D CMAKE_BUILD_TYPE=${{ matrix.config.BUILD_TYPE }} `
|
||||
-D BUILD_SHARED_LIBS=${{ matrix.config.BUILD_SHARED }} `
|
||||
-D SPDLOG_WCHAR_SUPPORT=${{ matrix.config.WCHAR }} `
|
||||
-D SPDLOG_WCHAR_FILENAMES=${{ matrix.config.WCHAR_FILES }} `
|
||||
-D SPDLOG_BUILD_EXAMPLE=${{ matrix.config.BUILD_EXAMPLE }} `
|
||||
-D SPDLOG_BUILD_EXAMPLE_HO=${{ matrix.config.BUILD_EXAMPLE }} `
|
||||
-D SPDLOG_BUILD_TESTS=ON `
|
||||
-D SPDLOG_BUILD_TESTS_HO=OFF `
|
||||
-D SPDLOG_BUILD_WARNINGS=${{ matrix.config.FATAL_ERRORS }} `
|
||||
-D SPDLOG_USE_STD_FORMAT=${{ matrix.config.USE_STD_FORMAT }} `
|
||||
-D CMAKE_CXX_STANDARD=${{ matrix.config.CXX_STANDARD }} ..
|
||||
|
||||
- name: Build
|
||||
shell: pwsh
|
||||
run: |
|
||||
cd build
|
||||
cmake --build . --parallel --config ${{ matrix.config.BUILD_TYPE }}
|
||||
|
||||
- name: Run Tests
|
||||
shell: pwsh
|
||||
env:
|
||||
PATH: ${{ env.PATH }};${{ github.workspace }}\build\_deps\catch2-build\src\${{ matrix.config.BUILD_TYPE }};${{ github.workspace }}\build\${{ matrix.config.BUILD_TYPE }}
|
||||
run: |
|
||||
build\tests\${{ matrix.config.BUILD_TYPE }}\spdlog-utests.exe
|
||||
|
||||
|
||||
@@ -19,7 +19,11 @@ include(GNUInstallDirs)
|
||||
# Set default build to release
|
||||
# ---------------------------------------------------------------------------------------
|
||||
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
|
||||
set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Choose Release or Debug" FORCE)
|
||||
# Set CMAKE_BUILD_TYPE only if this project is top-level
|
||||
if((DEFINED PROJECT_IS_TOP_LEVEL AND PROJECT_IS_TOP_LEVEL) OR (NOT DEFINED PROJECT_IS_TOP_LEVEL
|
||||
AND CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR))
|
||||
set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Choose Release or Debug" FORCE)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# ---------------------------------------------------------------------------------------
|
||||
@@ -62,6 +66,9 @@ option(SPDLOG_ENABLE_PCH "Build static or shared library using precompiled heade
|
||||
# build position independent code
|
||||
option(SPDLOG_BUILD_PIC "Build position independent code (-fPIC)" OFF)
|
||||
|
||||
# debug build postfix
|
||||
set(SPDLOG_DEBUG_POSTFIX "d" CACHE STRING "Filename postfix for libraries in debug builds")
|
||||
|
||||
# example options
|
||||
option(SPDLOG_BUILD_EXAMPLE "Build example" ${SPDLOG_MASTER_PROJECT})
|
||||
option(SPDLOG_BUILD_EXAMPLE_HO "Build header only example" OFF)
|
||||
@@ -90,6 +97,7 @@ option(SPDLOG_USE_STD_FORMAT "Use std::format instead of fmt library." 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)
|
||||
option(SPDLOG_NO_TZ_OFFSET "Omit %z timezone offset (use on platforms without tm_gmtoff)" OFF)
|
||||
|
||||
if(SPDLOG_FMT_EXTERNAL AND SPDLOG_FMT_EXTERNAL_HO)
|
||||
message(FATAL_ERROR "SPDLOG_FMT_EXTERNAL and SPDLOG_FMT_EXTERNAL_HO are mutually exclusive")
|
||||
@@ -191,7 +199,7 @@ spdlog_enable_warnings(spdlog)
|
||||
|
||||
set_target_properties(spdlog PROPERTIES VERSION ${SPDLOG_VERSION} SOVERSION
|
||||
${SPDLOG_VERSION_MAJOR}.${SPDLOG_VERSION_MINOR})
|
||||
set_target_properties(spdlog PROPERTIES DEBUG_POSTFIX d)
|
||||
set_target_properties(spdlog PROPERTIES DEBUG_POSTFIX ${SPDLOG_DEBUG_POSTFIX})
|
||||
|
||||
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)
|
||||
@@ -279,7 +287,8 @@ foreach(
|
||||
SPDLOG_NO_TLS
|
||||
SPDLOG_NO_ATOMIC_LEVELS
|
||||
SPDLOG_DISABLE_DEFAULT_LOGGER
|
||||
SPDLOG_USE_STD_FORMAT)
|
||||
SPDLOG_USE_STD_FORMAT
|
||||
SPDLOG_NO_TZ_OFFSET)
|
||||
if(${SPDLOG_OPTION})
|
||||
target_compile_definitions(spdlog PUBLIC ${SPDLOG_OPTION})
|
||||
target_compile_definitions(spdlog_header_only INTERFACE ${SPDLOG_OPTION})
|
||||
|
||||
51
LICENSE
51
LICENSE
@@ -1,26 +1,25 @@
|
||||
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://raw.githubusercontent.com/fmtlib/fmt/master/LICENSE
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016 - present, Gabi Melman and spdlog contributors.
|
||||
|
||||
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://raw.githubusercontent.com/fmtlib/fmt/master/LICENSE
|
||||
|
||||
27
README.md
27
README.md
@@ -80,7 +80,7 @@ int main()
|
||||
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::set_level(spdlog::level::debug); // Set *global* log level to debug
|
||||
spdlog::debug("This message should be displayed..");
|
||||
|
||||
// change log pattern
|
||||
@@ -224,7 +224,7 @@ void binary_example()
|
||||
```c++
|
||||
|
||||
// create a logger with 2 targets, with different log levels and formats.
|
||||
// The console will show only warnings or errors, while the file will log all.
|
||||
// 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>();
|
||||
@@ -241,6 +241,29 @@ void multi_sink_example()
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
#### Register several loggers - change global level
|
||||
```c++
|
||||
|
||||
// Creation of loggers. Set levels to all registered loggers.
|
||||
void set_level_example()
|
||||
{
|
||||
auto logger1 = spdlog::basic_logger_mt("logger1", "logs/logger1.txt");
|
||||
auto logger2 = spdlog::basic_logger_mt("logger2", "logs/logger2.txt");
|
||||
|
||||
spdlog::set_default_logger(logger2);
|
||||
spdlog::default_logger()->set_level(spdlog::level::trace); // set level for the default logger (logger2) to trace
|
||||
|
||||
spdlog::trace("trace message to the logger2 (specified as default)");
|
||||
|
||||
spdlog::set_level(spdlog::level::off) // (sic!) set level for *all* registered loggers to off (disable)
|
||||
|
||||
logger1.warn("warn message will not appear because the level set to off");
|
||||
logger2.warn("warn message will not appear because the level set to off");
|
||||
spdlog::warn("warn message will not appear because the level set to off");
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
#### User-defined callbacks about log events
|
||||
```c++
|
||||
|
||||
@@ -11,11 +11,11 @@
|
||||
#include "spdlog/sinks/basic_file_sink.h"
|
||||
|
||||
#if defined(SPDLOG_USE_STD_FORMAT)
|
||||
#include <format>
|
||||
#include <format>
|
||||
#elif defined(SPDLOG_FMT_EXTERNAL)
|
||||
#include <fmt/format.h>
|
||||
#include <fmt/format.h>
|
||||
#else
|
||||
#include "spdlog/fmt/bundled/format.h"
|
||||
#include "spdlog/fmt/bundled/format.h"
|
||||
#endif
|
||||
|
||||
#include "utils.h"
|
||||
@@ -34,9 +34,9 @@ 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
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4996) // disable fopen warning under msvc
|
||||
#endif // _MSC_VER
|
||||
|
||||
int count_lines(const char *filename) {
|
||||
int counter = 0;
|
||||
@@ -62,7 +62,7 @@ void verify_file(const char *filename, int expected_count) {
|
||||
}
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
|
||||
@@ -13,11 +13,11 @@
|
||||
#include "spdlog/sinks/rotating_file_sink.h"
|
||||
|
||||
#if defined(SPDLOG_USE_STD_FORMAT)
|
||||
#include <format>
|
||||
#include <format>
|
||||
#elif defined(SPDLOG_FMT_EXTERNAL)
|
||||
#include <fmt/format.h>
|
||||
#include <fmt/format.h>
|
||||
#else
|
||||
#include "spdlog/fmt/bundled/format.h"
|
||||
#include "spdlog/fmt/bundled/format.h"
|
||||
#endif
|
||||
|
||||
#include "utils.h"
|
||||
|
||||
@@ -183,7 +183,7 @@ void async_example() {
|
||||
// {:n} - don't split the output to lines.
|
||||
|
||||
#if !defined SPDLOG_USE_STD_FORMAT || defined(_MSC_VER)
|
||||
#include "spdlog/fmt/bin_to_hex.h"
|
||||
#include "spdlog/fmt/bin_to_hex.h"
|
||||
void binary_example() {
|
||||
std::vector<char> buf;
|
||||
for (int i = 0; i < 80; i++) {
|
||||
@@ -207,7 +207,7 @@ void binary_example() {
|
||||
|
||||
// Log a vector of numbers
|
||||
#ifndef SPDLOG_USE_STD_FORMAT
|
||||
#include "spdlog/fmt/ranges.h"
|
||||
#include "spdlog/fmt/ranges.h"
|
||||
void vector_example() {
|
||||
std::vector<int> vec = {1, 2, 3};
|
||||
spdlog::info("Vector example: {}", vec);
|
||||
@@ -301,7 +301,7 @@ void err_handler_example() {
|
||||
|
||||
// syslog example (linux/osx/freebsd)
|
||||
#ifndef _WIN32
|
||||
#include "spdlog/sinks/syslog_sink.h"
|
||||
#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);
|
||||
@@ -311,7 +311,7 @@ void syslog_example() {
|
||||
|
||||
// Android example.
|
||||
#if defined(__ANDROID__)
|
||||
#include "spdlog/sinks/android_sink.h"
|
||||
#include "spdlog/sinks/android_sink.h"
|
||||
void android_example() {
|
||||
std::string tag = "spdlog-android";
|
||||
auto android_logger = spdlog::android_logger_mt("android", tag);
|
||||
@@ -386,7 +386,7 @@ void replace_default_logger_example() {
|
||||
// thread-local storage.
|
||||
|
||||
#ifndef SPDLOG_NO_TLS
|
||||
#include "spdlog/mdc.h"
|
||||
#include "spdlog/mdc.h"
|
||||
void mdc_example() {
|
||||
spdlog::mdc::put("key1", "value1");
|
||||
spdlog::mdc::put("key2", "value2");
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef SPDLOG_HEADER_ONLY
|
||||
#include <spdlog/async_logger.h>
|
||||
#include <spdlog/async_logger.h>
|
||||
#endif
|
||||
|
||||
#include <spdlog/details/thread_pool.h>
|
||||
|
||||
@@ -70,5 +70,5 @@ private:
|
||||
} // namespace spdlog
|
||||
|
||||
#ifdef SPDLOG_HEADER_ONLY
|
||||
#include "async_logger-inl.h"
|
||||
#include "async_logger-inl.h"
|
||||
#endif
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef SPDLOG_HEADER_ONLY
|
||||
#include <spdlog/cfg/helpers.h>
|
||||
#include <spdlog/cfg/helpers.h>
|
||||
#endif
|
||||
|
||||
#include <spdlog/details/os.h>
|
||||
|
||||
@@ -25,5 +25,5 @@ SPDLOG_API void load_levels(const std::string &txt);
|
||||
} // namespace spdlog
|
||||
|
||||
#ifdef SPDLOG_HEADER_ONLY
|
||||
#include "helpers-inl.h"
|
||||
#include "helpers-inl.h"
|
||||
#endif // SPDLOG_HEADER_ONLY
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef SPDLOG_HEADER_ONLY
|
||||
#include <spdlog/common.h>
|
||||
#include <spdlog/common.h>
|
||||
#endif
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
@@ -17,57 +17,57 @@
|
||||
#include <type_traits>
|
||||
|
||||
#ifdef SPDLOG_USE_STD_FORMAT
|
||||
#include <version>
|
||||
#if __cpp_lib_format >= 202207L
|
||||
#include <format>
|
||||
#else
|
||||
#include <string_view>
|
||||
#endif
|
||||
#include <version>
|
||||
#if __cpp_lib_format >= 202207L
|
||||
#include <format>
|
||||
#else
|
||||
#include <string_view>
|
||||
#endif
|
||||
#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
|
||||
#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
|
||||
#define SPDLOG_API
|
||||
#define SPDLOG_HEADER_ONLY
|
||||
#define SPDLOG_INLINE inline
|
||||
#endif // #ifdef SPDLOG_COMPILED_LIB
|
||||
|
||||
#include <spdlog/fmt/fmt.h>
|
||||
|
||||
#if !defined(SPDLOG_USE_STD_FORMAT) && \
|
||||
FMT_VERSION >= 80000 // backward compatibility with fmt versions older than 8
|
||||
#define SPDLOG_FMT_RUNTIME(format_string) fmt::runtime(format_string)
|
||||
#define SPDLOG_FMT_STRING(format_string) FMT_STRING(format_string)
|
||||
#if defined(SPDLOG_WCHAR_FILENAMES) || defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT)
|
||||
#include <spdlog/fmt/xchar.h>
|
||||
#endif
|
||||
#define SPDLOG_FMT_RUNTIME(format_string) fmt::runtime(format_string)
|
||||
#define SPDLOG_FMT_STRING(format_string) FMT_STRING(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
|
||||
#define SPDLOG_FMT_STRING(format_string) format_string
|
||||
#define SPDLOG_FMT_RUNTIME(format_string) format_string
|
||||
#define SPDLOG_FMT_STRING(format_string) format_string
|
||||
#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_NOEXCEPT _NOEXCEPT
|
||||
#define SPDLOG_CONSTEXPR
|
||||
#else
|
||||
#define SPDLOG_NOEXCEPT noexcept
|
||||
#define SPDLOG_CONSTEXPR constexpr
|
||||
#define SPDLOG_NOEXCEPT noexcept
|
||||
#define SPDLOG_CONSTEXPR constexpr
|
||||
#endif
|
||||
|
||||
// If building with std::format, can just use constexpr, otherwise if building with fmt
|
||||
@@ -76,48 +76,48 @@
|
||||
// depending on the compiler
|
||||
// If fmt determines it can't use constexpr, we should inline the function instead
|
||||
#ifdef SPDLOG_USE_STD_FORMAT
|
||||
#define SPDLOG_CONSTEXPR_FUNC constexpr
|
||||
#define SPDLOG_CONSTEXPR_FUNC constexpr
|
||||
#else // Being built with fmt
|
||||
#if FMT_USE_CONSTEXPR
|
||||
#define SPDLOG_CONSTEXPR_FUNC FMT_CONSTEXPR
|
||||
#else
|
||||
#define SPDLOG_CONSTEXPR_FUNC inline
|
||||
#endif
|
||||
#if FMT_USE_CONSTEXPR
|
||||
#define SPDLOG_CONSTEXPR_FUNC FMT_CONSTEXPR
|
||||
#else
|
||||
#define SPDLOG_CONSTEXPR_FUNC inline
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
#define SPDLOG_DEPRECATED __attribute__((deprecated))
|
||||
#define SPDLOG_DEPRECATED __attribute__((deprecated))
|
||||
#elif defined(_MSC_VER)
|
||||
#define SPDLOG_DEPRECATED __declspec(deprecated)
|
||||
#define SPDLOG_DEPRECATED __declspec(deprecated)
|
||||
#else
|
||||
#define SPDLOG_DEPRECATED
|
||||
#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
|
||||
#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__)
|
||||
#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
|
||||
#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 &) { \
|
||||
}
|
||||
#define SPDLOG_TRY try
|
||||
#define SPDLOG_THROW(ex) throw(ex)
|
||||
#define SPDLOG_CATCH_STD \
|
||||
catch (const std::exception &) { \
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace spdlog {
|
||||
@@ -130,12 +130,12 @@ 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)
|
||||
// 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
|
||||
#define SPDLOG_FILENAME_T(s) s
|
||||
#endif
|
||||
|
||||
using log_clock = std::chrono::system_clock;
|
||||
@@ -149,28 +149,28 @@ using string_view_t = std::string_view;
|
||||
using memory_buf_t = std::string;
|
||||
|
||||
template <typename... Args>
|
||||
#if __cpp_lib_format >= 202207L
|
||||
#if __cpp_lib_format >= 202207L
|
||||
using format_string_t = std::format_string<Args...>;
|
||||
#else
|
||||
#else
|
||||
using format_string_t = std::string_view;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
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)
|
||||
#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>
|
||||
#if __cpp_lib_format >= 202207L
|
||||
#if __cpp_lib_format >= 202207L
|
||||
using wformat_string_t = std::wformat_string<Args...>;
|
||||
#else
|
||||
#else
|
||||
using wformat_string_t = std::wstring_view;
|
||||
#endif
|
||||
#endif
|
||||
#define SPDLOG_BUF_TO_STRING(x) x
|
||||
#endif
|
||||
#endif
|
||||
#define SPDLOG_BUF_TO_STRING(x) x
|
||||
#else // use fmt lib instead of std::format
|
||||
namespace fmt_lib = fmt;
|
||||
|
||||
@@ -184,11 +184,11 @@ template <class T>
|
||||
using remove_cvref_t = typename std::remove_cv<typename std::remove_reference<T>::type>::type;
|
||||
|
||||
template <typename Char>
|
||||
#if FMT_VERSION >= 90101
|
||||
#if FMT_VERSION >= 90101
|
||||
using fmt_runtime_string = fmt::runtime_format_string<Char>;
|
||||
#else
|
||||
#else
|
||||
using fmt_runtime_string = fmt::basic_runtime<Char>;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// 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
|
||||
@@ -200,21 +200,21 @@ struct is_convertible_to_basic_format_string
|
||||
std::is_same<remove_cvref_t<T>, fmt_runtime_string<Char>>::value> {
|
||||
};
|
||||
|
||||
#if defined(SPDLOG_WCHAR_FILENAMES) || defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT)
|
||||
#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
|
||||
#define SPDLOG_BUF_TO_STRING(x) fmt::to_string(x)
|
||||
#endif
|
||||
#define SPDLOG_BUF_TO_STRING(x) fmt::to_string(x)
|
||||
#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
|
||||
#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
|
||||
@@ -237,7 +237,7 @@ using level_t = std::atomic<int>;
|
||||
#define SPDLOG_LEVEL_OFF 6
|
||||
|
||||
#if !defined(SPDLOG_ACTIVE_LEVEL)
|
||||
#define SPDLOG_ACTIVE_LEVEL SPDLOG_LEVEL_INFO
|
||||
#define SPDLOG_ACTIVE_LEVEL SPDLOG_LEVEL_INFO
|
||||
#endif
|
||||
|
||||
// Log level enum
|
||||
@@ -262,18 +262,18 @@ enum level_enum : int {
|
||||
#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 \
|
||||
}
|
||||
#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" }
|
||||
#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;
|
||||
@@ -402,5 +402,5 @@ constexpr T conditional_static_cast(U value) {
|
||||
} // namespace spdlog
|
||||
|
||||
#ifdef SPDLOG_HEADER_ONLY
|
||||
#include "common-inl.h"
|
||||
#include "common-inl.h"
|
||||
#endif
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef SPDLOG_HEADER_ONLY
|
||||
#include <spdlog/details/backtracer.h>
|
||||
#include <spdlog/details/backtracer.h>
|
||||
#endif
|
||||
namespace spdlog {
|
||||
namespace details {
|
||||
|
||||
@@ -41,5 +41,5 @@ public:
|
||||
} // namespace spdlog
|
||||
|
||||
#ifdef SPDLOG_HEADER_ONLY
|
||||
#include "backtracer-inl.h"
|
||||
#include "backtracer-inl.h"
|
||||
#endif
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef SPDLOG_HEADER_ONLY
|
||||
#include <spdlog/details/file_helper.h>
|
||||
#include <spdlog/details/file_helper.h>
|
||||
#endif
|
||||
|
||||
#include <spdlog/common.h>
|
||||
|
||||
@@ -57,5 +57,5 @@ private:
|
||||
} // namespace spdlog
|
||||
|
||||
#ifdef SPDLOG_HEADER_ONLY
|
||||
#include "file_helper-inl.h"
|
||||
#include "file_helper-inl.h"
|
||||
#endif
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
#include <type_traits>
|
||||
|
||||
#ifdef SPDLOG_USE_STD_FORMAT
|
||||
#include <charconv>
|
||||
#include <limits>
|
||||
#include <charconv>
|
||||
#include <limits>
|
||||
#endif
|
||||
|
||||
// Some fmt helpers to efficiently format and pad ints and strings
|
||||
@@ -70,13 +70,13 @@ inline unsigned int count_digits(T n) {
|
||||
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
|
||||
// fmt 7.0.0 renamed the internal namespace to detail.
|
||||
// See: https://github.com/fmtlib/fmt/issues/1538
|
||||
#if FMT_VERSION < 70000
|
||||
internal
|
||||
#else
|
||||
#else
|
||||
detail
|
||||
#endif
|
||||
#endif
|
||||
::count_digits(static_cast<count_type>(n)));
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef SPDLOG_HEADER_ONLY
|
||||
#include <spdlog/details/log_msg.h>
|
||||
#include <spdlog/details/log_msg.h>
|
||||
#endif
|
||||
|
||||
#include <spdlog/details/os.h>
|
||||
|
||||
@@ -36,5 +36,5 @@ struct SPDLOG_API log_msg {
|
||||
} // namespace spdlog
|
||||
|
||||
#ifdef SPDLOG_HEADER_ONLY
|
||||
#include "log_msg-inl.h"
|
||||
#include "log_msg-inl.h"
|
||||
#endif
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef SPDLOG_HEADER_ONLY
|
||||
#include <spdlog/details/log_msg_buffer.h>
|
||||
#include <spdlog/details/log_msg_buffer.h>
|
||||
#endif
|
||||
|
||||
namespace spdlog {
|
||||
|
||||
@@ -28,5 +28,5 @@ public:
|
||||
} // namespace spdlog
|
||||
|
||||
#ifdef SPDLOG_HEADER_ONLY
|
||||
#include "log_msg_buffer-inl.h"
|
||||
#include "log_msg_buffer-inl.h"
|
||||
#endif
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef SPDLOG_HEADER_ONLY
|
||||
#include <spdlog/details/os.h>
|
||||
#include <spdlog/details/os.h>
|
||||
#endif
|
||||
|
||||
#include <spdlog/common.h>
|
||||
@@ -22,51 +22,50 @@
|
||||
#include <thread>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <spdlog/details/windows_include.h>
|
||||
#include <fileapi.h> // for FlushFileBuffers
|
||||
#include <io.h> // for _get_osfhandle, _isatty, _fileno
|
||||
#include <process.h> // for _get_pid
|
||||
#include <spdlog/details/windows_include.h>
|
||||
#include <io.h> // for _get_osfhandle, _isatty, _fileno
|
||||
#include <process.h> // for _get_pid
|
||||
|
||||
#ifdef __MINGW32__
|
||||
#include <share.h>
|
||||
#endif
|
||||
#ifdef __MINGW32__
|
||||
#include <share.h>
|
||||
#endif
|
||||
|
||||
#if defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) || defined(SPDLOG_WCHAR_FILENAMES)
|
||||
#include <cassert>
|
||||
#include <limits>
|
||||
#endif
|
||||
#if defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) || defined(SPDLOG_WCHAR_FILENAMES)
|
||||
#include <cassert>
|
||||
#include <limits>
|
||||
#endif
|
||||
|
||||
#include <direct.h> // for _mkdir/_wmkdir
|
||||
#include <direct.h> // for _mkdir/_wmkdir
|
||||
|
||||
#else // unix
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifdef __linux__
|
||||
#include <sys/syscall.h> //Use gettid() syscall under linux to get thread id
|
||||
#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(_AIX)
|
||||
#include <pthread.h> // for pthread_getthrds_np
|
||||
|
||||
#elif defined(__DragonFly__) || defined(__FreeBSD__)
|
||||
#include <pthread_np.h> // for pthread_getthreadid_np
|
||||
#elif defined(__DragonFly__) || defined(__FreeBSD__)
|
||||
#include <pthread_np.h> // for pthread_getthreadid_np
|
||||
|
||||
#elif defined(__NetBSD__)
|
||||
#include <lwp.h> // for _lwp_self
|
||||
#elif defined(__NetBSD__)
|
||||
#include <lwp.h> // for _lwp_self
|
||||
|
||||
#elif defined(__sun)
|
||||
#include <thread.h> // for thr_self
|
||||
#endif
|
||||
#elif defined(__sun)
|
||||
#include <thread.h> // for thr_self
|
||||
#endif
|
||||
|
||||
#endif // unix
|
||||
|
||||
#if defined __APPLE__
|
||||
#include <AvailabilityMacros.h>
|
||||
#include <AvailabilityMacros.h>
|
||||
#endif
|
||||
|
||||
#ifndef __has_feature // Clang - feature checking macros.
|
||||
#define __has_feature(x) 0 // Compatibility with non-clang compilers.
|
||||
#ifndef __has_feature // Clang - feature checking macros.
|
||||
#define __has_feature(x) 0 // Compatibility with non-clang compilers.
|
||||
#endif
|
||||
|
||||
namespace spdlog {
|
||||
@@ -120,12 +119,12 @@ SPDLOG_INLINE std::tm gmtime() SPDLOG_NOEXCEPT {
|
||||
// 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
|
||||
#ifdef SPDLOG_WCHAR_FILENAMES
|
||||
*fp = ::_wfsopen((filename.c_str()), mode.c_str(), _SH_DENYNO);
|
||||
#else
|
||||
#else
|
||||
*fp = ::_fsopen((filename.c_str()), mode.c_str(), _SH_DENYNO);
|
||||
#endif
|
||||
#if defined(SPDLOG_PREVENT_CHILD_FD)
|
||||
#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)) {
|
||||
@@ -133,9 +132,9 @@ SPDLOG_INLINE bool fopen_s(FILE **fp, const filename_t &filename, const filename
|
||||
*fp = nullptr;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
#else // unix
|
||||
#if defined(SPDLOG_PREVENT_CHILD_FD)
|
||||
#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));
|
||||
@@ -146,9 +145,9 @@ SPDLOG_INLINE bool fopen_s(FILE **fp, const filename_t &filename, const filename
|
||||
if (*fp == nullptr) {
|
||||
::close(fd);
|
||||
}
|
||||
#else
|
||||
#else
|
||||
*fp = ::fopen((filename.c_str()), mode.c_str());
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
return *fp == nullptr;
|
||||
@@ -178,11 +177,11 @@ SPDLOG_INLINE int rename(const filename_t &filename1, const filename_t &filename
|
||||
SPDLOG_INLINE bool path_exists(const filename_t &filename) SPDLOG_NOEXCEPT {
|
||||
#ifdef _WIN32
|
||||
struct _stat buffer;
|
||||
#ifdef SPDLOG_WCHAR_FILENAMES
|
||||
#ifdef SPDLOG_WCHAR_FILENAMES
|
||||
return (::_wstat(filename.c_str(), &buffer) == 0);
|
||||
#else
|
||||
#else
|
||||
return (::_stat(filename.c_str(), &buffer) == 0);
|
||||
#endif
|
||||
#endif
|
||||
#else // common linux/unix all have the stat system call
|
||||
struct stat buffer;
|
||||
return (::stat(filename.c_str(), &buffer) == 0);
|
||||
@@ -190,9 +189,9 @@ SPDLOG_INLINE bool path_exists(const filename_t &filename) SPDLOG_NOEXCEPT {
|
||||
}
|
||||
|
||||
#ifdef _MSC_VER
|
||||
// avoid warning about unreachable statement at the end of filesize()
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4702)
|
||||
// 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
|
||||
@@ -202,58 +201,59 @@ SPDLOG_INLINE size_t filesize(FILE *f) {
|
||||
}
|
||||
#if defined(_WIN32) && !defined(__CYGWIN__)
|
||||
int fd = ::_fileno(f);
|
||||
#if defined(_WIN64) // 64 bits
|
||||
#if defined(_WIN64) // 64 bits
|
||||
__int64 ret = ::_filelengthi64(fd);
|
||||
if (ret >= 0) {
|
||||
return static_cast<size_t>(ret);
|
||||
}
|
||||
|
||||
#else // windows 32 bits
|
||||
#else // windows 32 bits
|
||||
long ret = ::_filelength(fd);
|
||||
if (ret >= 0) {
|
||||
return static_cast<size_t>(ret);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#else // unix
|
||||
// OpenBSD and AIX doesn't compile with :: before the fileno(..)
|
||||
#if defined(__OpenBSD__) || defined(_AIX)
|
||||
// OpenBSD and AIX doesn't compile with :: before the fileno(..)
|
||||
#if defined(__OpenBSD__) || defined(_AIX)
|
||||
int fd = fileno(f);
|
||||
#else
|
||||
#else
|
||||
int fd = ::fileno(f);
|
||||
#endif
|
||||
// 64 bits(but not in osx, linux/musl or cygwin, where fstat64 is deprecated)
|
||||
#if ((defined(__linux__) && defined(__GLIBC__)) || defined(__sun) || defined(_AIX)) && \
|
||||
(defined(__LP64__) || defined(_LP64))
|
||||
#endif
|
||||
// 64 bits(but not in osx, linux/musl or cygwin, where fstat64 is deprecated)
|
||||
#if ((defined(__linux__) && defined(__GLIBC__)) || 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
|
||||
#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
|
||||
#endif
|
||||
throw_spdlog_ex("Failed getting file size from fd", errno);
|
||||
return 0; // will not be reached.
|
||||
}
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
// Return utc offset in minutes or throw spdlog_ex on failure
|
||||
#if !defined(SPDLOG_NO_TZ_OFFSET)
|
||||
SPDLOG_INLINE int utc_minutes_offset(const std::tm &tm) {
|
||||
#ifdef _WIN32
|
||||
#if _WIN32_WINNT < _WIN32_WINNT_WS08
|
||||
#if _WIN32_WINNT < _WIN32_WINNT_WS08
|
||||
TIME_ZONE_INFORMATION tzinfo;
|
||||
auto rv = ::GetTimeZoneInformation(&tzinfo);
|
||||
#else
|
||||
#else
|
||||
DYNAMIC_TIME_ZONE_INFORMATION tzinfo;
|
||||
auto rv = ::GetDynamicTimeZoneInformation(&tzinfo);
|
||||
#endif
|
||||
#endif
|
||||
if (rv == TIME_ZONE_ID_INVALID) throw_spdlog_ex("Failed getting timezone info. ", errno);
|
||||
|
||||
int offset = -tzinfo.Bias;
|
||||
@@ -264,46 +264,11 @@ SPDLOG_INLINE int utc_minutes_offset(const std::tm &tm) {
|
||||
}
|
||||
return offset;
|
||||
#else
|
||||
|
||||
#if defined(sun) || defined(__sun) || defined(_AIX) || \
|
||||
(defined(__NEWLIB__) && !defined(__TM_GMTOFF)) || \
|
||||
(!defined(__APPLE__) && !defined(_BSD_SOURCE) && !defined(_GNU_SOURCE) && \
|
||||
(!defined(_POSIX_VERSION) || (_POSIX_VERSION < 202405L)))
|
||||
// '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
|
||||
}
|
||||
#endif // SPDLOG_NO_TZ_OFFSET
|
||||
|
||||
// Return current thread id as size_t
|
||||
// It exists because the std::this_thread::get_id() is much slower(especially
|
||||
@@ -312,9 +277,9 @@ 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
|
||||
#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;
|
||||
@@ -333,25 +298,25 @@ SPDLOG_INLINE size_t _thread_id() SPDLOG_NOEXCEPT {
|
||||
return static_cast<size_t>(::thr_self());
|
||||
#elif __APPLE__
|
||||
uint64_t tid;
|
||||
// There is no pthread_threadid_np prior to Mac OS X 10.6, and it is not supported on any PPC,
|
||||
// including 10.6.8 Rosetta. __POWERPC__ is Apple-specific define encompassing ppc and ppc64.
|
||||
#ifdef MAC_OS_X_VERSION_MAX_ALLOWED
|
||||
// There is no pthread_threadid_np prior to Mac OS X 10.6, and it is not supported on any PPC,
|
||||
// including 10.6.8 Rosetta. __POWERPC__ is Apple-specific define encompassing ppc and ppc64.
|
||||
#ifdef MAC_OS_X_VERSION_MAX_ALLOWED
|
||||
{
|
||||
#if (MAC_OS_X_VERSION_MAX_ALLOWED < 1060) || defined(__POWERPC__)
|
||||
#if (MAC_OS_X_VERSION_MAX_ALLOWED < 1060) || defined(__POWERPC__)
|
||||
tid = pthread_mach_thread_np(pthread_self());
|
||||
#elif MAC_OS_X_VERSION_MIN_REQUIRED < 1060
|
||||
#elif MAC_OS_X_VERSION_MIN_REQUIRED < 1060
|
||||
if (&pthread_threadid_np) {
|
||||
pthread_threadid_np(nullptr, &tid);
|
||||
} else {
|
||||
tid = pthread_mach_thread_np(pthread_self());
|
||||
}
|
||||
#else
|
||||
#else
|
||||
pthread_threadid_np(nullptr, &tid);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
#else
|
||||
pthread_threadid_np(nullptr, &tid);
|
||||
#endif
|
||||
#endif
|
||||
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()));
|
||||
@@ -490,7 +455,7 @@ SPDLOG_INLINE void utf8_to_wstrbuf(string_view_t str, wmemory_buf_t &target) {
|
||||
result_size =
|
||||
::MultiByteToWideChar(CP_UTF8, 0, str.data(), str_size, target.data(), result_size);
|
||||
if (result_size > 0) {
|
||||
assert(result_size == target.size());
|
||||
assert(result_size == static_cast<int>(target.size()));
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -504,11 +469,11 @@ SPDLOG_INLINE void utf8_to_wstrbuf(string_view_t str, wmemory_buf_t &target) {
|
||||
// return true on success
|
||||
static SPDLOG_INLINE bool mkdir_(const filename_t &path) {
|
||||
#ifdef _WIN32
|
||||
#ifdef SPDLOG_WCHAR_FILENAMES
|
||||
#ifdef SPDLOG_WCHAR_FILENAMES
|
||||
return ::_wmkdir(path.c_str()) == 0;
|
||||
#else
|
||||
#else
|
||||
return ::_mkdir(path.c_str()) == 0;
|
||||
#endif
|
||||
#endif
|
||||
#else
|
||||
return ::mkdir(path.c_str(), mode_t(0755)) == 0;
|
||||
#endif
|
||||
@@ -564,11 +529,12 @@ SPDLOG_INLINE filename_t dir_name(const filename_t &path) {
|
||||
}
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4996)
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4996)
|
||||
#endif // _MSC_VER
|
||||
std::string SPDLOG_INLINE getenv(const char *field) {
|
||||
#if defined(_MSC_VER) && defined(__cplusplus_winrt)
|
||||
#if defined(_MSC_VER) && defined(WINAPI_FAMILY) && defined(WINAPI_FAMILY_DESKTOP_APP) && \
|
||||
(WINAPI_FAMILY != WINAPI_FAMILY_DESKTOP_APP)
|
||||
return std::string{}; // not supported under uwp
|
||||
#else
|
||||
char *buf = std::getenv(field);
|
||||
@@ -576,7 +542,7 @@ std::string SPDLOG_INLINE getenv(const char *field) {
|
||||
#endif
|
||||
}
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#pragma warning(pop)
|
||||
#endif // _MSC_VER
|
||||
|
||||
// Do fsync by FILE handlerpointer
|
||||
|
||||
@@ -22,22 +22,22 @@ 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
|
||||
#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
|
||||
#ifdef _WIN32
|
||||
#define SPDLOG_FOLDER_SEPS "\\/"
|
||||
#else
|
||||
#define SPDLOG_FOLDER_SEPS "/"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
SPDLOG_CONSTEXPR static const char folder_seps[] = SPDLOG_FOLDER_SEPS;
|
||||
@@ -123,5 +123,5 @@ SPDLOG_API bool fwrite_bytes(const void *ptr, const size_t n_bytes, FILE *fp);
|
||||
} // namespace spdlog
|
||||
|
||||
#ifdef SPDLOG_HEADER_ONLY
|
||||
#include "os-inl.h"
|
||||
#include "os-inl.h"
|
||||
#endif
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef SPDLOG_HEADER_ONLY
|
||||
#include <spdlog/details/periodic_worker.h>
|
||||
#include <spdlog/details/periodic_worker.h>
|
||||
#endif
|
||||
|
||||
namespace spdlog {
|
||||
|
||||
@@ -54,5 +54,5 @@ private:
|
||||
} // namespace spdlog
|
||||
|
||||
#ifdef SPDLOG_HEADER_ONLY
|
||||
#include "periodic_worker-inl.h"
|
||||
#include "periodic_worker-inl.h"
|
||||
#endif
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef SPDLOG_HEADER_ONLY
|
||||
#include <spdlog/details/registry.h>
|
||||
#include <spdlog/details/registry.h>
|
||||
#endif
|
||||
|
||||
#include <spdlog/common.h>
|
||||
@@ -13,12 +13,12 @@
|
||||
#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
|
||||
// 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>
|
||||
@@ -33,12 +33,12 @@ 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
|
||||
// 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
|
||||
#else
|
||||
auto color_sink = std::make_shared<sinks::ansicolor_stdout_sink_mt>();
|
||||
#endif
|
||||
#endif
|
||||
|
||||
const char *default_logger_name = "";
|
||||
default_logger_ = std::make_shared<spdlog::logger>(default_logger_name, std::move(color_sink));
|
||||
|
||||
@@ -127,5 +127,5 @@ private:
|
||||
} // namespace spdlog
|
||||
|
||||
#ifdef SPDLOG_HEADER_ONLY
|
||||
#include "registry-inl.h"
|
||||
#include "registry-inl.h"
|
||||
#endif
|
||||
|
||||
@@ -58,8 +58,81 @@ public:
|
||||
|
||||
SOCKET fd() const { return socket_; }
|
||||
|
||||
int connect_socket_with_timeout(SOCKET sockfd,
|
||||
const struct sockaddr *addr,
|
||||
int addrlen,
|
||||
const timeval &tv) {
|
||||
// If no timeout requested, do a normal blocking connect.
|
||||
if (tv.tv_sec == 0 && tv.tv_usec == 0) {
|
||||
int rv = ::connect(sockfd, addr, addrlen);
|
||||
if (rv == SOCKET_ERROR && WSAGetLastError() == WSAEISCONN) {
|
||||
return 0;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
// Switch to non‐blocking mode
|
||||
u_long mode = 1UL;
|
||||
if (::ioctlsocket(sockfd, FIONBIO, &mode) == SOCKET_ERROR) {
|
||||
return SOCKET_ERROR;
|
||||
}
|
||||
|
||||
int rv = ::connect(sockfd, addr, addrlen);
|
||||
int last_error = WSAGetLastError();
|
||||
if (rv == 0 || last_error == WSAEISCONN) {
|
||||
mode = 0UL;
|
||||
if (::ioctlsocket(sockfd, FIONBIO, &mode) == SOCKET_ERROR) {
|
||||
return SOCKET_ERROR;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
if (last_error != WSAEWOULDBLOCK) {
|
||||
// Real error
|
||||
mode = 0UL;
|
||||
if (::ioctlsocket(sockfd, FIONBIO, &mode)) {
|
||||
return SOCKET_ERROR;
|
||||
}
|
||||
return SOCKET_ERROR;
|
||||
}
|
||||
|
||||
// Wait until socket is writable or timeout expires
|
||||
fd_set wfds;
|
||||
FD_ZERO(&wfds);
|
||||
FD_SET(sockfd, &wfds);
|
||||
|
||||
rv = ::select(0, nullptr, &wfds, nullptr, const_cast<timeval *>(&tv));
|
||||
|
||||
// Restore blocking mode regardless of select result
|
||||
mode = 0UL;
|
||||
if (::ioctlsocket(sockfd, FIONBIO, &mode) == SOCKET_ERROR) {
|
||||
return SOCKET_ERROR;
|
||||
}
|
||||
|
||||
if (rv == 0) {
|
||||
WSASetLastError(WSAETIMEDOUT);
|
||||
return SOCKET_ERROR;
|
||||
}
|
||||
if (rv == SOCKET_ERROR) {
|
||||
return SOCKET_ERROR;
|
||||
}
|
||||
|
||||
int so_error = 0;
|
||||
int len = sizeof(so_error);
|
||||
if (::getsockopt(sockfd, SOL_SOCKET, SO_ERROR, reinterpret_cast<char *>(&so_error), &len) ==
|
||||
SOCKET_ERROR) {
|
||||
return SOCKET_ERROR;
|
||||
}
|
||||
if (so_error != 0 && so_error != WSAEISCONN) {
|
||||
// connection failed
|
||||
WSASetLastError(so_error);
|
||||
return SOCKET_ERROR;
|
||||
}
|
||||
|
||||
return 0; // success
|
||||
}
|
||||
|
||||
// try to connect or throw on failure
|
||||
void connect(const std::string &host, int port) {
|
||||
void connect(const std::string &host, int port, int timeout_ms = 0) {
|
||||
if (is_connected()) {
|
||||
close();
|
||||
}
|
||||
@@ -71,6 +144,10 @@ public:
|
||||
hints.ai_flags = AI_NUMERICSERV; // port passed as as numeric value
|
||||
hints.ai_protocol = 0;
|
||||
|
||||
timeval tv;
|
||||
tv.tv_sec = timeout_ms / 1000;
|
||||
tv.tv_usec = (timeout_ms % 1000) * 1000;
|
||||
|
||||
auto port_str = std::to_string(port);
|
||||
struct addrinfo *addrinfo_result;
|
||||
auto rv = ::getaddrinfo(host.c_str(), port_str.c_str(), &hints, &addrinfo_result);
|
||||
@@ -82,7 +159,6 @@ public:
|
||||
}
|
||||
|
||||
// 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) {
|
||||
@@ -90,18 +166,24 @@ public:
|
||||
WSACleanup();
|
||||
continue;
|
||||
}
|
||||
if (::connect(socket_, rp->ai_addr, (int)rp->ai_addrlen) == 0) {
|
||||
if (connect_socket_with_timeout(socket_, rp->ai_addr, (int)rp->ai_addrlen, tv) == 0) {
|
||||
last_error = 0;
|
||||
break;
|
||||
} else {
|
||||
last_error = ::WSAGetLastError();
|
||||
close();
|
||||
}
|
||||
last_error = WSAGetLastError();
|
||||
::closesocket(socket_);
|
||||
socket_ = INVALID_SOCKET;
|
||||
}
|
||||
::freeaddrinfo(addrinfo_result);
|
||||
if (socket_ == INVALID_SOCKET) {
|
||||
WSACleanup();
|
||||
throw_winsock_error_("connect failed", last_error);
|
||||
}
|
||||
if (timeout_ms > 0) {
|
||||
DWORD tv = static_cast<DWORD>(timeout_ms);
|
||||
::setsockopt(socket_, SOL_SOCKET, SO_RCVTIMEO, (const char *)&tv, sizeof(tv));
|
||||
::setsockopt(socket_, SOL_SOCKET, SO_SNDTIMEO, (const char *)&tv, sizeof(tv));
|
||||
}
|
||||
|
||||
// set TCP_NODELAY
|
||||
int enable_flag = 1;
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef _WIN32
|
||||
#error include tcp_client-windows.h instead
|
||||
#error include tcp_client-windows.h instead
|
||||
#endif
|
||||
|
||||
// tcp client helper
|
||||
@@ -17,6 +17,7 @@
|
||||
#include <netinet/tcp.h>
|
||||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
@@ -39,8 +40,72 @@ public:
|
||||
|
||||
~tcp_client() { close(); }
|
||||
|
||||
int connect_socket_with_timeout(int sockfd,
|
||||
const struct sockaddr *addr,
|
||||
socklen_t addrlen,
|
||||
const timeval &tv) {
|
||||
// Blocking connect if timeout is zero
|
||||
if (tv.tv_sec == 0 && tv.tv_usec == 0) {
|
||||
int rv = ::connect(sockfd, addr, addrlen);
|
||||
if (rv < 0 && errno == EISCONN) {
|
||||
// already connected, treat as success
|
||||
return 0;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
// Non-blocking path
|
||||
int orig_flags = ::fcntl(sockfd, F_GETFL, 0);
|
||||
if (orig_flags < 0) {
|
||||
return -1;
|
||||
}
|
||||
if (::fcntl(sockfd, F_SETFL, orig_flags | O_NONBLOCK) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int rv = ::connect(sockfd, addr, addrlen);
|
||||
if (rv == 0 || (rv < 0 && errno == EISCONN)) {
|
||||
// immediate connect or already connected
|
||||
::fcntl(sockfd, F_SETFL, orig_flags);
|
||||
return 0;
|
||||
}
|
||||
if (errno != EINPROGRESS) {
|
||||
::fcntl(sockfd, F_SETFL, orig_flags);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// wait for writability
|
||||
fd_set wfds;
|
||||
FD_ZERO(&wfds);
|
||||
FD_SET(sockfd, &wfds);
|
||||
|
||||
struct timeval tv_copy = tv;
|
||||
rv = ::select(sockfd + 1, nullptr, &wfds, nullptr, &tv_copy);
|
||||
if (rv <= 0) {
|
||||
// timeout or error
|
||||
::fcntl(sockfd, F_SETFL, orig_flags);
|
||||
if (rv == 0) errno = ETIMEDOUT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// check socket error
|
||||
int so_error = 0;
|
||||
socklen_t len = sizeof(so_error);
|
||||
if (::getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &so_error, &len) < 0) {
|
||||
::fcntl(sockfd, F_SETFL, orig_flags);
|
||||
return -1;
|
||||
}
|
||||
::fcntl(sockfd, F_SETFL, orig_flags);
|
||||
if (so_error != 0 && so_error != EISCONN) {
|
||||
errno = so_error;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// try to connect or throw on failure
|
||||
void connect(const std::string &host, int port) {
|
||||
void connect(const std::string &host, int port, int timeout_ms = 0) {
|
||||
close();
|
||||
struct addrinfo hints {};
|
||||
memset(&hints, 0, sizeof(struct addrinfo));
|
||||
@@ -49,6 +114,10 @@ public:
|
||||
hints.ai_flags = AI_NUMERICSERV; // port passed as as numeric value
|
||||
hints.ai_protocol = 0;
|
||||
|
||||
struct timeval tv;
|
||||
tv.tv_sec = timeout_ms / 1000;
|
||||
tv.tv_usec = (timeout_ms % 1000) * 1000;
|
||||
|
||||
auto port_str = std::to_string(port);
|
||||
struct addrinfo *addrinfo_result;
|
||||
auto rv = ::getaddrinfo(host.c_str(), port_str.c_str(), &hints, &addrinfo_result);
|
||||
@@ -69,8 +138,9 @@ public:
|
||||
last_errno = errno;
|
||||
continue;
|
||||
}
|
||||
rv = ::connect(socket_, rp->ai_addr, rp->ai_addrlen);
|
||||
if (rv == 0) {
|
||||
::fcntl(socket_, F_SETFD, FD_CLOEXEC);
|
||||
if (connect_socket_with_timeout(socket_, rp->ai_addr, rp->ai_addrlen, tv) == 0) {
|
||||
last_errno = 0;
|
||||
break;
|
||||
}
|
||||
last_errno = errno;
|
||||
@@ -82,6 +152,12 @@ public:
|
||||
throw_spdlog_ex("::connect failed", last_errno);
|
||||
}
|
||||
|
||||
if (timeout_ms > 0) {
|
||||
// Set timeouts for send and recv
|
||||
::setsockopt(socket_, SOL_SOCKET, SO_RCVTIMEO, (const char *)&tv, sizeof(tv));
|
||||
::setsockopt(socket_, SOL_SOCKET, SO_SNDTIMEO, (const char *)&tv, sizeof(tv));
|
||||
}
|
||||
|
||||
// set TCP_NODELAY
|
||||
int enable_flag = 1;
|
||||
::setsockopt(socket_, IPPROTO_TCP, TCP_NODELAY, reinterpret_cast<char *>(&enable_flag),
|
||||
@@ -94,7 +170,7 @@ public:
|
||||
#endif
|
||||
|
||||
#if !defined(SO_NOSIGPIPE) && !defined(MSG_NOSIGNAL)
|
||||
#error "tcp_sink would raise SIGPIPE since neither SO_NOSIGPIPE nor MSG_NOSIGNAL are available"
|
||||
#error "tcp_sink would raise SIGPIPE since neither SO_NOSIGPIPE nor MSG_NOSIGNAL are available"
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef SPDLOG_HEADER_ONLY
|
||||
#include <spdlog/details/thread_pool.h>
|
||||
#include <spdlog/details/thread_pool.h>
|
||||
#endif
|
||||
|
||||
#include <cassert>
|
||||
|
||||
@@ -113,5 +113,5 @@ private:
|
||||
} // namespace spdlog
|
||||
|
||||
#ifdef SPDLOG_HEADER_ONLY
|
||||
#include "thread_pool-inl.h"
|
||||
#include "thread_pool-inl.h"
|
||||
#endif
|
||||
|
||||
@@ -16,9 +16,9 @@
|
||||
#include <ws2tcpip.h>
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma comment(lib, "Ws2_32.lib")
|
||||
#pragma comment(lib, "Mswsock.lib")
|
||||
#pragma comment(lib, "AdvApi32.lib")
|
||||
#pragma comment(lib, "Ws2_32.lib")
|
||||
#pragma comment(lib, "Mswsock.lib")
|
||||
#pragma comment(lib, "AdvApi32.lib")
|
||||
#endif
|
||||
|
||||
namespace spdlog {
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
// Will throw on construction if the socket creation failed.
|
||||
|
||||
#ifdef _WIN32
|
||||
#error "include udp_client-windows.h instead"
|
||||
#error "include udp_client-windows.h instead"
|
||||
#endif
|
||||
|
||||
#include <arpa/inet.h>
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef NOMINMAX
|
||||
#define NOMINMAX // prevent windows redefining min/max
|
||||
#define NOMINMAX // prevent windows redefining min/max
|
||||
#endif
|
||||
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
@@ -9,13 +9,13 @@
|
||||
#include <spdlog/common.h>
|
||||
|
||||
#if defined(__has_include)
|
||||
#if __has_include(<version>)
|
||||
#include <version>
|
||||
#endif
|
||||
#if __has_include(<version>)
|
||||
#include <version>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if __cpp_lib_span >= 202002L
|
||||
#include <span>
|
||||
#include <span>
|
||||
#endif
|
||||
|
||||
//
|
||||
|
||||
@@ -71,7 +71,7 @@ class dynamic_arg_list {
|
||||
* It can be implicitly converted into `fmt::basic_format_args` for passing
|
||||
* into type-erased formatting functions such as `fmt::vformat`.
|
||||
*/
|
||||
template <typename Context> class dynamic_format_arg_store {
|
||||
FMT_EXPORT template <typename Context> class dynamic_format_arg_store {
|
||||
private:
|
||||
using char_type = typename Context::char_type;
|
||||
|
||||
@@ -212,7 +212,7 @@ template <typename Context> class dynamic_format_arg_store {
|
||||
}
|
||||
|
||||
/// Returns the number of elements in the store.
|
||||
size_t size() const noexcept { return data_.size(); }
|
||||
auto size() const noexcept -> size_t { return data_.size(); }
|
||||
};
|
||||
|
||||
FMT_END_NAMESPACE
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
#endif
|
||||
|
||||
// The fmt library version in the form major * 10000 + minor * 100 + patch.
|
||||
#define FMT_VERSION 110200
|
||||
#define FMT_VERSION 120100
|
||||
|
||||
// Detect compiler versions.
|
||||
#if defined(__clang__) && !defined(__ibmxl__)
|
||||
@@ -114,7 +114,9 @@
|
||||
#endif
|
||||
|
||||
// Detect consteval, C++20 constexpr extensions and std::is_constant_evaluated.
|
||||
#if !defined(__cpp_lib_is_constant_evaluated)
|
||||
#ifdef FMT_USE_CONSTEVAL
|
||||
// Use the provided definition.
|
||||
#elif !defined(__cpp_lib_is_constant_evaluated)
|
||||
# define FMT_USE_CONSTEVAL 0
|
||||
#elif FMT_CPLUSPLUS < 201709L
|
||||
# define FMT_USE_CONSTEVAL 0
|
||||
@@ -201,14 +203,6 @@
|
||||
# define FMT_NODISCARD
|
||||
#endif
|
||||
|
||||
#ifdef FMT_DEPRECATED
|
||||
// Use the provided definition.
|
||||
#elif FMT_HAS_CPP14_ATTRIBUTE(deprecated)
|
||||
# define FMT_DEPRECATED [[deprecated]]
|
||||
#else
|
||||
# define FMT_DEPRECATED /* deprecated */
|
||||
#endif
|
||||
|
||||
#if FMT_GCC_VERSION || FMT_CLANG_VERSION
|
||||
# define FMT_VISIBILITY(value) __attribute__((visibility(value)))
|
||||
#else
|
||||
@@ -242,6 +236,7 @@ FMT_PRAGMA_GCC(optimize("Og"))
|
||||
# define FMT_GCC_OPTIMIZED
|
||||
#endif
|
||||
FMT_PRAGMA_CLANG(diagnostic push)
|
||||
FMT_PRAGMA_GCC(diagnostic push)
|
||||
|
||||
#ifdef FMT_ALWAYS_INLINE
|
||||
// Use the provided definition.
|
||||
@@ -260,7 +255,7 @@ FMT_PRAGMA_CLANG(diagnostic push)
|
||||
#ifndef FMT_BEGIN_NAMESPACE
|
||||
# define FMT_BEGIN_NAMESPACE \
|
||||
namespace fmt { \
|
||||
inline namespace v11 {
|
||||
inline namespace v12 {
|
||||
# define FMT_END_NAMESPACE \
|
||||
} \
|
||||
}
|
||||
@@ -356,6 +351,9 @@ template <typename T> constexpr auto max_of(T a, T b) -> T {
|
||||
return a > b ? a : b;
|
||||
}
|
||||
|
||||
FMT_NORETURN FMT_API void assert_fail(const char* file, int line,
|
||||
const char* message);
|
||||
|
||||
namespace detail {
|
||||
// Suppresses "unused variable" warnings with the method described in
|
||||
// https://herbsutter.com/2009/10/18/mailbag-shutting-up-compiler-warnings/.
|
||||
@@ -396,7 +394,7 @@ FMT_NORETURN FMT_API void assert_fail(const char* file, int line,
|
||||
# define FMT_ASSERT(condition, message) \
|
||||
((condition) /* void() fails with -Winvalid-constexpr on clang 4.0.1 */ \
|
||||
? (void)0 \
|
||||
: fmt::detail::assert_fail(__FILE__, __LINE__, (message)))
|
||||
: ::fmt::assert_fail(__FILE__, __LINE__, (message)))
|
||||
#endif
|
||||
|
||||
#ifdef FMT_USE_INT128
|
||||
@@ -419,8 +417,12 @@ inline auto map(int128_opt) -> monostate { return {}; }
|
||||
inline auto map(uint128_opt) -> monostate { return {}; }
|
||||
#endif
|
||||
|
||||
#ifndef FMT_USE_BITINT
|
||||
# define FMT_USE_BITINT (FMT_CLANG_VERSION >= 1500)
|
||||
#ifdef FMT_USE_BITINT
|
||||
// Use the provided definition.
|
||||
#elif FMT_CLANG_VERSION >= 1500 && !defined(__CUDACC__)
|
||||
# define FMT_USE_BITINT 1
|
||||
#else
|
||||
# define FMT_USE_BITINT 0
|
||||
#endif
|
||||
|
||||
#if FMT_USE_BITINT
|
||||
@@ -463,12 +465,13 @@ enum { use_utf8 = !FMT_WIN32 || is_utf8_enabled };
|
||||
static_assert(!FMT_UNICODE || use_utf8,
|
||||
"Unicode support requires compiling with /utf-8");
|
||||
|
||||
template <typename T> constexpr const char* narrow(const T*) { return nullptr; }
|
||||
constexpr FMT_ALWAYS_INLINE const char* narrow(const char* s) { return s; }
|
||||
template <typename T> constexpr auto narrow(T*) -> char* { return nullptr; }
|
||||
constexpr FMT_ALWAYS_INLINE auto narrow(const char* s) -> const char* {
|
||||
return s;
|
||||
}
|
||||
|
||||
template <typename Char>
|
||||
FMT_CONSTEXPR auto compare(const Char* s1, const Char* s2, std::size_t n)
|
||||
-> int {
|
||||
FMT_CONSTEXPR auto compare(const Char* s1, const Char* s2, size_t n) -> int {
|
||||
if (!is_constant_evaluated() && sizeof(Char) == 1) return memcmp(s1, s2, n);
|
||||
for (; n != 0; ++s1, ++s2, --n) {
|
||||
if (*s1 < *s2) return -1;
|
||||
@@ -540,7 +543,7 @@ template <typename Char> class basic_string_view {
|
||||
FMT_CONSTEXPR20 basic_string_view(const Char* s) : data_(s) {
|
||||
#if FMT_HAS_BUILTIN(__builtin_strlen) || FMT_GCC_VERSION || FMT_CLANG_VERSION
|
||||
if (std::is_same<Char, char>::value && !detail::is_constant_evaluated()) {
|
||||
size_ = __builtin_strlen(detail::narrow(s)); // strlen is not costexpr.
|
||||
size_ = __builtin_strlen(detail::narrow(s)); // strlen is not constexpr.
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
@@ -616,19 +619,6 @@ template <typename Char> class basic_string_view {
|
||||
|
||||
using string_view = basic_string_view<char>;
|
||||
|
||||
// DEPRECATED! Will be merged with is_char and moved to detail.
|
||||
template <typename T> struct is_xchar : std::false_type {};
|
||||
template <> struct is_xchar<wchar_t> : std::true_type {};
|
||||
template <> struct is_xchar<char16_t> : std::true_type {};
|
||||
template <> struct is_xchar<char32_t> : std::true_type {};
|
||||
#ifdef __cpp_char8_t
|
||||
template <> struct is_xchar<char8_t> : std::true_type {};
|
||||
#endif
|
||||
|
||||
// Specifies if `T` is a character (code unit) type.
|
||||
template <typename T> struct is_char : is_xchar<T> {};
|
||||
template <> struct is_char<char> : std::true_type {};
|
||||
|
||||
template <typename T> class basic_appender;
|
||||
using appender = basic_appender<char>;
|
||||
|
||||
@@ -781,7 +771,7 @@ class basic_specs {
|
||||
(static_cast<unsigned>(p) << precision_shift);
|
||||
}
|
||||
|
||||
constexpr bool dynamic() const {
|
||||
constexpr auto dynamic() const -> bool {
|
||||
return (data_ & (width_mask | precision_mask)) != 0;
|
||||
}
|
||||
|
||||
@@ -921,14 +911,50 @@ template <typename Char = char> class parse_context {
|
||||
FMT_CONSTEXPR void check_dynamic_spec(int arg_id);
|
||||
};
|
||||
|
||||
#ifndef FMT_USE_LOCALE
|
||||
# define FMT_USE_LOCALE (FMT_OPTIMIZE_SIZE <= 1)
|
||||
#endif
|
||||
|
||||
// A type-erased reference to std::locale to avoid the heavy <locale> include.
|
||||
class locale_ref {
|
||||
#if FMT_USE_LOCALE
|
||||
private:
|
||||
const void* locale_; // A type-erased pointer to std::locale.
|
||||
|
||||
public:
|
||||
constexpr locale_ref() : locale_(nullptr) {}
|
||||
|
||||
template <typename Locale, FMT_ENABLE_IF(sizeof(Locale::collate) != 0)>
|
||||
locale_ref(const Locale& loc) : locale_(&loc) {
|
||||
// Check if std::isalpha is found via ADL to reduce the chance of misuse.
|
||||
detail::ignore_unused(isalpha('x', loc));
|
||||
}
|
||||
|
||||
inline explicit operator bool() const noexcept { return locale_ != nullptr; }
|
||||
#endif // FMT_USE_LOCALE
|
||||
|
||||
public:
|
||||
template <typename Locale> auto get() const -> Locale;
|
||||
};
|
||||
|
||||
FMT_END_EXPORT
|
||||
|
||||
namespace detail {
|
||||
|
||||
// Specifies if `T` is a code unit type.
|
||||
template <typename T> struct is_code_unit : std::false_type {};
|
||||
template <> struct is_code_unit<char> : std::true_type {};
|
||||
template <> struct is_code_unit<wchar_t> : std::true_type {};
|
||||
template <> struct is_code_unit<char16_t> : std::true_type {};
|
||||
template <> struct is_code_unit<char32_t> : std::true_type {};
|
||||
#ifdef __cpp_char8_t
|
||||
template <> struct is_code_unit<char8_t> : bool_constant<is_utf8_enabled> {};
|
||||
#endif
|
||||
|
||||
// Constructs fmt::basic_string_view<Char> from types implicitly convertible
|
||||
// to it, deducing Char. Explicitly convertible types such as the ones returned
|
||||
// from FMT_STRING are intentionally excluded.
|
||||
template <typename Char, FMT_ENABLE_IF(is_char<Char>::value)>
|
||||
template <typename Char, FMT_ENABLE_IF(is_code_unit<Char>::value)>
|
||||
constexpr auto to_string_view(const Char* s) -> basic_string_view<Char> {
|
||||
return s;
|
||||
}
|
||||
@@ -1057,11 +1083,11 @@ template <bool B1, bool B2, bool... Tail> constexpr auto count() -> int {
|
||||
return (B1 ? 1 : 0) + count<B2, Tail...>();
|
||||
}
|
||||
|
||||
template <typename... Args> constexpr auto count_named_args() -> int {
|
||||
return count<is_named_arg<Args>::value...>();
|
||||
template <typename... T> constexpr auto count_named_args() -> int {
|
||||
return count<is_named_arg<T>::value...>();
|
||||
}
|
||||
template <typename... Args> constexpr auto count_static_named_args() -> int {
|
||||
return count<is_static_named_arg<Args>::value...>();
|
||||
template <typename... T> constexpr auto count_static_named_args() -> int {
|
||||
return count<is_static_named_arg<T>::value...>();
|
||||
}
|
||||
|
||||
template <typename Char> struct named_arg_info {
|
||||
@@ -1069,7 +1095,7 @@ template <typename Char> struct named_arg_info {
|
||||
int id;
|
||||
};
|
||||
|
||||
// named_args is non-const to suppress a bogus -Wmaybe-uninitalized in gcc 13.
|
||||
// named_args is non-const to suppress a bogus -Wmaybe-uninitialized in gcc 13.
|
||||
template <typename Char>
|
||||
FMT_CONSTEXPR void check_for_duplicate(named_arg_info<Char>* named_args,
|
||||
int named_arg_index,
|
||||
@@ -1173,7 +1199,7 @@ template <typename Char> struct type_mapper {
|
||||
static auto map(ubitint<N>)
|
||||
-> conditional_t<N <= 64, unsigned long long, void>;
|
||||
|
||||
template <typename T, FMT_ENABLE_IF(is_char<T>::value)>
|
||||
template <typename T, FMT_ENABLE_IF(is_code_unit<T>::value)>
|
||||
static auto map(T) -> conditional_t<
|
||||
std::is_same<T, char>::value || std::is_same<T, Char>::value, Char, void>;
|
||||
|
||||
@@ -1679,12 +1705,12 @@ template <typename... T> struct arg_pack {};
|
||||
template <typename Char, int NUM_ARGS, int NUM_NAMED_ARGS, bool DYNAMIC_NAMES>
|
||||
class format_string_checker {
|
||||
private:
|
||||
type types_[max_of(1, NUM_ARGS)];
|
||||
named_arg_info<Char> named_args_[max_of(1, NUM_NAMED_ARGS)];
|
||||
type types_[max_of<size_t>(1, NUM_ARGS)];
|
||||
named_arg_info<Char> named_args_[max_of<size_t>(1, NUM_NAMED_ARGS)];
|
||||
compile_parse_context<Char> context_;
|
||||
|
||||
using parse_func = auto (*)(parse_context<Char>&) -> const Char*;
|
||||
parse_func parse_funcs_[max_of(1, NUM_ARGS)];
|
||||
parse_func parse_funcs_[max_of<size_t>(1, NUM_ARGS)];
|
||||
|
||||
public:
|
||||
template <typename... T>
|
||||
@@ -1828,12 +1854,17 @@ template <typename T> class buffer {
|
||||
void
|
||||
append(const U* begin, const U* end) {
|
||||
while (begin != end) {
|
||||
auto size = size_;
|
||||
auto free_cap = capacity_ - size;
|
||||
auto count = to_unsigned(end - begin);
|
||||
try_reserve(size_ + count);
|
||||
auto free_cap = capacity_ - size_;
|
||||
if (free_cap < count) count = free_cap;
|
||||
if (free_cap < count) {
|
||||
grow_(*this, size + count);
|
||||
size = size_;
|
||||
free_cap = capacity_ - size;
|
||||
count = count < free_cap ? count : free_cap;
|
||||
}
|
||||
// A loop is faster than memcpy on small sizes.
|
||||
T* out = ptr_ + size_;
|
||||
T* out = ptr_ + size;
|
||||
for (size_t i = 0; i < count; ++i) out[i] = begin[i];
|
||||
size_ += count;
|
||||
begin += count;
|
||||
@@ -2033,6 +2064,17 @@ struct has_back_insert_iterator_container_append<
|
||||
.append(std::declval<InputIt>(),
|
||||
std::declval<InputIt>()))>> : std::true_type {};
|
||||
|
||||
template <typename OutputIt, typename InputIt, typename = void>
|
||||
struct has_back_insert_iterator_container_insert_at_end : std::false_type {};
|
||||
|
||||
template <typename OutputIt, typename InputIt>
|
||||
struct has_back_insert_iterator_container_insert_at_end<
|
||||
OutputIt, InputIt,
|
||||
void_t<decltype(get_container(std::declval<OutputIt>())
|
||||
.insert(get_container(std::declval<OutputIt>()).end(),
|
||||
std::declval<InputIt>(),
|
||||
std::declval<InputIt>()))>> : std::true_type {};
|
||||
|
||||
// An optimized version of std::copy with the output value type (T).
|
||||
template <typename T, typename InputIt, typename OutputIt,
|
||||
FMT_ENABLE_IF(is_back_insert_iterator<OutputIt>::value&&
|
||||
@@ -2047,6 +2089,8 @@ FMT_CONSTEXPR20 auto copy(InputIt begin, InputIt end, OutputIt out)
|
||||
template <typename T, typename InputIt, typename OutputIt,
|
||||
FMT_ENABLE_IF(is_back_insert_iterator<OutputIt>::value &&
|
||||
!has_back_insert_iterator_container_append<
|
||||
OutputIt, InputIt>::value &&
|
||||
has_back_insert_iterator_container_insert_at_end<
|
||||
OutputIt, InputIt>::value)>
|
||||
FMT_CONSTEXPR20 auto copy(InputIt begin, InputIt end, OutputIt out)
|
||||
-> OutputIt {
|
||||
@@ -2056,7 +2100,11 @@ FMT_CONSTEXPR20 auto copy(InputIt begin, InputIt end, OutputIt out)
|
||||
}
|
||||
|
||||
template <typename T, typename InputIt, typename OutputIt,
|
||||
FMT_ENABLE_IF(!is_back_insert_iterator<OutputIt>::value)>
|
||||
FMT_ENABLE_IF(!(is_back_insert_iterator<OutputIt>::value &&
|
||||
(has_back_insert_iterator_container_append<
|
||||
OutputIt, InputIt>::value ||
|
||||
has_back_insert_iterator_container_insert_at_end<
|
||||
OutputIt, InputIt>::value)))>
|
||||
FMT_CONSTEXPR auto copy(InputIt begin, InputIt end, OutputIt out) -> OutputIt {
|
||||
while (begin != end) *out++ = static_cast<T>(*begin++);
|
||||
return out;
|
||||
@@ -2176,7 +2224,7 @@ template <typename Context> class value {
|
||||
static_assert(N <= 64, "unsupported _BitInt");
|
||||
}
|
||||
|
||||
template <typename T, FMT_ENABLE_IF(is_char<T>::value)>
|
||||
template <typename T, FMT_ENABLE_IF(is_code_unit<T>::value)>
|
||||
constexpr FMT_INLINE value(T x FMT_BUILTIN) : char_value(x) {
|
||||
static_assert(
|
||||
std::is_same<T, char>::value || std::is_same<T, char_type>::value,
|
||||
@@ -2252,7 +2300,7 @@ template <typename Context> class value {
|
||||
custom.value = const_cast<value_type*>(&x);
|
||||
#endif
|
||||
}
|
||||
custom.format = format_custom<value_type, formatter<value_type, char_type>>;
|
||||
custom.format = format_custom<value_type>;
|
||||
}
|
||||
|
||||
template <typename T, FMT_ENABLE_IF(!has_formatter<T, char_type>())>
|
||||
@@ -2263,10 +2311,10 @@ template <typename Context> class value {
|
||||
}
|
||||
|
||||
// Formats an argument of a custom type, such as a user-defined class.
|
||||
template <typename T, typename Formatter>
|
||||
template <typename T>
|
||||
static void format_custom(void* arg, parse_context<char_type>& parse_ctx,
|
||||
Context& ctx) {
|
||||
auto f = Formatter();
|
||||
auto f = formatter<T, char_type>();
|
||||
parse_ctx.advance_to(f.parse(parse_ctx));
|
||||
using qualified_type =
|
||||
conditional_t<has_formatter<const T, char_type>(), const T, T>;
|
||||
@@ -2293,35 +2341,14 @@ struct is_output_iterator<
|
||||
enable_if_t<std::is_assignable<decltype(*std::declval<decay_t<It>&>()++),
|
||||
T>::value>> : std::true_type {};
|
||||
|
||||
#ifndef FMT_USE_LOCALE
|
||||
# define FMT_USE_LOCALE (FMT_OPTIMIZE_SIZE <= 1)
|
||||
#endif
|
||||
|
||||
// A type-erased reference to an std::locale to avoid a heavy <locale> include.
|
||||
class locale_ref {
|
||||
#if FMT_USE_LOCALE
|
||||
private:
|
||||
const void* locale_; // A type-erased pointer to std::locale.
|
||||
|
||||
public:
|
||||
constexpr locale_ref() : locale_(nullptr) {}
|
||||
template <typename Locale> locale_ref(const Locale& loc);
|
||||
|
||||
inline explicit operator bool() const noexcept { return locale_ != nullptr; }
|
||||
#endif // FMT_USE_LOCALE
|
||||
|
||||
public:
|
||||
template <typename Locale> auto get() const -> Locale;
|
||||
};
|
||||
|
||||
template <typename> constexpr auto encode_types() -> unsigned long long {
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <typename Context, typename Arg, typename... Args>
|
||||
template <typename Context, typename First, typename... T>
|
||||
constexpr auto encode_types() -> unsigned long long {
|
||||
return static_cast<unsigned>(stored_type_constant<Arg, Context>::value) |
|
||||
(encode_types<Context, Args...>() << packed_arg_bits);
|
||||
return static_cast<unsigned>(stored_type_constant<First, Context>::value) |
|
||||
(encode_types<Context, T...>() << packed_arg_bits);
|
||||
}
|
||||
|
||||
template <typename Context, typename... T, size_t NUM_ARGS = sizeof...(T)>
|
||||
@@ -2338,8 +2365,9 @@ template <typename Context, int NUM_ARGS, int NUM_NAMED_ARGS,
|
||||
unsigned long long DESC>
|
||||
struct named_arg_store {
|
||||
// args_[0].named_args points to named_args to avoid bloating format_args.
|
||||
arg_t<Context, NUM_ARGS> args[1 + NUM_ARGS];
|
||||
named_arg_info<typename Context::char_type> named_args[NUM_NAMED_ARGS];
|
||||
arg_t<Context, NUM_ARGS> args[1u + NUM_ARGS];
|
||||
named_arg_info<typename Context::char_type>
|
||||
named_args[static_cast<size_t>(NUM_NAMED_ARGS)];
|
||||
|
||||
template <typename... T>
|
||||
FMT_CONSTEXPR FMT_ALWAYS_INLINE named_arg_store(T&... values)
|
||||
@@ -2358,8 +2386,8 @@ struct named_arg_store {
|
||||
}
|
||||
|
||||
named_arg_store(const named_arg_store& rhs) = delete;
|
||||
named_arg_store& operator=(const named_arg_store& rhs) = delete;
|
||||
named_arg_store& operator=(named_arg_store&& rhs) = delete;
|
||||
auto operator=(const named_arg_store& rhs) -> named_arg_store& = delete;
|
||||
auto operator=(named_arg_store&& rhs) -> named_arg_store& = delete;
|
||||
operator const arg_t<Context, NUM_ARGS>*() const { return args + 1; }
|
||||
};
|
||||
|
||||
@@ -2372,7 +2400,7 @@ struct format_arg_store {
|
||||
// +1 to workaround a bug in gcc 7.5 that causes duplicated-branches warning.
|
||||
using type =
|
||||
conditional_t<NUM_NAMED_ARGS == 0,
|
||||
arg_t<Context, NUM_ARGS>[max_of(1, NUM_ARGS)],
|
||||
arg_t<Context, NUM_ARGS>[max_of<size_t>(1, NUM_ARGS)],
|
||||
named_arg_store<Context, NUM_ARGS, NUM_NAMED_ARGS, DESC>>;
|
||||
type args;
|
||||
};
|
||||
@@ -2656,22 +2684,17 @@ class context {
|
||||
private:
|
||||
appender out_;
|
||||
format_args args_;
|
||||
FMT_NO_UNIQUE_ADDRESS detail::locale_ref loc_;
|
||||
FMT_NO_UNIQUE_ADDRESS locale_ref loc_;
|
||||
|
||||
public:
|
||||
/// The character type for the output.
|
||||
using char_type = char;
|
||||
|
||||
using char_type = char; ///< The character type for the output.
|
||||
using iterator = appender;
|
||||
using format_arg = basic_format_arg<context>;
|
||||
using parse_context_type FMT_DEPRECATED = parse_context<>;
|
||||
template <typename T> using formatter_type FMT_DEPRECATED = formatter<T>;
|
||||
enum { builtin_types = FMT_BUILTIN_TYPES };
|
||||
|
||||
/// Constructs a `context` object. References to the arguments are stored
|
||||
/// in the object so make sure they have appropriate lifetimes.
|
||||
FMT_CONSTEXPR context(iterator out, format_args args,
|
||||
detail::locale_ref loc = {})
|
||||
FMT_CONSTEXPR context(iterator out, format_args args, locale_ref loc = {})
|
||||
: out_(out), args_(args), loc_(loc) {}
|
||||
context(context&&) = default;
|
||||
context(const context&) = delete;
|
||||
@@ -2692,7 +2715,7 @@ class context {
|
||||
// Advances the begin iterator to `it`.
|
||||
FMT_CONSTEXPR void advance_to(iterator) {}
|
||||
|
||||
FMT_CONSTEXPR auto locale() const -> detail::locale_ref { return loc_; }
|
||||
FMT_CONSTEXPR auto locale() const -> locale_ref { return loc_; }
|
||||
};
|
||||
|
||||
template <typename Char = char> struct runtime_format_string {
|
||||
@@ -2779,9 +2802,6 @@ template <typename T, typename Char = char>
|
||||
concept formattable = is_formattable<remove_reference_t<T>, Char>::value;
|
||||
#endif
|
||||
|
||||
template <typename T, typename Char>
|
||||
using has_formatter FMT_DEPRECATED = std::is_constructible<formatter<T, Char>>;
|
||||
|
||||
// A formatter specialization for natively supported types.
|
||||
template <typename T, typename Char>
|
||||
struct formatter<T, Char,
|
||||
@@ -2978,9 +2998,10 @@ FMT_INLINE void println(format_string<T...> fmt, T&&... args) {
|
||||
return fmt::println(stdout, fmt, static_cast<T&&>(args)...);
|
||||
}
|
||||
|
||||
FMT_END_EXPORT
|
||||
FMT_PRAGMA_GCC(diagnostic pop)
|
||||
FMT_PRAGMA_CLANG(diagnostic pop)
|
||||
FMT_PRAGMA_GCC(pop_options)
|
||||
FMT_END_EXPORT
|
||||
FMT_END_NAMESPACE
|
||||
|
||||
#ifdef FMT_HEADER_ONLY
|
||||
|
||||
@@ -38,6 +38,7 @@ FMT_BEGIN_NAMESPACE
|
||||
// Copyright Paul Dreik 2019
|
||||
namespace safe_duration_cast {
|
||||
|
||||
// DEPRECATED!
|
||||
template <typename To, typename From,
|
||||
FMT_ENABLE_IF(!std::is_same<From, To>::value &&
|
||||
std::numeric_limits<From>::is_signed ==
|
||||
@@ -161,17 +162,6 @@ auto safe_duration_cast(std::chrono::duration<FromRep, FromPeriod> from,
|
||||
int& ec) -> To {
|
||||
using From = std::chrono::duration<FromRep, FromPeriod>;
|
||||
ec = 0;
|
||||
if (std::isnan(from.count())) {
|
||||
// nan in, gives nan out. easy.
|
||||
return To{std::numeric_limits<typename To::rep>::quiet_NaN()};
|
||||
}
|
||||
// maybe we should also check if from is denormal, and decide what to do about
|
||||
// it.
|
||||
|
||||
// +-inf should be preserved.
|
||||
if (std::isinf(from.count())) {
|
||||
return To{from.count()};
|
||||
}
|
||||
|
||||
// the basic idea is that we need to convert from count() in the from type
|
||||
// to count() in the To type, by multiplying it with this:
|
||||
@@ -282,8 +272,6 @@ namespace detail {
|
||||
#define FMT_NOMACRO
|
||||
|
||||
template <typename T = void> struct null {};
|
||||
inline auto localtime_r FMT_NOMACRO(...) -> null<> { return null<>(); }
|
||||
inline auto localtime_s(...) -> null<> { return null<>(); }
|
||||
inline auto gmtime_r(...) -> null<> { return null<>(); }
|
||||
inline auto gmtime_s(...) -> null<> { return null<>(); }
|
||||
|
||||
@@ -326,7 +314,7 @@ inline auto get_classic_locale() -> const std::locale& {
|
||||
}
|
||||
|
||||
template <typename CodeUnit> struct codecvt_result {
|
||||
static constexpr const size_t max_size = 32;
|
||||
static constexpr size_t max_size = 32;
|
||||
CodeUnit buf[max_size];
|
||||
CodeUnit* end;
|
||||
};
|
||||
@@ -443,11 +431,7 @@ auto duration_cast(std::chrono::duration<FromRep, FromPeriod> from) -> To {
|
||||
|
||||
using common_rep = typename std::common_type<FromRep, typename To::rep,
|
||||
decltype(factor::num)>::type;
|
||||
|
||||
int ec = 0;
|
||||
auto count = safe_duration_cast::lossless_integral_conversion<common_rep>(
|
||||
from.count(), ec);
|
||||
if (ec) throw_duration_error();
|
||||
common_rep count = from.count(); // This conversion is lossless.
|
||||
|
||||
// Multiply from.count() by factor and check for overflow.
|
||||
if (const_check(factor::num != 1)) {
|
||||
@@ -458,6 +442,7 @@ auto duration_cast(std::chrono::duration<FromRep, FromPeriod> from) -> To {
|
||||
count *= factor::num;
|
||||
}
|
||||
if (const_check(factor::den != 1)) count /= factor::den;
|
||||
int ec = 0;
|
||||
auto to =
|
||||
To(safe_duration_cast::lossless_integral_conversion<typename To::rep>(
|
||||
count, ec));
|
||||
@@ -471,6 +456,8 @@ template <typename To, typename FromRep, typename FromPeriod,
|
||||
std::is_floating_point<typename To::rep>::value)>
|
||||
auto duration_cast(std::chrono::duration<FromRep, FromPeriod> from) -> To {
|
||||
#if FMT_SAFE_DURATION_CAST
|
||||
// Preserve infinity and NaN.
|
||||
if (!isfinite(from.count())) return static_cast<To>(from.count());
|
||||
// Throwing version of safe_duration_cast is only available for
|
||||
// integer to integer or float to float casts.
|
||||
int ec;
|
||||
@@ -487,7 +474,7 @@ template <typename To, typename FromRep, typename FromPeriod,
|
||||
FMT_ENABLE_IF(
|
||||
!is_similar_arithmetic_type<FromRep, typename To::rep>::value)>
|
||||
auto duration_cast(std::chrono::duration<FromRep, FromPeriod> from) -> To {
|
||||
// Mixed integer <-> float cast is not supported by safe_duration_cast.
|
||||
// Mixed integer <-> float cast is not supported by safe duration_cast.
|
||||
return std::chrono::duration_cast<To>(from);
|
||||
}
|
||||
|
||||
@@ -501,86 +488,10 @@ auto to_time_t(sys_time<Duration> time_point) -> std::time_t {
|
||||
.count();
|
||||
}
|
||||
|
||||
namespace tz {
|
||||
|
||||
// DEPRECATED!
|
||||
struct time_zone {
|
||||
template <typename Duration, typename LocalTime>
|
||||
auto to_sys(LocalTime) -> sys_time<Duration> {
|
||||
return {};
|
||||
}
|
||||
};
|
||||
template <typename... T> auto current_zone(T...) -> time_zone* {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template <typename... T> void _tzset(T...) {}
|
||||
} // namespace tz
|
||||
|
||||
// DEPRECATED!
|
||||
inline void tzset_once() {
|
||||
static bool init = []() {
|
||||
using namespace tz;
|
||||
_tzset();
|
||||
return false;
|
||||
}();
|
||||
ignore_unused(init);
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
FMT_BEGIN_EXPORT
|
||||
|
||||
/**
|
||||
* Converts given time since epoch as `std::time_t` value into calendar time,
|
||||
* expressed in local time. Unlike `std::localtime`, this function is
|
||||
* thread-safe on most platforms.
|
||||
*/
|
||||
FMT_DEPRECATED inline auto localtime(std::time_t time) -> std::tm {
|
||||
struct dispatcher {
|
||||
std::time_t time_;
|
||||
std::tm tm_;
|
||||
|
||||
inline dispatcher(std::time_t t) : time_(t) {}
|
||||
|
||||
inline auto run() -> bool {
|
||||
using namespace fmt::detail;
|
||||
return handle(localtime_r(&time_, &tm_));
|
||||
}
|
||||
|
||||
inline auto handle(std::tm* tm) -> bool { return tm != nullptr; }
|
||||
|
||||
inline auto handle(detail::null<>) -> bool {
|
||||
using namespace fmt::detail;
|
||||
return fallback(localtime_s(&tm_, &time_));
|
||||
}
|
||||
|
||||
inline auto fallback(int res) -> bool { return res == 0; }
|
||||
|
||||
#if !FMT_MSC_VERSION
|
||||
inline auto fallback(detail::null<>) -> bool {
|
||||
using namespace fmt::detail;
|
||||
std::tm* tm = std::localtime(&time_);
|
||||
if (tm) tm_ = *tm;
|
||||
return tm != nullptr;
|
||||
}
|
||||
#endif
|
||||
};
|
||||
dispatcher lt(time);
|
||||
// Too big time values may be unsupported.
|
||||
if (!lt.run()) FMT_THROW(format_error("time_t value out of range"));
|
||||
return lt.tm_;
|
||||
}
|
||||
|
||||
#if FMT_USE_LOCAL_TIME
|
||||
template <typename Duration>
|
||||
FMT_DEPRECATED auto localtime(std::chrono::local_time<Duration> time)
|
||||
-> std::tm {
|
||||
using namespace std::chrono;
|
||||
using namespace detail::tz;
|
||||
return localtime(detail::to_time_t(current_zone()->to_sys<Duration>(time)));
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Converts given time since epoch as `std::time_t` value into calendar time,
|
||||
* expressed in Coordinated Universal Time (UTC). Unlike `std::gmtime`, this
|
||||
@@ -652,7 +563,7 @@ inline void write_digit2_separated(char* buf, unsigned a, unsigned b,
|
||||
// Add ASCII '0' to each digit byte and insert separators.
|
||||
digits |= 0x3030003030003030 | (usep << 16) | (usep << 40);
|
||||
|
||||
constexpr const size_t len = 8;
|
||||
constexpr size_t len = 8;
|
||||
if (const_check(is_big_endian())) {
|
||||
char tmp[len];
|
||||
std::memcpy(tmp, &digits, len);
|
||||
@@ -1000,16 +911,16 @@ template <typename T>
|
||||
struct has_tm_zone<T, void_t<decltype(T::tm_zone)>> : std::true_type {};
|
||||
|
||||
template <typename T, FMT_ENABLE_IF(has_tm_zone<T>::value)>
|
||||
bool set_tm_zone(T& time, char* tz) {
|
||||
auto set_tm_zone(T& time, char* tz) -> bool {
|
||||
time.tm_zone = tz;
|
||||
return true;
|
||||
}
|
||||
template <typename T, FMT_ENABLE_IF(!has_tm_zone<T>::value)>
|
||||
bool set_tm_zone(T&, char*) {
|
||||
auto set_tm_zone(T&, char*) -> bool {
|
||||
return false;
|
||||
}
|
||||
|
||||
inline char* utc() {
|
||||
inline auto utc() -> char* {
|
||||
static char tz[] = "UTC";
|
||||
return tz;
|
||||
}
|
||||
@@ -1683,8 +1594,13 @@ class get_locale {
|
||||
|
||||
public:
|
||||
inline get_locale(bool localized, locale_ref loc) : has_locale_(localized) {
|
||||
if (localized)
|
||||
::new (&locale_) std::locale(loc.template get<std::locale>());
|
||||
if (!localized) return;
|
||||
ignore_unused(loc);
|
||||
::new (&locale_) std::locale(
|
||||
#if FMT_USE_LOCALE
|
||||
loc.template get<std::locale>()
|
||||
#endif
|
||||
);
|
||||
}
|
||||
inline ~get_locale() {
|
||||
if (has_locale_) locale_.~locale();
|
||||
@@ -2230,7 +2146,7 @@ template <typename Char> struct formatter<std::tm, Char> {
|
||||
detail::handle_dynamic_spec(specs.dynamic_width(), specs.width, width_ref_,
|
||||
ctx);
|
||||
|
||||
auto loc_ref = specs.localized() ? ctx.locale() : detail::locale_ref();
|
||||
auto loc_ref = specs.localized() ? ctx.locale() : locale_ref();
|
||||
detail::get_locale loc(static_cast<bool>(loc_ref), loc_ref);
|
||||
auto w = detail::tm_writer<basic_appender<Char>, Char, Duration>(
|
||||
loc, out, tm, subsecs);
|
||||
|
||||
@@ -375,19 +375,17 @@ template <typename Char> struct ansi_color_escape {
|
||||
// 10 more.
|
||||
if (is_background) value += 10u;
|
||||
|
||||
size_t index = 0;
|
||||
buffer[index++] = static_cast<Char>('\x1b');
|
||||
buffer[index++] = static_cast<Char>('[');
|
||||
buffer[size++] = static_cast<Char>('\x1b');
|
||||
buffer[size++] = static_cast<Char>('[');
|
||||
|
||||
if (value >= 100u) {
|
||||
buffer[index++] = static_cast<Char>('1');
|
||||
buffer[size++] = static_cast<Char>('1');
|
||||
value %= 100u;
|
||||
}
|
||||
buffer[index++] = static_cast<Char>('0' + value / 10u);
|
||||
buffer[index++] = static_cast<Char>('0' + value % 10u);
|
||||
buffer[size++] = static_cast<Char>('0' + value / 10u);
|
||||
buffer[size++] = static_cast<Char>('0' + value % 10u);
|
||||
|
||||
buffer[index++] = static_cast<Char>('m');
|
||||
buffer[index++] = static_cast<Char>('\0');
|
||||
buffer[size++] = static_cast<Char>('m');
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -398,7 +396,7 @@ template <typename Char> struct ansi_color_escape {
|
||||
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);
|
||||
size = 19;
|
||||
}
|
||||
FMT_CONSTEXPR ansi_color_escape(emphasis em) noexcept {
|
||||
uint8_t em_codes[num_emphases] = {};
|
||||
@@ -411,26 +409,28 @@ template <typename Char> struct ansi_color_escape {
|
||||
if (has_emphasis(em, emphasis::conceal)) em_codes[6] = 8;
|
||||
if (has_emphasis(em, emphasis::strikethrough)) em_codes[7] = 9;
|
||||
|
||||
size_t index = 0;
|
||||
buffer[size++] = static_cast<Char>('\x1b');
|
||||
buffer[size++] = static_cast<Char>('[');
|
||||
|
||||
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[size++] = static_cast<Char>('0' + em_codes[i]);
|
||||
buffer[size++] = static_cast<Char>(';');
|
||||
}
|
||||
buffer[index++] = static_cast<Char>(0);
|
||||
|
||||
buffer[size - 1] = static_cast<Char>('m');
|
||||
}
|
||||
FMT_CONSTEXPR operator const Char*() const noexcept { return buffer; }
|
||||
|
||||
FMT_CONSTEXPR auto begin() const noexcept -> const Char* { return buffer; }
|
||||
FMT_CONSTEXPR20 auto end() const noexcept -> const Char* {
|
||||
return buffer + basic_string_view<Char>(buffer).size();
|
||||
FMT_CONSTEXPR auto end() const noexcept -> const Char* {
|
||||
return buffer + size;
|
||||
}
|
||||
|
||||
private:
|
||||
static constexpr size_t num_emphases = 8;
|
||||
Char buffer[7u + 3u * num_emphases + 1u];
|
||||
Char buffer[7u + 4u * num_emphases] = {};
|
||||
size_t size = 0;
|
||||
|
||||
static FMT_CONSTEXPR void to_esc(uint8_t c, Char* out,
|
||||
char delimiter) noexcept {
|
||||
|
||||
@@ -15,15 +15,14 @@
|
||||
#include "format.h"
|
||||
|
||||
FMT_BEGIN_NAMESPACE
|
||||
FMT_BEGIN_EXPORT
|
||||
|
||||
// A compile-time string which is compiled into fast formatting code.
|
||||
FMT_EXPORT class compiled_string {};
|
||||
class compiled_string {};
|
||||
|
||||
template <typename S>
|
||||
struct is_compiled_string : std::is_base_of<compiled_string, S> {};
|
||||
|
||||
namespace detail {
|
||||
|
||||
/**
|
||||
* 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
|
||||
@@ -41,18 +40,42 @@ namespace detail {
|
||||
# define FMT_COMPILE(s) FMT_STRING(s)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Converts a string literal into a format string that will be parsed at
|
||||
* compile time and converted into efficient formatting code. Requires support
|
||||
* for class types in constant template parameters (a C++20 feature).
|
||||
*
|
||||
* **Example**:
|
||||
*
|
||||
* // Converts 42 into std::string using the most efficient method and no
|
||||
* // runtime format string processing.
|
||||
* using namespace fmt::literals;
|
||||
* std::string s = fmt::format("{}"_cf, 42);
|
||||
*/
|
||||
#if FMT_USE_NONTYPE_TEMPLATE_ARGS
|
||||
inline namespace literals {
|
||||
template <detail::fixed_string Str> constexpr auto operator""_cf() {
|
||||
return FMT_COMPILE(Str.data);
|
||||
}
|
||||
} // namespace literals
|
||||
#endif
|
||||
|
||||
FMT_END_EXPORT
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <typename T, typename... Tail>
|
||||
auto first(const T& value, const Tail&...) -> const T& {
|
||||
constexpr auto first(const T& value, const Tail&...) -> const T& {
|
||||
return value;
|
||||
}
|
||||
|
||||
#if defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction)
|
||||
template <typename... Args> struct type_list {};
|
||||
template <typename... T> 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) {
|
||||
constexpr auto get([[maybe_unused]] const T& first,
|
||||
[[maybe_unused]] const Args&... rest) -> const auto& {
|
||||
static_assert(N < 1 + sizeof...(Args), "index is out of bounds");
|
||||
if constexpr (N == 0)
|
||||
return first;
|
||||
@@ -84,8 +107,8 @@ FMT_CONSTEXPR auto get_arg_index_by_name(basic_string_view<Char> name) -> int {
|
||||
}
|
||||
|
||||
template <typename Char, typename... Args>
|
||||
constexpr int get_arg_index_by_name(basic_string_view<Char> name,
|
||||
type_list<Args...>) {
|
||||
constexpr auto get_arg_index_by_name(basic_string_view<Char> name,
|
||||
type_list<Args...>) -> int {
|
||||
return get_arg_index_by_name<Args...>(name);
|
||||
}
|
||||
|
||||
@@ -105,8 +128,8 @@ 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 {
|
||||
template <typename OutputIt, typename... T>
|
||||
constexpr auto format(OutputIt out, const T&...) const -> OutputIt {
|
||||
return write<Char>(out, data);
|
||||
}
|
||||
};
|
||||
@@ -115,8 +138,8 @@ 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) {
|
||||
constexpr auto make_text(basic_string_view<Char> s, size_t pos, size_t size)
|
||||
-> text<Char> {
|
||||
return {{&s[pos], size}};
|
||||
}
|
||||
|
||||
@@ -124,8 +147,8 @@ 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 {
|
||||
template <typename OutputIt, typename... T>
|
||||
constexpr auto format(OutputIt out, const T&...) const -> OutputIt {
|
||||
*out++ = value;
|
||||
return out;
|
||||
}
|
||||
@@ -133,7 +156,7 @@ template <typename Char> struct code_unit {
|
||||
|
||||
// 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) {
|
||||
constexpr auto get_arg_checked(const Args&... args) -> const T& {
|
||||
const auto& arg = detail::get<N>(args...);
|
||||
if constexpr (detail::is_named_arg<remove_cvref_t<decltype(arg)>>()) {
|
||||
return arg.value;
|
||||
@@ -146,13 +169,13 @@ 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 {
|
||||
template <typename Char, typename V, int N> struct field {
|
||||
using char_type = Char;
|
||||
|
||||
template <typename OutputIt, typename... Args>
|
||||
constexpr OutputIt format(OutputIt out, const Args&... args) const {
|
||||
const T& arg = get_arg_checked<T, N>(args...);
|
||||
if constexpr (std::is_convertible<T, basic_string_view<Char>>::value) {
|
||||
template <typename OutputIt, typename... T>
|
||||
constexpr auto format(OutputIt out, const T&... args) const -> OutputIt {
|
||||
const V& arg = get_arg_checked<V, N>(args...);
|
||||
if constexpr (std::is_convertible<V, basic_string_view<Char>>::value) {
|
||||
auto s = basic_string_view<Char>(arg);
|
||||
return copy<Char>(s.begin(), s.end(), out);
|
||||
} else {
|
||||
@@ -170,10 +193,10 @@ template <typename Char> struct runtime_named_field {
|
||||
basic_string_view<Char> name;
|
||||
|
||||
template <typename OutputIt, typename T>
|
||||
constexpr static bool try_format_argument(
|
||||
constexpr static auto 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) {
|
||||
[[maybe_unused]] basic_string_view<Char> arg_name, const T& arg) -> bool {
|
||||
if constexpr (is_named_arg<typename std::remove_cv<T>::type>::value) {
|
||||
if (arg_name == arg.name) {
|
||||
out = write<Char>(out, arg.value);
|
||||
@@ -183,8 +206,8 @@ template <typename Char> struct runtime_named_field {
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename OutputIt, typename... Args>
|
||||
constexpr OutputIt format(OutputIt out, const Args&... args) const {
|
||||
template <typename OutputIt, typename... T>
|
||||
constexpr auto format(OutputIt out, const T&... args) const -> OutputIt {
|
||||
bool found = (try_format_argument(out, name, args) || ...);
|
||||
if (!found) {
|
||||
FMT_THROW(format_error("argument with specified name is not found"));
|
||||
@@ -197,17 +220,17 @@ 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 {
|
||||
template <typename Char, typename V, int N> struct spec_field {
|
||||
using char_type = Char;
|
||||
formatter<T, Char> fmt;
|
||||
formatter<V, Char> fmt;
|
||||
|
||||
template <typename OutputIt, typename... Args>
|
||||
constexpr FMT_INLINE OutputIt format(OutputIt out,
|
||||
const Args&... args) const {
|
||||
template <typename OutputIt, typename... T>
|
||||
constexpr FMT_INLINE auto format(OutputIt out, const T&... args) const
|
||||
-> OutputIt {
|
||||
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);
|
||||
return fmt.format(get_arg_checked<V, N>(args...), ctx);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -219,8 +242,8 @@ template <typename L, typename R> struct concat {
|
||||
R rhs;
|
||||
using char_type = typename L::char_type;
|
||||
|
||||
template <typename OutputIt, typename... Args>
|
||||
constexpr OutputIt format(OutputIt out, const Args&... args) const {
|
||||
template <typename OutputIt, typename... T>
|
||||
constexpr auto format(OutputIt out, const T&... args) const -> OutputIt {
|
||||
out = lhs.format(out, args...);
|
||||
return rhs.format(out, args...);
|
||||
}
|
||||
@@ -230,14 +253,14 @@ 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) {
|
||||
constexpr auto make_concat(L lhs, R rhs) -> concat<L, R> {
|
||||
return {lhs, rhs};
|
||||
}
|
||||
|
||||
struct unknown_format {};
|
||||
|
||||
template <typename Char>
|
||||
constexpr size_t parse_text(basic_string_view<Char> str, size_t pos) {
|
||||
constexpr auto parse_text(basic_string_view<Char> str, size_t pos) -> size_t {
|
||||
for (size_t size = str.size(); pos != size; ++pos) {
|
||||
if (str[pos] == '{' || str[pos] == '}') break;
|
||||
}
|
||||
@@ -270,8 +293,8 @@ template <typename T, typename Char> struct parse_specs_result {
|
||||
enum { 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) {
|
||||
constexpr auto parse_specs(basic_string_view<Char> str, size_t pos,
|
||||
int next_arg_id) -> parse_specs_result<T, Char> {
|
||||
str.remove_prefix(pos);
|
||||
auto ctx =
|
||||
compile_parse_context<Char>(str, max_value<int>(), nullptr, next_arg_id);
|
||||
@@ -285,16 +308,16 @@ template <typename Char> struct arg_id_handler {
|
||||
arg_id_kind kind;
|
||||
arg_ref<Char> arg_id;
|
||||
|
||||
constexpr int on_auto() {
|
||||
constexpr auto on_auto() -> int {
|
||||
FMT_ASSERT(false, "handler cannot be used with automatic indexing");
|
||||
return 0;
|
||||
}
|
||||
constexpr int on_index(int id) {
|
||||
constexpr auto on_index(int id) -> int {
|
||||
kind = arg_id_kind::index;
|
||||
arg_id = arg_ref<Char>(id);
|
||||
return 0;
|
||||
}
|
||||
constexpr int on_name(basic_string_view<Char> id) {
|
||||
constexpr auto on_name(basic_string_view<Char> id) -> int {
|
||||
kind = arg_id_kind::name;
|
||||
arg_id = arg_ref<Char>(id);
|
||||
return 0;
|
||||
@@ -433,27 +456,28 @@ FMT_BEGIN_EXPORT
|
||||
|
||||
#if defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction)
|
||||
|
||||
template <typename CompiledFormat, typename... Args,
|
||||
template <typename CompiledFormat, typename... T,
|
||||
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) {
|
||||
FMT_INLINE FMT_CONSTEXPR_STRING auto format(const CompiledFormat& cf,
|
||||
const T&... args)
|
||||
-> std::basic_string<Char> {
|
||||
auto s = std::basic_string<Char>();
|
||||
cf.format(std::back_inserter(s), args...);
|
||||
return s;
|
||||
}
|
||||
|
||||
template <typename OutputIt, typename CompiledFormat, typename... Args,
|
||||
template <typename OutputIt, typename CompiledFormat, typename... T,
|
||||
FMT_ENABLE_IF(detail::is_compiled_format<CompiledFormat>::value)>
|
||||
constexpr FMT_INLINE OutputIt format_to(OutputIt out, const CompiledFormat& cf,
|
||||
const Args&... args) {
|
||||
constexpr FMT_INLINE auto format_to(OutputIt out, const CompiledFormat& cf,
|
||||
const T&... args) -> OutputIt {
|
||||
return cf.format(out, args...);
|
||||
}
|
||||
|
||||
template <typename S, typename... Args,
|
||||
template <typename S, typename... T,
|
||||
FMT_ENABLE_IF(is_compiled_string<S>::value)>
|
||||
FMT_INLINE std::basic_string<typename S::char_type> format(const S&,
|
||||
Args&&... args) {
|
||||
FMT_INLINE FMT_CONSTEXPR_STRING auto format(const S&, T&&... args)
|
||||
-> std::basic_string<typename S::char_type> {
|
||||
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] == '}') {
|
||||
@@ -466,72 +490,97 @@ FMT_INLINE std::basic_string<typename S::char_type> format(const S&,
|
||||
}
|
||||
}
|
||||
}
|
||||
constexpr auto compiled = detail::compile<Args...>(S());
|
||||
constexpr auto compiled = detail::compile<T...>(S());
|
||||
if constexpr (std::is_same<remove_cvref_t<decltype(compiled)>,
|
||||
detail::unknown_format>()) {
|
||||
return fmt::format(
|
||||
static_cast<basic_string_view<typename S::char_type>>(S()),
|
||||
std::forward<Args>(args)...);
|
||||
std::forward<T>(args)...);
|
||||
} else {
|
||||
return fmt::format(compiled, std::forward<Args>(args)...);
|
||||
return fmt::format(compiled, std::forward<T>(args)...);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename OutputIt, typename S, typename... Args,
|
||||
template <typename OutputIt, typename S, typename... T,
|
||||
FMT_ENABLE_IF(is_compiled_string<S>::value)>
|
||||
FMT_CONSTEXPR OutputIt format_to(OutputIt out, const S&, Args&&... args) {
|
||||
constexpr auto compiled = detail::compile<Args...>(S());
|
||||
FMT_CONSTEXPR auto format_to(OutputIt out, const S&, T&&... args) -> OutputIt {
|
||||
constexpr auto compiled = detail::compile<T...>(S());
|
||||
if constexpr (std::is_same<remove_cvref_t<decltype(compiled)>,
|
||||
detail::unknown_format>()) {
|
||||
return fmt::format_to(
|
||||
out, static_cast<basic_string_view<typename S::char_type>>(S()),
|
||||
std::forward<Args>(args)...);
|
||||
std::forward<T>(args)...);
|
||||
} else {
|
||||
return fmt::format_to(out, compiled, std::forward<Args>(args)...);
|
||||
return fmt::format_to(out, compiled, std::forward<T>(args)...);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
template <typename OutputIt, typename S, typename... Args,
|
||||
template <typename OutputIt, typename S, typename... T,
|
||||
FMT_ENABLE_IF(is_compiled_string<S>::value)>
|
||||
auto format_to_n(OutputIt out, size_t n, const S& fmt, Args&&... args)
|
||||
auto format_to_n(OutputIt out, size_t n, const S& fmt, T&&... args)
|
||||
-> format_to_n_result<OutputIt> {
|
||||
using traits = detail::fixed_buffer_traits;
|
||||
auto buf = detail::iterator_buffer<OutputIt, char, traits>(out, n);
|
||||
fmt::format_to(std::back_inserter(buf), fmt, std::forward<Args>(args)...);
|
||||
fmt::format_to(std::back_inserter(buf), fmt, std::forward<T>(args)...);
|
||||
return {buf.out(), buf.count()};
|
||||
}
|
||||
|
||||
template <typename S, typename... Args,
|
||||
template <typename S, typename... T,
|
||||
FMT_ENABLE_IF(is_compiled_string<S>::value)>
|
||||
FMT_CONSTEXPR20 auto formatted_size(const S& fmt, const Args&... args)
|
||||
-> size_t {
|
||||
FMT_CONSTEXPR20 auto formatted_size(const S& fmt, T&&... args) -> size_t {
|
||||
auto buf = detail::counting_buffer<>();
|
||||
fmt::format_to(appender(buf), fmt, args...);
|
||||
fmt::format_to(appender(buf), fmt, std::forward<T>(args)...);
|
||||
return buf.count();
|
||||
}
|
||||
|
||||
template <typename S, typename... Args,
|
||||
template <typename S, typename... T,
|
||||
FMT_ENABLE_IF(is_compiled_string<S>::value)>
|
||||
void print(std::FILE* f, const S& fmt, const Args&... args) {
|
||||
void print(std::FILE* f, const S& fmt, T&&... args) {
|
||||
auto buf = memory_buffer();
|
||||
fmt::format_to(appender(buf), fmt, args...);
|
||||
fmt::format_to(appender(buf), fmt, std::forward<T>(args)...);
|
||||
detail::print(f, {buf.data(), buf.size()});
|
||||
}
|
||||
|
||||
template <typename S, typename... Args,
|
||||
template <typename S, typename... T,
|
||||
FMT_ENABLE_IF(is_compiled_string<S>::value)>
|
||||
void print(const S& fmt, const Args&... args) {
|
||||
print(stdout, fmt, args...);
|
||||
void print(const S& fmt, T&&... args) {
|
||||
print(stdout, fmt, std::forward<T>(args)...);
|
||||
}
|
||||
|
||||
#if FMT_USE_NONTYPE_TEMPLATE_ARGS
|
||||
inline namespace literals {
|
||||
template <detail::fixed_string Str> constexpr auto operator""_cf() {
|
||||
return FMT_COMPILE(Str.data);
|
||||
}
|
||||
} // namespace literals
|
||||
#endif
|
||||
template <size_t N> class static_format_result {
|
||||
private:
|
||||
char data[N];
|
||||
|
||||
public:
|
||||
template <typename S, typename... T,
|
||||
FMT_ENABLE_IF(is_compiled_string<S>::value)>
|
||||
explicit FMT_CONSTEXPR static_format_result(const S& fmt, T&&... args) {
|
||||
*fmt::format_to(data, fmt, std::forward<T>(args)...) = '\0';
|
||||
}
|
||||
|
||||
auto str() const -> fmt::string_view { return {data, N - 1}; }
|
||||
auto c_str() const -> const char* { return data; }
|
||||
};
|
||||
|
||||
/**
|
||||
* Formats arguments according to the format string `fmt_str` and produces
|
||||
* a string of the exact required size at compile time. Both the format string
|
||||
* and the arguments must be compile-time expressions.
|
||||
*
|
||||
* The resulting string can be accessed as a C string via `c_str()` or as
|
||||
* a `fmt::string_view` via `str()`.
|
||||
*
|
||||
* **Example**:
|
||||
*
|
||||
* // Produces the static string "42" at compile time.
|
||||
* static constexpr auto result = FMT_STATIC_FORMAT("{}", 42);
|
||||
* const char* s = result.c_str();
|
||||
*/
|
||||
#define FMT_STATIC_FORMAT(fmt_str, ...) \
|
||||
fmt::static_format_result< \
|
||||
fmt::formatted_size(FMT_COMPILE(fmt_str), __VA_ARGS__) + 1>( \
|
||||
FMT_COMPILE(fmt_str), __VA_ARGS__)
|
||||
|
||||
FMT_END_EXPORT
|
||||
FMT_END_NAMESPACE
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
|
||||
#include "format.h"
|
||||
|
||||
#if FMT_USE_LOCALE
|
||||
#if FMT_USE_LOCALE && !defined(FMT_MODULE)
|
||||
# include <locale>
|
||||
#endif
|
||||
|
||||
@@ -31,14 +31,44 @@
|
||||
#endif
|
||||
|
||||
FMT_BEGIN_NAMESPACE
|
||||
namespace detail {
|
||||
|
||||
#ifndef FMT_CUSTOM_ASSERT_FAIL
|
||||
FMT_FUNC void assert_fail(const char* file, int line, const char* message) {
|
||||
// Use unchecked std::fprintf to avoid triggering another assertion when
|
||||
// writing to stderr fails.
|
||||
fprintf(stderr, "%s:%d: assertion failed: %s", file, line, message);
|
||||
std::fprintf(stderr, "%s:%d: assertion failed: %s", file, line, message);
|
||||
abort();
|
||||
}
|
||||
#endif
|
||||
|
||||
#if FMT_USE_LOCALE
|
||||
namespace detail {
|
||||
using std::locale;
|
||||
using std::numpunct;
|
||||
using std::use_facet;
|
||||
} // namespace detail
|
||||
#else
|
||||
namespace detail {
|
||||
struct locale {};
|
||||
template <typename Char> struct numpunct {
|
||||
auto grouping() const -> std::string { return "\03"; }
|
||||
auto thousands_sep() const -> Char { return ','; }
|
||||
auto decimal_point() const -> Char { return '.'; }
|
||||
};
|
||||
template <typename Facet> Facet use_facet(locale) { return {}; }
|
||||
} // namespace detail
|
||||
#endif // FMT_USE_LOCALE
|
||||
|
||||
template <typename Locale> auto locale_ref::get() const -> Locale {
|
||||
using namespace detail;
|
||||
static_assert(std::is_same<Locale, locale>::value, "");
|
||||
#if FMT_USE_LOCALE
|
||||
if (locale_) return *static_cast<const locale*>(locale_);
|
||||
#endif
|
||||
return locale();
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
|
||||
FMT_FUNC void format_error_code(detail::buffer<char>& out, int error_code,
|
||||
string_view message) noexcept {
|
||||
@@ -79,33 +109,6 @@ inline void fwrite_all(const void* ptr, size_t count, FILE* stream) {
|
||||
FMT_THROW(system_error(errno, FMT_STRING("cannot write to file")));
|
||||
}
|
||||
|
||||
#if FMT_USE_LOCALE
|
||||
using std::locale;
|
||||
using std::numpunct;
|
||||
using std::use_facet;
|
||||
|
||||
template <typename Locale>
|
||||
locale_ref::locale_ref(const Locale& loc) : locale_(&loc) {
|
||||
static_assert(std::is_same<Locale, locale>::value, "");
|
||||
}
|
||||
#else
|
||||
struct locale {};
|
||||
template <typename Char> struct numpunct {
|
||||
auto grouping() const -> std::string { return "\03"; }
|
||||
auto thousands_sep() const -> Char { return ','; }
|
||||
auto decimal_point() const -> Char { return '.'; }
|
||||
};
|
||||
template <typename Facet> Facet use_facet(locale) { return {}; }
|
||||
#endif // FMT_USE_LOCALE
|
||||
|
||||
template <typename Locale> auto locale_ref::get() const -> Locale {
|
||||
static_assert(std::is_same<Locale, locale>::value, "");
|
||||
#if FMT_USE_LOCALE
|
||||
if (locale_) return *static_cast<const locale*>(locale_);
|
||||
#endif
|
||||
return locale();
|
||||
}
|
||||
|
||||
template <typename Char>
|
||||
FMT_FUNC auto thousands_sep_impl(locale_ref loc) -> thousands_sep_result<Char> {
|
||||
auto&& facet = use_facet<numpunct<Char>>(loc.get<locale>());
|
||||
@@ -133,14 +136,13 @@ FMT_FUNC auto write_loc(appender out, loc_value value,
|
||||
} // namespace detail
|
||||
|
||||
FMT_FUNC void report_error(const char* message) {
|
||||
#if FMT_USE_EXCEPTIONS
|
||||
// Use FMT_THROW instead of throw to avoid bogus unreachable code warnings
|
||||
// from MSVC.
|
||||
FMT_THROW(format_error(message));
|
||||
#else
|
||||
fputs(message, stderr);
|
||||
abort();
|
||||
#if FMT_MSC_VERSION || defined(__NVCC__)
|
||||
// Silence unreachable code warnings in MSVC and NVCC because these
|
||||
// are nearly impossible to fix in a generic code.
|
||||
volatile bool b = true;
|
||||
if (!b) return;
|
||||
#endif
|
||||
FMT_THROW(format_error(message));
|
||||
}
|
||||
|
||||
template <typename Locale> typename Locale::id format_facet<Locale>::id;
|
||||
@@ -174,11 +176,11 @@ inline auto operator==(basic_fp<F> x, basic_fp<F> y) -> bool {
|
||||
}
|
||||
|
||||
// Compilers should be able to optimize this into the ror instruction.
|
||||
FMT_CONSTEXPR inline auto rotr(uint32_t n, uint32_t r) noexcept -> uint32_t {
|
||||
FMT_INLINE auto rotr(uint32_t n, uint32_t r) noexcept -> uint32_t {
|
||||
r &= 31;
|
||||
return (n >> r) | (n << (32 - r));
|
||||
}
|
||||
FMT_CONSTEXPR inline auto rotr(uint64_t n, uint32_t r) noexcept -> uint64_t {
|
||||
FMT_INLINE auto rotr(uint64_t n, uint32_t r) noexcept -> uint64_t {
|
||||
r &= 63;
|
||||
return (n >> r) | (n << (64 - r));
|
||||
}
|
||||
@@ -275,7 +277,7 @@ template <> struct cache_accessor<float> {
|
||||
static auto get_cached_power(int k) noexcept -> uint64_t {
|
||||
FMT_ASSERT(k >= float_info<float>::min_k && k <= float_info<float>::max_k,
|
||||
"k is out of range");
|
||||
static constexpr const uint64_t pow10_significands[] = {
|
||||
static constexpr uint64_t pow10_significands[] = {
|
||||
0x81ceb32c4b43fcf5, 0xa2425ff75e14fc32, 0xcad2f7f5359a3b3f,
|
||||
0xfd87b5f28300ca0e, 0x9e74d1b791e07e49, 0xc612062576589ddb,
|
||||
0xf79687aed3eec552, 0x9abe14cd44753b53, 0xc16d9a0095928a28,
|
||||
@@ -370,7 +372,7 @@ template <> struct cache_accessor<double> {
|
||||
FMT_ASSERT(k >= float_info<double>::min_k && k <= float_info<double>::max_k,
|
||||
"k is out of range");
|
||||
|
||||
static constexpr const uint128_fallback pow10_significands[] = {
|
||||
static constexpr uint128_fallback pow10_significands[] = {
|
||||
#if FMT_USE_FULL_CACHE_DRAGONBOX
|
||||
{0xff77b1fcbebcdc4f, 0x25e8e89c13bb0f7b},
|
||||
{0x9faacf3df73609b1, 0x77b191618c54e9ad},
|
||||
@@ -1037,7 +1039,7 @@ template <> struct cache_accessor<double> {
|
||||
#if FMT_USE_FULL_CACHE_DRAGONBOX
|
||||
return pow10_significands[k - float_info<double>::min_k];
|
||||
#else
|
||||
static constexpr const uint64_t powers_of_5_64[] = {
|
||||
static constexpr uint64_t powers_of_5_64[] = {
|
||||
0x0000000000000001, 0x0000000000000005, 0x0000000000000019,
|
||||
0x000000000000007d, 0x0000000000000271, 0x0000000000000c35,
|
||||
0x0000000000003d09, 0x000000000001312d, 0x000000000005f5e1,
|
||||
@@ -1149,8 +1151,8 @@ auto is_left_endpoint_integer_shorter_interval(int exponent) noexcept -> bool {
|
||||
exponent <= case_shorter_interval_left_endpoint_upper_threshold;
|
||||
}
|
||||
|
||||
// Remove trailing zeros from n and return the number of zeros removed (float)
|
||||
FMT_INLINE int remove_trailing_zeros(uint32_t& n, int s = 0) noexcept {
|
||||
// Remove trailing zeros from n and return the number of zeros removed (float).
|
||||
FMT_INLINE auto remove_trailing_zeros(uint32_t& n, int s = 0) noexcept -> int {
|
||||
FMT_ASSERT(n != 0, "");
|
||||
// Modular inverse of 5 (mod 2^32): (mod_inv_5 * 5) mod 2^32 = 1.
|
||||
constexpr uint32_t mod_inv_5 = 0xcccccccd;
|
||||
@@ -1170,22 +1172,19 @@ FMT_INLINE int remove_trailing_zeros(uint32_t& n, int s = 0) noexcept {
|
||||
return s;
|
||||
}
|
||||
|
||||
// Removes trailing zeros and returns the number of zeros removed (double)
|
||||
FMT_INLINE int remove_trailing_zeros(uint64_t& n) noexcept {
|
||||
// Removes trailing zeros and returns the number of zeros removed (double).
|
||||
FMT_INLINE auto remove_trailing_zeros(uint64_t& n) noexcept -> int {
|
||||
FMT_ASSERT(n != 0, "");
|
||||
|
||||
// This magic number is ceil(2^90 / 10^8).
|
||||
constexpr uint64_t magic_number = 12379400392853802749ull;
|
||||
auto nm = umul128(n, magic_number);
|
||||
|
||||
// Is n is divisible by 10^8?
|
||||
if ((nm.high() & ((1ull << (90 - 64)) - 1)) == 0 && nm.low() < magic_number) {
|
||||
constexpr uint32_t ten_pow_8 = 100000000u;
|
||||
if ((n % ten_pow_8) == 0) {
|
||||
// If yes, work with the quotient...
|
||||
auto n32 = static_cast<uint32_t>(nm.high() >> (90 - 64));
|
||||
auto n32 = static_cast<uint32_t>(n / ten_pow_8);
|
||||
// ... and use the 32 bit variant of the function
|
||||
int s = remove_trailing_zeros(n32, 8);
|
||||
int num_zeros = remove_trailing_zeros(n32, 8);
|
||||
n = n32;
|
||||
return s;
|
||||
return num_zeros;
|
||||
}
|
||||
|
||||
// If n is not divisible by 10^8, work with n itself.
|
||||
@@ -1210,7 +1209,7 @@ FMT_INLINE int remove_trailing_zeros(uint64_t& n) noexcept {
|
||||
|
||||
// The main algorithm for shorter interval case
|
||||
template <typename T>
|
||||
FMT_INLINE decimal_fp<T> shorter_interval_case(int exponent) noexcept {
|
||||
FMT_INLINE auto shorter_interval_case(int exponent) noexcept -> decimal_fp<T> {
|
||||
decimal_fp<T> ret_value;
|
||||
// Compute k and beta
|
||||
const int minus_k = floor_log10_pow2_minus_log10_4_over_3(exponent);
|
||||
@@ -1454,8 +1453,8 @@ FMT_FUNC void vformat_to(buffer<char>& buf, string_view fmt, format_args args,
|
||||
auto out = appender(buf);
|
||||
if (fmt.size() == 2 && equal2(fmt.data(), "{}"))
|
||||
return args.get(0).visit(default_arg_formatter<char>{out});
|
||||
parse_format_string(
|
||||
fmt, format_handler<char>{parse_context<char>(fmt), {out, args, loc}});
|
||||
parse_format_string(fmt,
|
||||
format_handler<>{parse_context<>(fmt), {out, args, loc}});
|
||||
}
|
||||
|
||||
template <typename T> struct span {
|
||||
@@ -1546,10 +1545,11 @@ template <typename F> class glibc_file : public file_base<F> {
|
||||
|
||||
void advance_write_buffer(size_t size) { this->file_->_IO_write_ptr += size; }
|
||||
|
||||
bool needs_flush() const {
|
||||
auto needs_flush() const -> bool {
|
||||
if ((this->file_->_flags & line_buffered) == 0) return false;
|
||||
char* end = this->file_->_IO_write_end;
|
||||
return memchr(end, '\n', to_unsigned(this->file_->_IO_write_ptr - end));
|
||||
auto size = max_of<ptrdiff_t>(this->file_->_IO_write_ptr - end, 0);
|
||||
return memchr(end, '\n', static_cast<size_t>(size));
|
||||
}
|
||||
|
||||
void flush() { fflush_unlocked(this->file_); }
|
||||
@@ -1573,7 +1573,7 @@ template <typename F> class apple_file : public file_base<F> {
|
||||
void init_buffer() {
|
||||
if (this->file_->_p) return;
|
||||
// Force buffer initialization by placing and removing a char in a buffer.
|
||||
putc_unlocked(0, this->file_);
|
||||
if (!FMT_CLANG_ANALYZER) putc_unlocked(0, this->file_);
|
||||
--this->file_->_p;
|
||||
++this->file_->_w;
|
||||
}
|
||||
@@ -1594,7 +1594,7 @@ template <typename F> class apple_file : public file_base<F> {
|
||||
this->file_->_w -= size;
|
||||
}
|
||||
|
||||
bool needs_flush() const {
|
||||
auto needs_flush() const -> bool {
|
||||
if ((this->file_->_flags & line_buffered) == 0) return false;
|
||||
return memchr(this->file_->_p + this->file_->_w, '\n',
|
||||
to_unsigned(-this->file_->_w));
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -29,7 +29,8 @@
|
||||
# if (FMT_HAS_INCLUDE(<fcntl.h>) || defined(__APPLE__) || \
|
||||
defined(__linux__)) && \
|
||||
(!defined(WINAPI_FAMILY) || \
|
||||
(WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP))
|
||||
(WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP)) && \
|
||||
!defined(__wasm__)
|
||||
# include <fcntl.h> // for O_RDONLY
|
||||
# define FMT_USE_FCNTL 1
|
||||
# else
|
||||
@@ -135,10 +136,9 @@ FMT_API std::system_error vwindows_error(int error_code, string_view fmt,
|
||||
* **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";
|
||||
* // cannot open file 'foo': The system cannot find the file specified.
|
||||
* // or similar (system message may vary) if the file doesn't exist.
|
||||
* const char *filename = "foo";
|
||||
* LPOFSTRUCT of = LPOFSTRUCT();
|
||||
* HFILE file = OpenFile(filename, &of, OF_READ);
|
||||
* if (file == HFILE_ERROR) {
|
||||
@@ -364,17 +364,17 @@ FMT_INLINE_VARIABLE constexpr auto buffer_size = detail::buffer_size();
|
||||
|
||||
/// A fast buffered output stream for writing from a single thread. Writing from
|
||||
/// multiple threads without external synchronization may result in a data race.
|
||||
class FMT_API ostream : private detail::buffer<char> {
|
||||
class ostream : private detail::buffer<char> {
|
||||
private:
|
||||
file file_;
|
||||
|
||||
ostream(cstring_view path, const detail::ostream_params& params);
|
||||
FMT_API ostream(cstring_view path, const detail::ostream_params& params);
|
||||
|
||||
static void grow(buffer<char>& buf, size_t);
|
||||
FMT_API static void grow(buffer<char>& buf, size_t);
|
||||
|
||||
public:
|
||||
ostream(ostream&& other) noexcept;
|
||||
~ostream();
|
||||
FMT_API ostream(ostream&& other) noexcept;
|
||||
FMT_API ~ostream();
|
||||
|
||||
operator writer() {
|
||||
detail::buffer<char>& buf = *this;
|
||||
|
||||
@@ -33,8 +33,8 @@
|
||||
FMT_BEGIN_NAMESPACE
|
||||
namespace detail {
|
||||
|
||||
// Generate a unique explicit instantion in every translation unit using a tag
|
||||
// type in an anonymous namespace.
|
||||
// Generate a unique explicit instantiation in every translation unit using a
|
||||
// tag type in an anonymous namespace.
|
||||
namespace {
|
||||
struct file_access_tag {};
|
||||
} // namespace
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
#define FMT_PRINTF_H_
|
||||
|
||||
#ifndef FMT_MODULE
|
||||
# include <algorithm> // std::max
|
||||
# include <algorithm> // std::find
|
||||
# include <limits> // std::numeric_limits
|
||||
#endif
|
||||
|
||||
@@ -18,10 +18,6 @@
|
||||
FMT_BEGIN_NAMESPACE
|
||||
FMT_BEGIN_EXPORT
|
||||
|
||||
template <typename T> struct printf_formatter {
|
||||
printf_formatter() = delete;
|
||||
};
|
||||
|
||||
template <typename Char> class basic_printf_context {
|
||||
private:
|
||||
basic_appender<Char> out_;
|
||||
@@ -33,8 +29,6 @@ template <typename Char> class basic_printf_context {
|
||||
|
||||
public:
|
||||
using char_type = Char;
|
||||
using parse_context_type = parse_context<Char>;
|
||||
template <typename T> using formatter_type = printf_formatter<T>;
|
||||
enum { builtin_types = 1 };
|
||||
|
||||
/// Constructs a `printf_context` object. References to the arguments are
|
||||
@@ -46,7 +40,7 @@ template <typename Char> class basic_printf_context {
|
||||
auto out() -> basic_appender<Char> { return out_; }
|
||||
void advance_to(basic_appender<Char>) {}
|
||||
|
||||
auto locale() -> detail::locale_ref { return {}; }
|
||||
auto locale() -> locale_ref { return {}; }
|
||||
|
||||
auto arg(int id) const -> basic_format_arg<basic_printf_context> {
|
||||
return args_.get(id);
|
||||
@@ -74,10 +68,9 @@ inline auto find<false, char>(const char* first, const char* last, char value,
|
||||
|
||||
// Checks if a value fits in int - used to avoid warnings about comparing
|
||||
// signed and unsigned integers.
|
||||
template <bool IsSigned> struct int_checker {
|
||||
template <bool IS_SIGNED> struct int_checker {
|
||||
template <typename T> static auto fits_in_int(T value) -> bool {
|
||||
unsigned max = to_unsigned(max_value<int>());
|
||||
return value <= max;
|
||||
return value <= to_unsigned(max_value<int>());
|
||||
}
|
||||
inline static auto fits_in_int(bool) -> bool { return true; }
|
||||
};
|
||||
@@ -95,7 +88,7 @@ struct printf_precision_handler {
|
||||
auto operator()(T value) -> int {
|
||||
if (!int_checker<std::numeric_limits<T>::is_signed>::fits_in_int(value))
|
||||
report_error("number is too big");
|
||||
return (std::max)(static_cast<int>(value), 0);
|
||||
return max_of(static_cast<int>(value), 0);
|
||||
}
|
||||
|
||||
template <typename T, FMT_ENABLE_IF(!std::is_integral<T>::value)>
|
||||
@@ -410,7 +403,9 @@ void vprintf(buffer<Char>& buf, basic_string_view<Char> format,
|
||||
arg_index = parse_ctx.next_arg_id();
|
||||
else
|
||||
parse_ctx.check_arg_id(--arg_index);
|
||||
return detail::get_arg(context, arg_index);
|
||||
auto arg = context.arg(arg_index);
|
||||
if (!arg) report_error("argument not found");
|
||||
return arg;
|
||||
};
|
||||
|
||||
const Char* start = parse_ctx.begin();
|
||||
@@ -571,15 +566,19 @@ inline auto vsprintf(basic_string_view<Char> fmt,
|
||||
*
|
||||
* std::string message = fmt::sprintf("The answer is %d", 42);
|
||||
*/
|
||||
template <typename S, typename... T, typename Char = detail::char_t<S>>
|
||||
inline auto sprintf(const S& fmt, const T&... args) -> std::basic_string<Char> {
|
||||
return vsprintf(detail::to_string_view(fmt),
|
||||
fmt::make_format_args<basic_printf_context<Char>>(args...));
|
||||
template <typename... T>
|
||||
inline auto sprintf(string_view fmt, const T&... args) -> std::string {
|
||||
return vsprintf(fmt, make_printf_args(args...));
|
||||
}
|
||||
template <typename... T>
|
||||
FMT_DEPRECATED auto sprintf(basic_string_view<wchar_t> fmt, const T&... args)
|
||||
-> std::wstring {
|
||||
return vsprintf(fmt, make_printf_args<wchar_t>(args...));
|
||||
}
|
||||
|
||||
template <typename Char>
|
||||
inline auto vfprintf(std::FILE* f, basic_string_view<Char> fmt,
|
||||
typename vprintf_args<Char>::type args) -> int {
|
||||
auto vfprintf(std::FILE* f, basic_string_view<Char> fmt,
|
||||
typename vprintf_args<Char>::type args) -> int {
|
||||
auto buf = basic_memory_buffer<Char>();
|
||||
detail::vprintf(buf, fmt, args);
|
||||
size_t size = buf.size();
|
||||
@@ -596,17 +595,14 @@ inline auto vfprintf(std::FILE* f, basic_string_view<Char> fmt,
|
||||
*
|
||||
* fmt::fprintf(stderr, "Don't %s!", "panic");
|
||||
*/
|
||||
template <typename S, typename... T, typename Char = detail::char_t<S>>
|
||||
inline auto fprintf(std::FILE* f, const S& fmt, const T&... args) -> int {
|
||||
return vfprintf(f, detail::to_string_view(fmt),
|
||||
make_printf_args<Char>(args...));
|
||||
template <typename... T>
|
||||
inline auto fprintf(std::FILE* f, string_view fmt, const T&... args) -> int {
|
||||
return vfprintf(f, fmt, make_printf_args(args...));
|
||||
}
|
||||
|
||||
template <typename Char>
|
||||
FMT_DEPRECATED inline auto vprintf(basic_string_view<Char> fmt,
|
||||
typename vprintf_args<Char>::type args)
|
||||
-> int {
|
||||
return vfprintf(stdout, fmt, args);
|
||||
template <typename... T>
|
||||
FMT_DEPRECATED auto fprintf(std::FILE* f, basic_string_view<wchar_t> fmt,
|
||||
const T&... args) -> int {
|
||||
return vfprintf(f, fmt, make_printf_args<wchar_t>(args...));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -621,11 +617,6 @@ template <typename... T>
|
||||
inline auto printf(string_view fmt, const T&... args) -> int {
|
||||
return vfprintf(stdout, fmt, make_printf_args(args...));
|
||||
}
|
||||
template <typename... T>
|
||||
FMT_DEPRECATED inline auto printf(basic_string_view<wchar_t> fmt,
|
||||
const T&... args) -> int {
|
||||
return vfprintf(stdout, fmt, make_printf_args<wchar_t>(args...));
|
||||
}
|
||||
|
||||
FMT_END_EXPORT
|
||||
FMT_END_NAMESPACE
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
#ifndef FMT_MODULE
|
||||
# include <initializer_list>
|
||||
# include <iterator>
|
||||
# include <string>
|
||||
# include <tuple>
|
||||
# include <type_traits>
|
||||
# include <utility>
|
||||
@@ -19,6 +18,13 @@
|
||||
|
||||
#include "format.h"
|
||||
|
||||
#if FMT_HAS_CPP_ATTRIBUTE(clang::lifetimebound)
|
||||
# define FMT_LIFETIMEBOUND [[clang::lifetimebound]]
|
||||
#else
|
||||
# define FMT_LIFETIMEBOUND
|
||||
#endif
|
||||
FMT_PRAGMA_CLANG(diagnostic error "-Wreturn-stack-address")
|
||||
|
||||
FMT_BEGIN_NAMESPACE
|
||||
|
||||
FMT_EXPORT
|
||||
@@ -31,7 +37,7 @@ template <typename T> class is_map {
|
||||
template <typename> static void check(...);
|
||||
|
||||
public:
|
||||
static constexpr const bool value =
|
||||
static constexpr bool value =
|
||||
!std::is_void<decltype(check<T>(nullptr))>::value;
|
||||
};
|
||||
|
||||
@@ -40,17 +46,16 @@ template <typename T> class is_set {
|
||||
template <typename> static void check(...);
|
||||
|
||||
public:
|
||||
static constexpr const bool value =
|
||||
static constexpr bool value =
|
||||
!std::is_void<decltype(check<T>(nullptr))>::value && !is_map<T>::value;
|
||||
};
|
||||
|
||||
// C array overload
|
||||
template <typename T, std::size_t N>
|
||||
template <typename T, 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* {
|
||||
template <typename T, size_t N> auto range_end(const T (&arr)[N]) -> const T* {
|
||||
return arr + N;
|
||||
}
|
||||
|
||||
@@ -120,7 +125,7 @@ template <typename T> class is_tuple_like_ {
|
||||
template <typename> static void check(...);
|
||||
|
||||
public:
|
||||
static constexpr const bool value =
|
||||
static constexpr bool value =
|
||||
!std::is_void<decltype(check<T>(nullptr))>::value;
|
||||
};
|
||||
|
||||
@@ -154,7 +159,7 @@ using tuple_index_sequence = make_index_sequence<std::tuple_size<T>::value>;
|
||||
template <typename T, typename C, bool = is_tuple_like_<T>::value>
|
||||
class is_tuple_formattable_ {
|
||||
public:
|
||||
static constexpr const bool value = false;
|
||||
static constexpr bool value = false;
|
||||
};
|
||||
template <typename T, typename C> class is_tuple_formattable_<T, C, true> {
|
||||
template <size_t... Is>
|
||||
@@ -170,7 +175,7 @@ template <typename T, typename C> class is_tuple_formattable_<T, C, true> {
|
||||
C>::value)...>{}));
|
||||
|
||||
public:
|
||||
static constexpr const bool value =
|
||||
static constexpr bool value =
|
||||
decltype(check(tuple_index_sequence<T>{}))::value;
|
||||
};
|
||||
|
||||
@@ -208,7 +213,7 @@ template <typename Char, typename... T>
|
||||
using result_t = std::tuple<formatter<remove_cvref_t<T>, Char>...>;
|
||||
|
||||
using std::get;
|
||||
template <typename Tuple, typename Char, std::size_t... Is>
|
||||
template <typename Tuple, typename Char, size_t... Is>
|
||||
auto get_formatters(index_sequence<Is...>)
|
||||
-> result_t<Char, decltype(get<Is>(std::declval<Tuple>()))...>;
|
||||
} // namespace tuple
|
||||
@@ -219,7 +224,7 @@ template <typename R> struct range_reference_type_impl {
|
||||
using type = decltype(*detail::range_begin(std::declval<R&>()));
|
||||
};
|
||||
|
||||
template <typename T, std::size_t N> struct range_reference_type_impl<T[N]> {
|
||||
template <typename T, size_t N> struct range_reference_type_impl<T[N]> {
|
||||
using type = T&;
|
||||
};
|
||||
|
||||
@@ -236,14 +241,6 @@ using range_reference_type =
|
||||
template <typename Range>
|
||||
using uncvref_type = remove_cvref_t<range_reference_type<Range>>;
|
||||
|
||||
template <typename Formatter>
|
||||
FMT_CONSTEXPR auto maybe_set_debug_format(Formatter& f, bool set)
|
||||
-> decltype(f.set_debug_format(set)) {
|
||||
f.set_debug_format(set);
|
||||
}
|
||||
template <typename Formatter>
|
||||
FMT_CONSTEXPR void maybe_set_debug_format(Formatter&, ...) {}
|
||||
|
||||
template <typename T>
|
||||
struct range_format_kind_
|
||||
: std::integral_constant<range_format,
|
||||
@@ -281,14 +278,15 @@ template <typename FormatContext> struct format_tuple_element {
|
||||
|
||||
} // namespace detail
|
||||
|
||||
FMT_EXPORT
|
||||
template <typename T> struct is_tuple_like {
|
||||
static constexpr const bool value =
|
||||
static constexpr bool value =
|
||||
detail::is_tuple_like_<T>::value && !detail::is_range_<T>::value;
|
||||
};
|
||||
|
||||
FMT_EXPORT
|
||||
template <typename T, typename C> struct is_tuple_formattable {
|
||||
static constexpr const bool value =
|
||||
detail::is_tuple_formattable_<T, C>::value;
|
||||
static constexpr bool value = detail::is_tuple_formattable_<T, C>::value;
|
||||
};
|
||||
|
||||
template <typename Tuple, typename Char>
|
||||
@@ -343,8 +341,9 @@ struct formatter<Tuple, Char,
|
||||
}
|
||||
};
|
||||
|
||||
FMT_EXPORT
|
||||
template <typename T, typename Char> struct is_range {
|
||||
static constexpr const bool value =
|
||||
static constexpr bool value =
|
||||
detail::is_range_<T>::value && !detail::has_to_string_view<T>::value;
|
||||
};
|
||||
|
||||
@@ -368,6 +367,7 @@ template <typename P1, typename... Pn>
|
||||
struct conjunction<P1, Pn...>
|
||||
: conditional_t<bool(P1::value), conjunction<Pn...>, P1> {};
|
||||
|
||||
FMT_EXPORT
|
||||
template <typename T, typename Char, typename Enable = void>
|
||||
struct range_formatter;
|
||||
|
||||
@@ -670,7 +670,8 @@ struct formatter<join_view<It, Sentinel, Char>, Char> {
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Char, typename Tuple> struct tuple_join_view : detail::view {
|
||||
FMT_EXPORT
|
||||
template <typename Tuple, typename Char> struct tuple_join_view : detail::view {
|
||||
const Tuple& tuple;
|
||||
basic_string_view<Char> sep;
|
||||
|
||||
@@ -685,15 +686,15 @@ template <typename Char, typename Tuple> struct tuple_join_view : detail::view {
|
||||
# define FMT_TUPLE_JOIN_SPECIFIERS 0
|
||||
#endif
|
||||
|
||||
template <typename Char, typename Tuple>
|
||||
struct formatter<tuple_join_view<Char, Tuple>, Char,
|
||||
template <typename Tuple, typename Char>
|
||||
struct formatter<tuple_join_view<Tuple, Char>, Char,
|
||||
enable_if_t<is_tuple_like<Tuple>::value>> {
|
||||
FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* {
|
||||
return do_parse(ctx, std::tuple_size<Tuple>());
|
||||
}
|
||||
|
||||
template <typename FormatContext>
|
||||
auto format(const tuple_join_view<Char, Tuple>& value,
|
||||
auto format(const tuple_join_view<Tuple, Char>& value,
|
||||
FormatContext& ctx) const -> typename FormatContext::iterator {
|
||||
return do_format(value, ctx, std::tuple_size<Tuple>());
|
||||
}
|
||||
@@ -725,14 +726,14 @@ struct formatter<tuple_join_view<Char, Tuple>, Char,
|
||||
}
|
||||
|
||||
template <typename FormatContext>
|
||||
auto do_format(const tuple_join_view<Char, Tuple>&, FormatContext& ctx,
|
||||
auto do_format(const tuple_join_view<Tuple, Char>&, 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, Tuple>& value, FormatContext& ctx,
|
||||
auto do_format(const tuple_join_view<Tuple, Char>& value, FormatContext& ctx,
|
||||
std::integral_constant<size_t, N>) const ->
|
||||
typename FormatContext::iterator {
|
||||
using std::get;
|
||||
@@ -754,7 +755,7 @@ template <typename T> class is_container_adaptor_like {
|
||||
template <typename> static void check(...);
|
||||
|
||||
public:
|
||||
static constexpr const bool value =
|
||||
static constexpr bool value =
|
||||
!std::is_void<decltype(check<T>(nullptr))>::value;
|
||||
};
|
||||
|
||||
@@ -819,13 +820,13 @@ auto join(Range&& r, string_view sep)
|
||||
*
|
||||
* **Example**:
|
||||
*
|
||||
* auto t = std::tuple<int, char>{1, 'a'};
|
||||
* auto t = std::tuple<int, char>(1, 'a');
|
||||
* fmt::print("{}", fmt::join(t, ", "));
|
||||
* // Output: 1, a
|
||||
*/
|
||||
template <typename Tuple, FMT_ENABLE_IF(is_tuple_like<Tuple>::value)>
|
||||
FMT_CONSTEXPR auto join(const Tuple& tuple, string_view sep)
|
||||
-> tuple_join_view<char, Tuple> {
|
||||
FMT_CONSTEXPR auto join(const Tuple& tuple FMT_LIFETIMEBOUND, string_view sep)
|
||||
-> tuple_join_view<Tuple, char> {
|
||||
return {tuple, sep};
|
||||
}
|
||||
|
||||
|
||||
@@ -15,15 +15,13 @@
|
||||
# include <atomic>
|
||||
# include <bitset>
|
||||
# include <complex>
|
||||
# include <cstdlib>
|
||||
# include <exception>
|
||||
# include <functional>
|
||||
# include <functional> // std::reference_wrapper
|
||||
# include <memory>
|
||||
# include <thread>
|
||||
# include <type_traits>
|
||||
# include <typeinfo>
|
||||
# include <utility>
|
||||
# include <vector>
|
||||
# include <typeinfo> // std::type_info
|
||||
# include <utility> // std::make_index_sequence
|
||||
|
||||
// Check FMT_CPLUSPLUS to suppress a bogus warning in MSVC.
|
||||
# if FMT_CPLUSPLUS >= 201703L
|
||||
@@ -62,27 +60,26 @@
|
||||
# endif
|
||||
#endif
|
||||
|
||||
// For older Xcode versions, __cpp_lib_xxx flags are inaccurately defined.
|
||||
#ifndef FMT_CPP_LIB_FILESYSTEM
|
||||
# ifdef __cpp_lib_filesystem
|
||||
# define FMT_CPP_LIB_FILESYSTEM __cpp_lib_filesystem
|
||||
# else
|
||||
# define FMT_CPP_LIB_FILESYSTEM 0
|
||||
# endif
|
||||
#ifdef FMT_CPP_LIB_FILESYSTEM
|
||||
// Use the provided definition.
|
||||
#elif defined(__cpp_lib_filesystem)
|
||||
# define FMT_CPP_LIB_FILESYSTEM __cpp_lib_filesystem
|
||||
#else
|
||||
# define FMT_CPP_LIB_FILESYSTEM 0
|
||||
#endif
|
||||
|
||||
#ifndef FMT_CPP_LIB_VARIANT
|
||||
# ifdef __cpp_lib_variant
|
||||
# define FMT_CPP_LIB_VARIANT __cpp_lib_variant
|
||||
# else
|
||||
# define FMT_CPP_LIB_VARIANT 0
|
||||
# endif
|
||||
#ifdef FMT_CPP_LIB_VARIANT
|
||||
// Use the provided definition.
|
||||
#elif defined(__cpp_lib_variant)
|
||||
# define FMT_CPP_LIB_VARIANT __cpp_lib_variant
|
||||
#else
|
||||
# define FMT_CPP_LIB_VARIANT 0
|
||||
#endif
|
||||
|
||||
FMT_BEGIN_NAMESPACE
|
||||
namespace detail {
|
||||
|
||||
#if FMT_CPP_LIB_FILESYSTEM
|
||||
FMT_BEGIN_NAMESPACE
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <typename Char, typename PathChar>
|
||||
auto get_path_string(const std::filesystem::path& p,
|
||||
@@ -111,8 +108,180 @@ void write_escaped_path(basic_memory_buffer<Char>& quoted,
|
||||
}
|
||||
}
|
||||
|
||||
#endif // FMT_CPP_LIB_FILESYSTEM
|
||||
|
||||
#if defined(__cpp_lib_expected) || FMT_CPP_LIB_VARIANT
|
||||
|
||||
template <typename Char, typename OutputIt, typename T, typename FormatContext>
|
||||
auto write_escaped_alternative(OutputIt out, const T& v, FormatContext& ctx)
|
||||
-> OutputIt {
|
||||
if constexpr (has_to_string_view<T>::value)
|
||||
return write_escaped_string<Char>(out, detail::to_string_view(v));
|
||||
if constexpr (std::is_same_v<T, Char>) return write_escaped_char(out, v);
|
||||
|
||||
formatter<std::remove_cv_t<T>, Char> underlying;
|
||||
maybe_set_debug_format(underlying, true);
|
||||
return underlying.format(v, ctx);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if FMT_CPP_LIB_VARIANT
|
||||
|
||||
template <typename> struct is_variant_like_ : std::false_type {};
|
||||
template <typename... Types>
|
||||
struct is_variant_like_<std::variant<Types...>> : std::true_type {};
|
||||
|
||||
template <typename Variant, typename Char> class is_variant_formattable {
|
||||
template <size_t... Is>
|
||||
static auto check(std::index_sequence<Is...>) -> std::conjunction<
|
||||
is_formattable<std::variant_alternative_t<Is, Variant>, Char>...>;
|
||||
|
||||
public:
|
||||
static constexpr bool value = decltype(check(
|
||||
std::make_index_sequence<std::variant_size<Variant>::value>()))::value;
|
||||
};
|
||||
|
||||
#endif // FMT_CPP_LIB_VARIANT
|
||||
|
||||
#if FMT_USE_RTTI
|
||||
inline auto normalize_libcxx_inline_namespaces(string_view demangled_name_view,
|
||||
char* begin) -> string_view {
|
||||
// Normalization of stdlib inline namespace names.
|
||||
// libc++ inline namespaces.
|
||||
// std::__1::* -> std::*
|
||||
// std::__1::__fs::* -> std::*
|
||||
// libstdc++ inline namespaces.
|
||||
// std::__cxx11::* -> std::*
|
||||
// std::filesystem::__cxx11::* -> std::filesystem::*
|
||||
if (demangled_name_view.starts_with("std::")) {
|
||||
char* to = begin + 5; // std::
|
||||
for (const char *from = to, *end = begin + demangled_name_view.size();
|
||||
from < end;) {
|
||||
// This is safe, because demangled_name is NUL-terminated.
|
||||
if (from[0] == '_' && from[1] == '_') {
|
||||
const char* next = from + 1;
|
||||
while (next < end && *next != ':') next++;
|
||||
if (next[0] == ':' && next[1] == ':') {
|
||||
from = next + 2;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
*to++ = *from++;
|
||||
}
|
||||
demangled_name_view = {begin, detail::to_unsigned(to - begin)};
|
||||
}
|
||||
return demangled_name_view;
|
||||
}
|
||||
|
||||
template <class OutputIt>
|
||||
auto normalize_msvc_abi_name(string_view abi_name_view, OutputIt out)
|
||||
-> OutputIt {
|
||||
const string_view demangled_name(abi_name_view);
|
||||
for (size_t i = 0; i < demangled_name.size(); ++i) {
|
||||
auto sub = demangled_name;
|
||||
sub.remove_prefix(i);
|
||||
if (sub.starts_with("enum ")) {
|
||||
i += 4;
|
||||
continue;
|
||||
}
|
||||
if (sub.starts_with("class ") || sub.starts_with("union ")) {
|
||||
i += 5;
|
||||
continue;
|
||||
}
|
||||
if (sub.starts_with("struct ")) {
|
||||
i += 6;
|
||||
continue;
|
||||
}
|
||||
if (*sub.begin() != ' ') *out++ = *sub.begin();
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
template <typename OutputIt>
|
||||
auto write_demangled_name(OutputIt out, const std::type_info& ti) -> OutputIt {
|
||||
# ifdef FMT_HAS_ABI_CXA_DEMANGLE
|
||||
int status = 0;
|
||||
size_t size = 0;
|
||||
std::unique_ptr<char, void (*)(void*)> demangled_name_ptr(
|
||||
abi::__cxa_demangle(ti.name(), nullptr, &size, &status), &free);
|
||||
|
||||
string_view demangled_name_view;
|
||||
if (demangled_name_ptr) {
|
||||
demangled_name_view = normalize_libcxx_inline_namespaces(
|
||||
demangled_name_ptr.get(), demangled_name_ptr.get());
|
||||
} else {
|
||||
demangled_name_view = string_view(ti.name());
|
||||
}
|
||||
return detail::write_bytes<char>(out, demangled_name_view);
|
||||
# elif FMT_MSC_VERSION && defined(_MSVC_STL_UPDATE)
|
||||
return normalize_msvc_abi_name(ti.name(), out);
|
||||
# elif FMT_MSC_VERSION && defined(_LIBCPP_VERSION)
|
||||
const string_view demangled_name = ti.name();
|
||||
std::string name_copy(demangled_name.size(), '\0');
|
||||
// normalize_msvc_abi_name removes class, struct, union etc that MSVC has in
|
||||
// front of types
|
||||
name_copy.erase(normalize_msvc_abi_name(demangled_name, name_copy.begin()),
|
||||
name_copy.end());
|
||||
// normalize_libcxx_inline_namespaces removes the inline __1, __2, etc
|
||||
// namespaces libc++ uses for ABI versioning On MSVC ABI + libc++
|
||||
// environments, we need to eliminate both of them.
|
||||
const string_view normalized_name =
|
||||
normalize_libcxx_inline_namespaces(name_copy, name_copy.data());
|
||||
return detail::write_bytes<char>(out, normalized_name);
|
||||
# else
|
||||
return detail::write_bytes<char>(out, string_view(ti.name()));
|
||||
# endif
|
||||
}
|
||||
|
||||
#endif // FMT_USE_RTTI
|
||||
|
||||
template <typename T, typename Enable = void>
|
||||
struct has_flip : std::false_type {};
|
||||
|
||||
template <typename T>
|
||||
struct has_flip<T, void_t<decltype(std::declval<T>().flip())>>
|
||||
: std::true_type {};
|
||||
|
||||
template <typename T> struct is_bit_reference_like {
|
||||
static constexpr bool value = std::is_convertible<T, bool>::value &&
|
||||
std::is_nothrow_assignable<T, bool>::value &&
|
||||
has_flip<T>::value;
|
||||
};
|
||||
|
||||
// Workaround for libc++ incompatibility with C++ standard.
|
||||
// According to the Standard, `bitset::operator[] const` returns bool.
|
||||
#if defined(_LIBCPP_VERSION) && !defined(FMT_IMPORT_STD)
|
||||
template <typename C>
|
||||
struct is_bit_reference_like<std::__bit_const_reference<C>> {
|
||||
static constexpr bool value = true;
|
||||
};
|
||||
#endif
|
||||
|
||||
template <typename T, typename Enable = void>
|
||||
struct has_format_as : std::false_type {};
|
||||
template <typename T>
|
||||
struct has_format_as<T, void_t<decltype(format_as(std::declval<const T&>()))>>
|
||||
: std::true_type {};
|
||||
|
||||
template <typename T, typename Enable = void>
|
||||
struct has_format_as_member : std::false_type {};
|
||||
template <typename T>
|
||||
struct has_format_as_member<
|
||||
T, void_t<decltype(formatter<T>::format_as(std::declval<const T&>()))>>
|
||||
: std::true_type {};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template <typename T, typename Deleter>
|
||||
auto ptr(const std::unique_ptr<T, Deleter>& p) -> const void* {
|
||||
return p.get();
|
||||
}
|
||||
template <typename T> auto ptr(const std::shared_ptr<T>& p) -> const void* {
|
||||
return p.get();
|
||||
}
|
||||
|
||||
#if FMT_CPP_LIB_FILESYSTEM
|
||||
|
||||
template <typename Char> struct formatter<std::filesystem::path, Char> {
|
||||
private:
|
||||
format_specs specs_;
|
||||
@@ -177,24 +346,20 @@ class path : public std::filesystem::path {
|
||||
auto generic_system_string() const -> std::string { return generic_string(); }
|
||||
};
|
||||
|
||||
FMT_END_NAMESPACE
|
||||
#endif // FMT_CPP_LIB_FILESYSTEM
|
||||
|
||||
FMT_BEGIN_NAMESPACE
|
||||
template <std::size_t N, typename Char>
|
||||
template <size_t N, typename Char>
|
||||
struct formatter<std::bitset<N>, Char>
|
||||
: nested_formatter<basic_string_view<Char>, Char> {
|
||||
private:
|
||||
// Functor because C++11 doesn't support generic lambdas.
|
||||
// This is a functor because C++11 doesn't support generic lambdas.
|
||||
struct writer {
|
||||
const std::bitset<N>& bs;
|
||||
|
||||
template <typename OutputIt>
|
||||
FMT_CONSTEXPR auto operator()(OutputIt out) -> OutputIt {
|
||||
for (auto pos = N; pos > 0; --pos) {
|
||||
for (auto pos = N; pos > 0; --pos)
|
||||
out = detail::write<Char>(out, bs[pos - 1] ? Char('1') : Char('0'));
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
};
|
||||
@@ -209,33 +374,22 @@ struct formatter<std::bitset<N>, Char>
|
||||
|
||||
template <typename Char>
|
||||
struct formatter<std::thread::id, Char> : basic_ostream_formatter<Char> {};
|
||||
FMT_END_NAMESPACE
|
||||
|
||||
#ifdef __cpp_lib_optional
|
||||
FMT_BEGIN_NAMESPACE
|
||||
template <typename T, typename Char>
|
||||
struct formatter<std::optional<T>, Char,
|
||||
std::enable_if_t<is_formattable<T, Char>::value>> {
|
||||
private:
|
||||
formatter<T, Char> underlying_;
|
||||
formatter<std::remove_cv_t<T>, Char> underlying_;
|
||||
static constexpr basic_string_view<Char> optional =
|
||||
detail::string_literal<Char, 'o', 'p', 't', 'i', 'o', 'n', 'a', 'l',
|
||||
'('>{};
|
||||
static constexpr basic_string_view<Char> none =
|
||||
detail::string_literal<Char, 'n', 'o', 'n', 'e'>{};
|
||||
|
||||
template <class U>
|
||||
FMT_CONSTEXPR static auto maybe_set_debug_format(U& u, bool set)
|
||||
-> decltype(u.set_debug_format(set)) {
|
||||
u.set_debug_format(set);
|
||||
}
|
||||
|
||||
template <class U>
|
||||
FMT_CONSTEXPR static void maybe_set_debug_format(U&, ...) {}
|
||||
|
||||
public:
|
||||
FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) {
|
||||
maybe_set_debug_format(underlying_, true);
|
||||
detail::maybe_set_debug_format(underlying_, true);
|
||||
return underlying_.parse(ctx);
|
||||
}
|
||||
|
||||
@@ -251,30 +405,9 @@ struct formatter<std::optional<T>, Char,
|
||||
return detail::write(out, ')');
|
||||
}
|
||||
};
|
||||
FMT_END_NAMESPACE
|
||||
#endif // __cpp_lib_optional
|
||||
|
||||
#if defined(__cpp_lib_expected) || FMT_CPP_LIB_VARIANT
|
||||
|
||||
FMT_BEGIN_NAMESPACE
|
||||
namespace detail {
|
||||
|
||||
template <typename Char, typename OutputIt, typename T>
|
||||
auto write_escaped_alternative(OutputIt out, const T& v) -> OutputIt {
|
||||
if constexpr (has_to_string_view<T>::value)
|
||||
return write_escaped_string<Char>(out, detail::to_string_view(v));
|
||||
if constexpr (std::is_same_v<T, Char>) return write_escaped_char(out, v);
|
||||
return write<Char>(out, v);
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
FMT_END_NAMESPACE
|
||||
#endif
|
||||
|
||||
#ifdef __cpp_lib_expected
|
||||
FMT_BEGIN_NAMESPACE
|
||||
|
||||
template <typename T, typename E, typename Char>
|
||||
struct formatter<std::expected<T, E>, Char,
|
||||
std::enable_if_t<(std::is_void<T>::value ||
|
||||
@@ -292,20 +425,18 @@ struct formatter<std::expected<T, E>, Char,
|
||||
if (value.has_value()) {
|
||||
out = detail::write<Char>(out, "expected(");
|
||||
if constexpr (!std::is_void<T>::value)
|
||||
out = detail::write_escaped_alternative<Char>(out, *value);
|
||||
out = detail::write_escaped_alternative<Char>(out, *value, ctx);
|
||||
} else {
|
||||
out = detail::write<Char>(out, "unexpected(");
|
||||
out = detail::write_escaped_alternative<Char>(out, value.error());
|
||||
out = detail::write_escaped_alternative<Char>(out, value.error(), ctx);
|
||||
}
|
||||
*out++ = ')';
|
||||
return out;
|
||||
}
|
||||
};
|
||||
FMT_END_NAMESPACE
|
||||
#endif // __cpp_lib_expected
|
||||
|
||||
#ifdef __cpp_lib_source_location
|
||||
FMT_BEGIN_NAMESPACE
|
||||
template <> struct formatter<std::source_location> {
|
||||
FMT_CONSTEXPR auto parse(parse_context<>& ctx) { return ctx.begin(); }
|
||||
|
||||
@@ -323,42 +454,12 @@ template <> struct formatter<std::source_location> {
|
||||
return out;
|
||||
}
|
||||
};
|
||||
FMT_END_NAMESPACE
|
||||
#endif
|
||||
|
||||
#if FMT_CPP_LIB_VARIANT
|
||||
FMT_BEGIN_NAMESPACE
|
||||
namespace detail {
|
||||
|
||||
template <typename T>
|
||||
using variant_index_sequence =
|
||||
std::make_index_sequence<std::variant_size<T>::value>;
|
||||
|
||||
template <typename> struct is_variant_like_ : std::false_type {};
|
||||
template <typename... Types>
|
||||
struct is_variant_like_<std::variant<Types...>> : std::true_type {};
|
||||
|
||||
// formattable element check.
|
||||
template <typename T, typename C> class is_variant_formattable_ {
|
||||
template <std::size_t... Is>
|
||||
static std::conjunction<
|
||||
is_formattable<std::variant_alternative_t<Is, T>, C>...>
|
||||
check(std::index_sequence<Is...>);
|
||||
|
||||
public:
|
||||
static constexpr const bool value =
|
||||
decltype(check(variant_index_sequence<T>{}))::value;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template <typename T> struct is_variant_like {
|
||||
static constexpr const bool value = detail::is_variant_like_<T>::value;
|
||||
};
|
||||
|
||||
template <typename T, typename C> struct is_variant_formattable {
|
||||
static constexpr const bool value =
|
||||
detail::is_variant_formattable_<T, C>::value;
|
||||
static constexpr bool value = detail::is_variant_like_<T>::value;
|
||||
};
|
||||
|
||||
template <typename Char> struct formatter<std::monostate, Char> {
|
||||
@@ -374,10 +475,10 @@ template <typename Char> struct formatter<std::monostate, Char> {
|
||||
};
|
||||
|
||||
template <typename Variant, typename Char>
|
||||
struct formatter<
|
||||
Variant, Char,
|
||||
std::enable_if_t<std::conjunction_v<
|
||||
is_variant_like<Variant>, is_variant_formattable<Variant, Char>>>> {
|
||||
struct formatter<Variant, Char,
|
||||
std::enable_if_t<std::conjunction_v<
|
||||
is_variant_like<Variant>,
|
||||
detail::is_variant_formattable<Variant, Char>>>> {
|
||||
FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* {
|
||||
return ctx.begin();
|
||||
}
|
||||
@@ -391,7 +492,7 @@ struct formatter<
|
||||
FMT_TRY {
|
||||
std::visit(
|
||||
[&](const auto& v) {
|
||||
out = detail::write_escaped_alternative<Char>(out, v);
|
||||
out = detail::write_escaped_alternative<Char>(out, v, ctx);
|
||||
},
|
||||
value);
|
||||
}
|
||||
@@ -402,10 +503,9 @@ struct formatter<
|
||||
return out;
|
||||
}
|
||||
};
|
||||
FMT_END_NAMESPACE
|
||||
|
||||
#endif // FMT_CPP_LIB_VARIANT
|
||||
|
||||
FMT_BEGIN_NAMESPACE
|
||||
template <> struct formatter<std::error_code> {
|
||||
private:
|
||||
format_specs specs_;
|
||||
@@ -413,6 +513,8 @@ template <> struct formatter<std::error_code> {
|
||||
bool debug_ = false;
|
||||
|
||||
public:
|
||||
FMT_CONSTEXPR void set_debug_format(bool set = true) { debug_ = set; }
|
||||
|
||||
FMT_CONSTEXPR auto parse(parse_context<>& ctx) -> const char* {
|
||||
auto it = ctx.begin(), end = ctx.end();
|
||||
if (it == end) return it;
|
||||
@@ -459,101 +561,29 @@ template <> struct formatter<std::error_code> {
|
||||
};
|
||||
|
||||
#if FMT_USE_RTTI
|
||||
namespace detail {
|
||||
|
||||
template <typename Char, typename OutputIt>
|
||||
auto write_demangled_name(OutputIt out, const std::type_info& ti) -> OutputIt {
|
||||
# ifdef FMT_HAS_ABI_CXA_DEMANGLE
|
||||
int status = 0;
|
||||
std::size_t size = 0;
|
||||
std::unique_ptr<char, void (*)(void*)> demangled_name_ptr(
|
||||
abi::__cxa_demangle(ti.name(), nullptr, &size, &status), &std::free);
|
||||
|
||||
string_view demangled_name_view;
|
||||
if (demangled_name_ptr) {
|
||||
demangled_name_view = demangled_name_ptr.get();
|
||||
|
||||
// Normalization of stdlib inline namespace names.
|
||||
// libc++ inline namespaces.
|
||||
// std::__1::* -> std::*
|
||||
// std::__1::__fs::* -> std::*
|
||||
// libstdc++ inline namespaces.
|
||||
// std::__cxx11::* -> std::*
|
||||
// std::filesystem::__cxx11::* -> std::filesystem::*
|
||||
if (demangled_name_view.starts_with("std::")) {
|
||||
char* begin = demangled_name_ptr.get();
|
||||
char* to = begin + 5; // std::
|
||||
for (char *from = to, *end = begin + demangled_name_view.size();
|
||||
from < end;) {
|
||||
// This is safe, because demangled_name is NUL-terminated.
|
||||
if (from[0] == '_' && from[1] == '_') {
|
||||
char* next = from + 1;
|
||||
while (next < end && *next != ':') next++;
|
||||
if (next[0] == ':' && next[1] == ':') {
|
||||
from = next + 2;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
*to++ = *from++;
|
||||
}
|
||||
demangled_name_view = {begin, detail::to_unsigned(to - begin)};
|
||||
}
|
||||
} else {
|
||||
demangled_name_view = string_view(ti.name());
|
||||
}
|
||||
return detail::write_bytes<Char>(out, demangled_name_view);
|
||||
# elif FMT_MSC_VERSION
|
||||
const string_view demangled_name(ti.name());
|
||||
for (std::size_t i = 0; i < demangled_name.size(); ++i) {
|
||||
auto sub = demangled_name;
|
||||
sub.remove_prefix(i);
|
||||
if (sub.starts_with("enum ")) {
|
||||
i += 4;
|
||||
continue;
|
||||
}
|
||||
if (sub.starts_with("class ") || sub.starts_with("union ")) {
|
||||
i += 5;
|
||||
continue;
|
||||
}
|
||||
if (sub.starts_with("struct ")) {
|
||||
i += 6;
|
||||
continue;
|
||||
}
|
||||
if (*sub.begin() != ' ') *out++ = *sub.begin();
|
||||
}
|
||||
return out;
|
||||
# else
|
||||
return detail::write_bytes<Char>(out, string_view(ti.name()));
|
||||
# endif
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template <typename Char>
|
||||
struct formatter<std::type_info, Char // DEPRECATED! Mixing code unit types.
|
||||
> {
|
||||
template <> struct formatter<std::type_info> {
|
||||
public:
|
||||
FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* {
|
||||
FMT_CONSTEXPR auto parse(parse_context<>& ctx) -> const char* {
|
||||
return ctx.begin();
|
||||
}
|
||||
|
||||
template <typename Context>
|
||||
auto format(const std::type_info& ti, Context& ctx) const
|
||||
-> decltype(ctx.out()) {
|
||||
return detail::write_demangled_name<Char>(ctx.out(), ti);
|
||||
return detail::write_demangled_name(ctx.out(), ti);
|
||||
}
|
||||
};
|
||||
#endif
|
||||
#endif // FMT_USE_RTTI
|
||||
|
||||
template <typename T, typename Char>
|
||||
template <typename T>
|
||||
struct formatter<
|
||||
T, Char, // DEPRECATED! Mixing code unit types.
|
||||
T, char,
|
||||
typename std::enable_if<std::is_base_of<std::exception, T>::value>::type> {
|
||||
private:
|
||||
bool with_typename_ = false;
|
||||
|
||||
public:
|
||||
FMT_CONSTEXPR auto parse(parse_context<Char>& ctx) -> const Char* {
|
||||
FMT_CONSTEXPR auto parse(parse_context<>& ctx) -> const char* {
|
||||
auto it = ctx.begin();
|
||||
auto end = ctx.end();
|
||||
if (it == end || *it == '}') return it;
|
||||
@@ -570,43 +600,15 @@ struct formatter<
|
||||
auto out = ctx.out();
|
||||
#if FMT_USE_RTTI
|
||||
if (with_typename_) {
|
||||
out = detail::write_demangled_name<Char>(out, typeid(ex));
|
||||
out = detail::write_demangled_name(out, typeid(ex));
|
||||
*out++ = ':';
|
||||
*out++ = ' ';
|
||||
}
|
||||
#endif
|
||||
return detail::write_bytes<Char>(out, string_view(ex.what()));
|
||||
return detail::write_bytes<char>(out, string_view(ex.what()));
|
||||
}
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <typename T, typename Enable = void>
|
||||
struct has_flip : std::false_type {};
|
||||
|
||||
template <typename T>
|
||||
struct has_flip<T, void_t<decltype(std::declval<T>().flip())>>
|
||||
: std::true_type {};
|
||||
|
||||
template <typename T> struct is_bit_reference_like {
|
||||
static constexpr const bool value =
|
||||
std::is_convertible<T, bool>::value &&
|
||||
std::is_nothrow_assignable<T, bool>::value && has_flip<T>::value;
|
||||
};
|
||||
|
||||
#ifdef _LIBCPP_VERSION
|
||||
|
||||
// Workaround for libc++ incompatibility with C++ standard.
|
||||
// According to the Standard, `bitset::operator[] const` returns bool.
|
||||
template <typename C>
|
||||
struct is_bit_reference_like<std::__bit_const_reference<C>> {
|
||||
static constexpr const bool value = true;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace detail
|
||||
|
||||
// We can't use std::vector<bool, Allocator>::reference and
|
||||
// std::bitset<N>::reference because the compiler can't deduce Allocator and N
|
||||
// in partial specialization.
|
||||
@@ -621,14 +623,6 @@ struct formatter<BitRef, Char,
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, typename Deleter>
|
||||
auto ptr(const std::unique_ptr<T, Deleter>& p) -> const void* {
|
||||
return p.get();
|
||||
}
|
||||
template <typename T> auto ptr(const std::shared_ptr<T>& p) -> const void* {
|
||||
return p.get();
|
||||
}
|
||||
|
||||
template <typename T, typename Char>
|
||||
struct formatter<std::atomic<T>, Char,
|
||||
enable_if_t<is_formattable<T, Char>::value>>
|
||||
@@ -715,7 +709,11 @@ template <typename T, typename Char> struct formatter<std::complex<T>, Char> {
|
||||
|
||||
template <typename T, typename Char>
|
||||
struct formatter<std::reference_wrapper<T>, Char,
|
||||
enable_if_t<is_formattable<remove_cvref_t<T>, Char>::value>>
|
||||
// Guard against format_as because reference_wrapper is
|
||||
// implicitly convertible to T&.
|
||||
enable_if_t<is_formattable<remove_cvref_t<T>, Char>::value &&
|
||||
!detail::has_format_as<T>::value &&
|
||||
!detail::has_format_as_member<T>::value>>
|
||||
: formatter<remove_cvref_t<T>, Char> {
|
||||
template <typename FormatContext>
|
||||
auto format(std::reference_wrapper<T> ref, FormatContext& ctx) const
|
||||
@@ -725,4 +723,5 @@ struct formatter<std::reference_wrapper<T>, Char,
|
||||
};
|
||||
|
||||
FMT_END_NAMESPACE
|
||||
|
||||
#endif // FMT_STD_H_
|
||||
|
||||
@@ -55,6 +55,16 @@ inline auto write_loc(basic_appender<wchar_t> out, loc_value value,
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename Char>
|
||||
void vformat_to(buffer<Char>& buf, basic_string_view<Char> fmt,
|
||||
basic_format_args<buffered_context<Char>> args,
|
||||
locale_ref loc = {}) {
|
||||
static_assert(!std::is_same<Char, char>::value, "");
|
||||
auto out = basic_appender<Char>(buf);
|
||||
parse_format_string(
|
||||
fmt, format_handler<Char>{parse_context<Char>(fmt), {out, args, loc}});
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
FMT_BEGIN_EXPORT
|
||||
@@ -112,10 +122,6 @@ inline auto runtime(wstring_view s) -> runtime_format_string<wchar_t> {
|
||||
return {{s}};
|
||||
}
|
||||
|
||||
#ifdef __cpp_char8_t
|
||||
template <> struct is_char<char8_t> : bool_constant<detail::is_utf8_enabled> {};
|
||||
#endif
|
||||
|
||||
template <typename... T>
|
||||
constexpr auto make_wformat_args(T&... args)
|
||||
-> decltype(fmt::make_format_args<wformat_context>(args...)) {
|
||||
@@ -151,13 +157,13 @@ auto join(std::initializer_list<T> list, wstring_view sep)
|
||||
|
||||
template <typename Tuple, FMT_ENABLE_IF(is_tuple_like<Tuple>::value)>
|
||||
auto join(const Tuple& tuple, basic_string_view<wchar_t> sep)
|
||||
-> tuple_join_view<wchar_t, Tuple> {
|
||||
-> tuple_join_view<Tuple, wchar_t> {
|
||||
return {tuple, sep};
|
||||
}
|
||||
|
||||
template <typename Char, FMT_ENABLE_IF(!std::is_same<Char, char>::value)>
|
||||
auto vformat(basic_string_view<Char> fmt,
|
||||
typename detail::vformat_args<Char>::type args)
|
||||
basic_format_args<buffered_context<Char>> args)
|
||||
-> std::basic_string<Char> {
|
||||
auto buf = basic_memory_buffer<Char>();
|
||||
detail::vformat_to(buf, fmt, args);
|
||||
@@ -187,24 +193,20 @@ auto format(const S& fmt, T&&... args) -> std::basic_string<Char> {
|
||||
fmt::make_format_args<buffered_context<Char>>(args...));
|
||||
}
|
||||
|
||||
template <typename Locale, typename S,
|
||||
typename Char = detail::format_string_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& fmt,
|
||||
typename detail::vformat_args<Char>::type args)
|
||||
template <typename S, typename Char = detail::format_string_char_t<S>,
|
||||
FMT_ENABLE_IF(detail::is_exotic_char<Char>::value)>
|
||||
inline auto vformat(locale_ref loc, const S& fmt,
|
||||
basic_format_args<buffered_context<Char>> args)
|
||||
-> std::basic_string<Char> {
|
||||
auto buf = basic_memory_buffer<Char>();
|
||||
detail::vformat_to(buf, detail::to_string_view(fmt), args,
|
||||
detail::locale_ref(loc));
|
||||
detail::vformat_to(buf, detail::to_string_view(fmt), args, loc);
|
||||
return {buf.data(), buf.size()};
|
||||
}
|
||||
|
||||
template <typename Locale, typename S, typename... T,
|
||||
template <typename S, typename... T,
|
||||
typename Char = detail::format_string_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& fmt, T&&... args)
|
||||
FMT_ENABLE_IF(detail::is_exotic_char<Char>::value)>
|
||||
inline auto format(locale_ref loc, const S& fmt, T&&... args)
|
||||
-> std::basic_string<Char> {
|
||||
return vformat(loc, detail::to_string_view(fmt),
|
||||
fmt::make_format_args<buffered_context<Char>>(args...));
|
||||
@@ -215,7 +217,7 @@ template <typename OutputIt, typename S,
|
||||
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value&&
|
||||
detail::is_exotic_char<Char>::value)>
|
||||
auto vformat_to(OutputIt out, const S& fmt,
|
||||
typename detail::vformat_args<Char>::type args) -> OutputIt {
|
||||
basic_format_args<buffered_context<Char>> args) -> OutputIt {
|
||||
auto&& buf = detail::get_buffer<Char>(out);
|
||||
detail::vformat_to(buf, detail::to_string_view(fmt), args);
|
||||
return detail::get_iterator(buf, out);
|
||||
@@ -231,27 +233,24 @@ inline auto format_to(OutputIt out, const S& fmt, T&&... args) -> OutputIt {
|
||||
fmt::make_format_args<buffered_context<Char>>(args...));
|
||||
}
|
||||
|
||||
template <typename Locale, typename S, typename OutputIt, typename... Args,
|
||||
template <typename S, typename OutputIt, typename... Args,
|
||||
typename Char = detail::format_string_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& fmt,
|
||||
typename detail::vformat_args<Char>::type args)
|
||||
detail::is_exotic_char<Char>::value)>
|
||||
inline auto vformat_to(OutputIt out, locale_ref loc, const S& fmt,
|
||||
basic_format_args<buffered_context<Char>> args)
|
||||
-> OutputIt {
|
||||
auto&& buf = detail::get_buffer<Char>(out);
|
||||
vformat_to(buf, detail::to_string_view(fmt), args, detail::locale_ref(loc));
|
||||
vformat_to(buf, detail::to_string_view(fmt), args, loc);
|
||||
return detail::get_iterator(buf, out);
|
||||
}
|
||||
|
||||
template <typename Locale, typename OutputIt, typename S, typename... T,
|
||||
template <typename OutputIt, typename S, typename... T,
|
||||
typename Char = detail::format_string_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& fmt,
|
||||
T&&... args) ->
|
||||
typename std::enable_if<enable, OutputIt>::type {
|
||||
inline auto format_to(OutputIt out, locale_ref loc, const S& fmt, T&&... args)
|
||||
-> typename std::enable_if<enable, OutputIt>::type {
|
||||
return vformat_to(out, loc, detail::to_string_view(fmt),
|
||||
fmt::make_format_args<buffered_context<Char>>(args...));
|
||||
}
|
||||
@@ -260,7 +259,7 @@ 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> fmt,
|
||||
typename detail::vformat_args<Char>::type args)
|
||||
basic_format_args<buffered_context<Char>> args)
|
||||
-> format_to_n_result<OutputIt> {
|
||||
using traits = detail::fixed_buffer_traits;
|
||||
auto buf = detail::iterator_buffer<OutputIt, Char, traits>(out, n);
|
||||
@@ -331,18 +330,6 @@ inline auto format(text_style ts, wformat_string<T...> fmt, T&&... args)
|
||||
return fmt::vformat(ts, fmt, fmt::make_wformat_args(args...));
|
||||
}
|
||||
|
||||
template <typename... T>
|
||||
FMT_DEPRECATED void print(std::FILE* f, text_style ts, wformat_string<T...> fmt,
|
||||
const T&... args) {
|
||||
vprint(f, ts, fmt, fmt::make_wformat_args(args...));
|
||||
}
|
||||
|
||||
template <typename... T>
|
||||
FMT_DEPRECATED void print(text_style ts, wformat_string<T...> fmt,
|
||||
const T&... args) {
|
||||
return print(stdout, ts, fmt, args...);
|
||||
}
|
||||
|
||||
inline void vprint(std::wostream& os, wstring_view fmt, wformat_args args) {
|
||||
auto buffer = basic_memory_buffer<wchar_t>();
|
||||
detail::vformat_to(buffer, fmt, args);
|
||||
|
||||
@@ -10,14 +10,14 @@
|
||||
#include <spdlog/tweakme.h>
|
||||
|
||||
#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
|
||||
#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
|
||||
|
||||
@@ -10,14 +10,14 @@
|
||||
#include <spdlog/tweakme.h>
|
||||
|
||||
#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
|
||||
#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
|
||||
|
||||
@@ -12,15 +12,15 @@
|
||||
#include <spdlog/tweakme.h>
|
||||
|
||||
#if defined(SPDLOG_USE_STD_FORMAT) // SPDLOG_USE_STD_FORMAT is defined - use std::format
|
||||
#include <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
|
||||
#include <spdlog/fmt/bundled/format.h>
|
||||
#else // SPDLOG_FMT_EXTERNAL is defined - use external fmtlib
|
||||
#include <fmt/format.h>
|
||||
#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
|
||||
#include <spdlog/fmt/bundled/format.h>
|
||||
#else // SPDLOG_FMT_EXTERNAL is defined - use external fmtlib
|
||||
#include <fmt/format.h>
|
||||
#endif
|
||||
|
||||
@@ -10,14 +10,14 @@
|
||||
#include <spdlog/tweakme.h>
|
||||
|
||||
#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
|
||||
#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
|
||||
|
||||
@@ -10,14 +10,14 @@
|
||||
#include <spdlog/tweakme.h>
|
||||
|
||||
#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
|
||||
#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
|
||||
|
||||
@@ -11,14 +11,14 @@
|
||||
#include <spdlog/tweakme.h>
|
||||
|
||||
#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/std.h>
|
||||
#else
|
||||
#include <fmt/std.h>
|
||||
#endif
|
||||
#if !defined(SPDLOG_FMT_EXTERNAL)
|
||||
#ifdef SPDLOG_HEADER_ONLY
|
||||
#ifndef FMT_HEADER_ONLY
|
||||
#define FMT_HEADER_ONLY
|
||||
#endif
|
||||
#endif
|
||||
#include <spdlog/fmt/bundled/std.h>
|
||||
#else
|
||||
#include <fmt/std.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -10,14 +10,14 @@
|
||||
#include <spdlog/tweakme.h>
|
||||
|
||||
#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
|
||||
#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
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef SPDLOG_HEADER_ONLY
|
||||
#include <spdlog/logger.h>
|
||||
#include <spdlog/logger.h>
|
||||
#endif
|
||||
|
||||
#include <spdlog/details/backtracer.h>
|
||||
|
||||
@@ -19,30 +19,30 @@
|
||||
#include <spdlog/details/log_msg.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>
|
||||
#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(SPDLOG_FMT_STRING("{} [{}({})]"), ex.what(), \
|
||||
location.filename, location.line)); \
|
||||
} else { \
|
||||
err_handler_(ex.what()); \
|
||||
} \
|
||||
} \
|
||||
catch (...) { \
|
||||
err_handler_("Rethrowing unknown exception in logger"); \
|
||||
throw; \
|
||||
}
|
||||
#define SPDLOG_LOGGER_CATCH(location) \
|
||||
catch (const std::exception &ex) { \
|
||||
if (location.filename) { \
|
||||
err_handler_(fmt_lib::format(SPDLOG_FMT_STRING("{} [{}({})]"), 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)
|
||||
#define SPDLOG_LOGGER_CATCH(location)
|
||||
#endif
|
||||
|
||||
namespace spdlog {
|
||||
@@ -375,5 +375,5 @@ void swap(logger &a, logger &b) noexcept;
|
||||
} // namespace spdlog
|
||||
|
||||
#ifdef SPDLOG_HEADER_ONLY
|
||||
#include "logger-inl.h"
|
||||
#include "logger-inl.h"
|
||||
#endif
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#pragma once
|
||||
|
||||
#if defined(SPDLOG_NO_TLS)
|
||||
#error "This header requires thread local storage support, but SPDLOG_NO_TLS is defined."
|
||||
#error "This header requires thread local storage support, but SPDLOG_NO_TLS is defined."
|
||||
#endif
|
||||
|
||||
#include <map>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef SPDLOG_HEADER_ONLY
|
||||
#include <spdlog/pattern_formatter.h>
|
||||
#include <spdlog/pattern_formatter.h>
|
||||
#endif
|
||||
|
||||
#include <spdlog/details/fmt_helper.h>
|
||||
@@ -12,7 +12,7 @@
|
||||
#include <spdlog/details/os.h>
|
||||
|
||||
#ifndef SPDLOG_NO_TLS
|
||||
#include <spdlog/mdc.h>
|
||||
#include <spdlog/mdc.h>
|
||||
#endif
|
||||
|
||||
#include <spdlog/fmt/fmt.h>
|
||||
@@ -510,6 +510,7 @@ public:
|
||||
};
|
||||
|
||||
// ISO 8601 offset from UTC in timezone (+-HH:MM)
|
||||
// If SPDLOG_NO_TZ_OFFSET is defined, print "+??.??" instead.
|
||||
template <typename ScopedPadder>
|
||||
class z_formatter final : public flag_formatter {
|
||||
public:
|
||||
@@ -524,6 +525,10 @@ public:
|
||||
const size_t field_size = 6;
|
||||
ScopedPadder p(field_size, padinfo_, dest);
|
||||
|
||||
#ifdef SPDLOG_NO_TZ_OFFSET
|
||||
const char *str = "+??:??";
|
||||
dest.append(str, str + 6);
|
||||
#else
|
||||
auto total_minutes = get_cached_offset(msg, tm_time);
|
||||
bool is_negative = total_minutes < 0;
|
||||
if (is_negative) {
|
||||
@@ -536,6 +541,7 @@ public:
|
||||
fmt_helper::pad2(total_minutes / 60, dest); // hours
|
||||
dest.push_back(':');
|
||||
fmt_helper::pad2(total_minutes % 60, dest); // minutes
|
||||
#endif // SPDLOG_NO_TZ_OFFSET
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -696,9 +702,9 @@ public:
|
||||
: flag_formatter(padinfo) {}
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4127) // consider using 'if constexpr' instead
|
||||
#endif // _MSC_VER
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4127) // consider using 'if constexpr' instead
|
||||
#endif // _MSC_VER
|
||||
static const char *basename(const char *filename) {
|
||||
// if the size is 2 (1 character + null terminator) we can use the more efficient strrchr
|
||||
// the branch will be elided by optimizations
|
||||
@@ -715,7 +721,7 @@ public:
|
||||
}
|
||||
}
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#pragma warning(pop)
|
||||
#endif // _MSC_VER
|
||||
|
||||
void format(const details::log_msg &msg, const std::tm &, memory_buf_t &dest) override {
|
||||
@@ -1154,12 +1160,10 @@ SPDLOG_INLINE void pattern_formatter::handle_flag_(char flag, details::padding_i
|
||||
formatters_.push_back(details::make_unique<details::T_formatter<Padder>>(padding));
|
||||
need_localtime_ = true;
|
||||
break;
|
||||
|
||||
case ('z'): // timezone
|
||||
formatters_.push_back(details::make_unique<details::z_formatter<Padder>>(padding));
|
||||
need_localtime_ = true;
|
||||
break;
|
||||
|
||||
case ('P'): // pid
|
||||
formatters_.push_back(details::make_unique<details::pid_formatter<Padder>>(padding));
|
||||
break;
|
||||
|
||||
@@ -114,5 +114,5 @@ private:
|
||||
} // namespace spdlog
|
||||
|
||||
#ifdef SPDLOG_HEADER_ONLY
|
||||
#include "pattern_formatter-inl.h"
|
||||
#include "pattern_formatter-inl.h"
|
||||
#endif
|
||||
|
||||
@@ -5,22 +5,22 @@
|
||||
|
||||
#ifdef __ANDROID__
|
||||
|
||||
#include <spdlog/details/fmt_helper.h>
|
||||
#include <spdlog/details/null_mutex.h>
|
||||
#include <spdlog/details/os.h>
|
||||
#include <spdlog/details/synchronous_factory.h>
|
||||
#include <spdlog/sinks/base_sink.h>
|
||||
#include <spdlog/details/fmt_helper.h>
|
||||
#include <spdlog/details/null_mutex.h>
|
||||
#include <spdlog/details/os.h>
|
||||
#include <spdlog/details/synchronous_factory.h>
|
||||
#include <spdlog/sinks/base_sink.h>
|
||||
|
||||
#include <android/log.h>
|
||||
#include <chrono>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <type_traits>
|
||||
#include <android/log.h>
|
||||
#include <chrono>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <type_traits>
|
||||
|
||||
#if !defined(SPDLOG_ANDROID_RETRIES)
|
||||
#define SPDLOG_ANDROID_RETRIES 2
|
||||
#endif
|
||||
#if !defined(SPDLOG_ANDROID_RETRIES)
|
||||
#define SPDLOG_ANDROID_RETRIES 2
|
||||
#endif
|
||||
|
||||
namespace spdlog {
|
||||
namespace sinks {
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef SPDLOG_HEADER_ONLY
|
||||
#include <spdlog/sinks/ansicolor_sink.h>
|
||||
#include <spdlog/sinks/ansicolor_sink.h>
|
||||
#endif
|
||||
|
||||
#include <spdlog/details/os.h>
|
||||
|
||||
@@ -78,8 +78,10 @@ public:
|
||||
const string_view_t red_bold = "\033[31m\033[1m";
|
||||
const string_view_t bold_on_red = "\033[1m\033[41m";
|
||||
|
||||
private:
|
||||
protected:
|
||||
FILE *target_file_;
|
||||
|
||||
private:
|
||||
mutex_t &mutex_;
|
||||
bool should_do_colors_;
|
||||
std::unique_ptr<spdlog::formatter> formatter_;
|
||||
@@ -112,5 +114,5 @@ using ansicolor_stderr_sink_st = ansicolor_stderr_sink<details::console_nullmute
|
||||
} // namespace spdlog
|
||||
|
||||
#ifdef SPDLOG_HEADER_ONLY
|
||||
#include "ansicolor_sink-inl.h"
|
||||
#include "ansicolor_sink-inl.h"
|
||||
#endif
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef SPDLOG_HEADER_ONLY
|
||||
#include <spdlog/sinks/base_sink.h>
|
||||
#include <spdlog/sinks/base_sink.h>
|
||||
#endif
|
||||
|
||||
#include <spdlog/common.h>
|
||||
|
||||
@@ -47,5 +47,5 @@ protected:
|
||||
} // namespace spdlog
|
||||
|
||||
#ifdef SPDLOG_HEADER_ONLY
|
||||
#include "base_sink-inl.h"
|
||||
#include "base_sink-inl.h"
|
||||
#endif
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef SPDLOG_HEADER_ONLY
|
||||
#include <spdlog/sinks/basic_file_sink.h>
|
||||
#include <spdlog/sinks/basic_file_sink.h>
|
||||
#endif
|
||||
|
||||
#include <spdlog/common.h>
|
||||
|
||||
@@ -62,5 +62,5 @@ inline std::shared_ptr<logger> basic_logger_st(const std::string &logger_name,
|
||||
} // namespace spdlog
|
||||
|
||||
#ifdef SPDLOG_HEADER_ONLY
|
||||
#include "basic_file_sink-inl.h"
|
||||
#include "basic_file_sink-inl.h"
|
||||
#endif
|
||||
|
||||
@@ -5,21 +5,21 @@
|
||||
|
||||
#if defined(_WIN32)
|
||||
|
||||
#include <spdlog/details/null_mutex.h>
|
||||
#if defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT)
|
||||
#include <spdlog/details/os.h>
|
||||
#endif
|
||||
#include <spdlog/sinks/base_sink.h>
|
||||
#include <spdlog/details/null_mutex.h>
|
||||
#if defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT)
|
||||
#include <spdlog/details/os.h>
|
||||
#endif
|
||||
#include <spdlog/sinks/base_sink.h>
|
||||
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
|
||||
// Avoid including windows.h (https://stackoverflow.com/a/30741042)
|
||||
#if defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT)
|
||||
// Avoid including windows.h (https://stackoverflow.com/a/30741042)
|
||||
#if defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT)
|
||||
extern "C" __declspec(dllimport) void __stdcall OutputDebugStringW(const wchar_t *lpOutputString);
|
||||
#else
|
||||
#else
|
||||
extern "C" __declspec(dllimport) void __stdcall OutputDebugStringA(const char *lpOutputString);
|
||||
#endif
|
||||
#endif
|
||||
extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent();
|
||||
|
||||
namespace spdlog {
|
||||
@@ -42,13 +42,13 @@ protected:
|
||||
memory_buf_t formatted;
|
||||
base_sink<Mutex>::formatter_->format(msg, formatted);
|
||||
formatted.push_back('\0'); // add a null terminator for OutputDebugString
|
||||
#if defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT)
|
||||
#if defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT)
|
||||
wmemory_buf_t wformatted;
|
||||
details::os::utf8_to_wstrbuf(string_view_t(formatted.data(), formatted.size()), wformatted);
|
||||
OutputDebugStringW(wformatted.data());
|
||||
#else
|
||||
#else
|
||||
OutputDebugStringA(formatted.data());
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
void flush_() override {}
|
||||
|
||||
@@ -160,20 +160,24 @@ protected:
|
||||
payload = QString::fromUtf8(str.data(), static_cast<int>(str.size()));
|
||||
// convert color ranges from byte index to character index.
|
||||
if (msg.color_range_start < msg.color_range_end) {
|
||||
color_range_start = QString::fromUtf8(str.data(), msg.color_range_start).size();
|
||||
color_range_end = QString::fromUtf8(str.data(), msg.color_range_end).size();
|
||||
color_range_start =
|
||||
QString::fromUtf8(str.data(), static_cast<qsizetype>(msg.color_range_start))
|
||||
.size();
|
||||
color_range_end =
|
||||
QString::fromUtf8(str.data(), static_cast<qsizetype>(msg.color_range_end))
|
||||
.size();
|
||||
}
|
||||
} else {
|
||||
payload = QString::fromLatin1(str.data(), static_cast<int>(str.size()));
|
||||
}
|
||||
|
||||
invoke_params params{max_lines_, // max lines
|
||||
qt_text_edit_, // text edit to append to
|
||||
std::move(payload), // text to append
|
||||
default_color_, // default color
|
||||
colors_.at(msg.level), // color to apply
|
||||
color_range_start, // color range start
|
||||
color_range_end}; // color range end
|
||||
invoke_params params{max_lines_, // max lines
|
||||
qt_text_edit_, // text edit to append to
|
||||
std::move(payload), // text to append
|
||||
default_color_, // default color
|
||||
colors_.at(static_cast<size_t>(msg.level)), // color to apply
|
||||
color_range_start, // color range start
|
||||
color_range_end}; // color range end
|
||||
|
||||
QMetaObject::invokeMethod(
|
||||
qt_text_edit_, [params]() { invoke_method_(params); }, Qt::AutoConnection);
|
||||
|
||||
@@ -21,7 +21,11 @@ template <typename Mutex>
|
||||
class ringbuffer_sink final : public base_sink<Mutex> {
|
||||
public:
|
||||
explicit ringbuffer_sink(size_t n_items)
|
||||
: q_{n_items} {}
|
||||
: q_{n_items} {
|
||||
if (n_items == 0) {
|
||||
throw_spdlog_ex("ringbuffer_sink: n_items cannot be zero");
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<details::log_msg_buffer> last_raw(size_t lim = 0) {
|
||||
std::lock_guard<Mutex> lock(base_sink<Mutex>::mutex_);
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef SPDLOG_HEADER_ONLY
|
||||
#include <spdlog/sinks/rotating_file_sink.h>
|
||||
#include <spdlog/sinks/rotating_file_sink.h>
|
||||
#endif
|
||||
|
||||
#include <spdlog/common.h>
|
||||
|
||||
@@ -89,5 +89,5 @@ std::shared_ptr<logger> rotating_logger_st(const std::string &logger_name,
|
||||
} // namespace spdlog
|
||||
|
||||
#ifdef SPDLOG_HEADER_ONLY
|
||||
#include "rotating_file_sink-inl.h"
|
||||
#include "rotating_file_sink-inl.h"
|
||||
#endif
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef SPDLOG_HEADER_ONLY
|
||||
#include <spdlog/sinks/sink.h>
|
||||
#include <spdlog/sinks/sink.h>
|
||||
#endif
|
||||
|
||||
#include <spdlog/common.h>
|
||||
|
||||
@@ -30,5 +30,5 @@ protected:
|
||||
} // namespace spdlog
|
||||
|
||||
#ifdef SPDLOG_HEADER_ONLY
|
||||
#include "sink-inl.h"
|
||||
#include "sink-inl.h"
|
||||
#endif
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef SPDLOG_HEADER_ONLY
|
||||
#include <spdlog/sinks/stdout_color_sinks.h>
|
||||
#include <spdlog/sinks/stdout_color_sinks.h>
|
||||
#endif
|
||||
|
||||
#include <spdlog/common.h>
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <spdlog/sinks/wincolor_sink.h>
|
||||
#include <spdlog/sinks/wincolor_sink.h>
|
||||
#else
|
||||
#include <spdlog/sinks/ansicolor_sink.h>
|
||||
#include <spdlog/sinks/ansicolor_sink.h>
|
||||
#endif
|
||||
|
||||
#include <spdlog/details/synchronous_factory.h>
|
||||
@@ -45,5 +45,5 @@ std::shared_ptr<logger> stderr_color_st(const std::string &logger_name,
|
||||
} // namespace spdlog
|
||||
|
||||
#ifdef SPDLOG_HEADER_ONLY
|
||||
#include "stdout_color_sinks-inl.h"
|
||||
#include "stdout_color_sinks-inl.h"
|
||||
#endif
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef SPDLOG_HEADER_ONLY
|
||||
#include <spdlog/sinks/stdout_sinks.h>
|
||||
#include <spdlog/sinks/stdout_sinks.h>
|
||||
#endif
|
||||
|
||||
#include <memory>
|
||||
@@ -13,17 +13,17 @@
|
||||
#include <spdlog/details/os.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
// under windows using fwrite to non-binary stream results in \r\r\n (see issue #1675)
|
||||
// so instead we use ::FileWrite
|
||||
#include <spdlog/details/windows_include.h>
|
||||
// under windows using fwrite to non-binary stream results in \r\r\n (see issue #1675)
|
||||
// so instead we use ::FileWrite
|
||||
#include <spdlog/details/windows_include.h>
|
||||
|
||||
#ifndef _USING_V110_SDK71_ // fileapi.h doesn't exist in winxp
|
||||
#include <fileapi.h> // WriteFile (..)
|
||||
#endif
|
||||
#ifndef _USING_V110_SDK71_ // fileapi.h doesn't exist in winxp
|
||||
#include <fileapi.h> // WriteFile (..)
|
||||
#endif
|
||||
|
||||
#include <io.h> // _get_osfhandle(..)
|
||||
#include <stdio.h> // _fileno(..)
|
||||
#endif // _WIN32
|
||||
#include <io.h> // _get_osfhandle(..)
|
||||
#include <stdio.h> // _fileno(..)
|
||||
#endif // _WIN32
|
||||
|
||||
namespace spdlog {
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
#include <spdlog/sinks/sink.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <spdlog/details/windows_include.h>
|
||||
#include <spdlog/details/windows_include.h>
|
||||
#endif
|
||||
|
||||
namespace spdlog {
|
||||
@@ -80,5 +80,5 @@ std::shared_ptr<logger> stderr_logger_st(const std::string &logger_name);
|
||||
} // namespace spdlog
|
||||
|
||||
#ifdef SPDLOG_HEADER_ONLY
|
||||
#include "stdout_sinks-inl.h"
|
||||
#include "stdout_sinks-inl.h"
|
||||
#endif
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
#include <array>
|
||||
#ifndef SD_JOURNAL_SUPPRESS_LOCATION
|
||||
#define SD_JOURNAL_SUPPRESS_LOCATION
|
||||
#define SD_JOURNAL_SUPPRESS_LOCATION
|
||||
#endif
|
||||
#include <systemd/sd-journal.h>
|
||||
|
||||
|
||||
@@ -7,9 +7,9 @@
|
||||
#include <spdlog/details/null_mutex.h>
|
||||
#include <spdlog/sinks/base_sink.h>
|
||||
#ifdef _WIN32
|
||||
#include <spdlog/details/tcp_client-windows.h>
|
||||
#include <spdlog/details/tcp_client-windows.h>
|
||||
#else
|
||||
#include <spdlog/details/tcp_client.h>
|
||||
#include <spdlog/details/tcp_client.h>
|
||||
#endif
|
||||
|
||||
#include <chrono>
|
||||
@@ -31,6 +31,8 @@ namespace sinks {
|
||||
struct tcp_sink_config {
|
||||
std::string server_host;
|
||||
int server_port;
|
||||
int timeout_ms =
|
||||
0; // The timeout for all 3 major socket operations that is connect, send, and recv
|
||||
bool lazy_connect = false; // if true connect on first log call instead of on construction
|
||||
|
||||
tcp_sink_config(std::string host, int port)
|
||||
@@ -44,10 +46,22 @@ public:
|
||||
// connect to tcp host/port or throw if failed
|
||||
// host can be hostname or ip address
|
||||
|
||||
explicit tcp_sink(const std::string &host,
|
||||
int port,
|
||||
int timeout_ms = 0,
|
||||
bool lazy_connect = false)
|
||||
: config_{host, port} {
|
||||
config_.timeout_ms = timeout_ms;
|
||||
config_.lazy_connect = lazy_connect;
|
||||
if (!config_.lazy_connect) {
|
||||
client_.connect(config_.server_host, config_.server_port, config_.timeout_ms);
|
||||
}
|
||||
}
|
||||
|
||||
explicit tcp_sink(tcp_sink_config sink_config)
|
||||
: config_{std::move(sink_config)} {
|
||||
if (!config_.lazy_connect) {
|
||||
this->client_.connect(config_.server_host, config_.server_port);
|
||||
client_.connect(config_.server_host, config_.server_port, config_.timeout_ms);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,7 +72,7 @@ protected:
|
||||
spdlog::memory_buf_t formatted;
|
||||
spdlog::sinks::base_sink<Mutex>::formatter_->format(msg, formatted);
|
||||
if (!client_.is_connected()) {
|
||||
client_.connect(config_.server_host, config_.server_port);
|
||||
client_.connect(config_.server_host, config_.server_port, config_.timeout_ms);
|
||||
}
|
||||
client_.send(formatted.data(), formatted.size());
|
||||
}
|
||||
|
||||
@@ -7,9 +7,9 @@
|
||||
#include <spdlog/details/null_mutex.h>
|
||||
#include <spdlog/sinks/base_sink.h>
|
||||
#ifdef _WIN32
|
||||
#include <spdlog/details/udp_client-windows.h>
|
||||
#include <spdlog/details/udp_client-windows.h>
|
||||
#else
|
||||
#include <spdlog/details/udp_client.h>
|
||||
#include <spdlog/details/udp_client.h>
|
||||
#endif
|
||||
|
||||
#include <chrono>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef SPDLOG_HEADER_ONLY
|
||||
#include <spdlog/sinks/wincolor_sink.h>
|
||||
#include <spdlog/sinks/wincolor_sink.h>
|
||||
#endif
|
||||
|
||||
#include <spdlog/details/windows_include.h>
|
||||
|
||||
@@ -78,5 +78,5 @@ using wincolor_stderr_sink_st = wincolor_stderr_sink<details::console_nullmutex>
|
||||
} // namespace spdlog
|
||||
|
||||
#ifdef SPDLOG_HEADER_ONLY
|
||||
#include "wincolor_sink-inl.h"
|
||||
#include "wincolor_sink-inl.h"
|
||||
#endif
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef SPDLOG_HEADER_ONLY
|
||||
#include <spdlog/spdlog.h>
|
||||
#include <spdlog/spdlog.h>
|
||||
#endif
|
||||
|
||||
#include <spdlog/common.h>
|
||||
|
||||
@@ -289,69 +289,66 @@ inline void critical(const T &msg) {
|
||||
//
|
||||
|
||||
#ifndef SPDLOG_NO_SOURCE_LOC
|
||||
#define SPDLOG_LOGGER_CALL(logger, level, ...) \
|
||||
(logger)->log(spdlog::source_loc{__FILE__, __LINE__, SPDLOG_FUNCTION}, level, __VA_ARGS__)
|
||||
#define SPDLOG_LOGGER_CALL(logger, level, ...) \
|
||||
(logger)->log(spdlog::source_loc{__FILE__, __LINE__, SPDLOG_FUNCTION}, level, __VA_ARGS__)
|
||||
#else
|
||||
#define SPDLOG_LOGGER_CALL(logger, level, ...) \
|
||||
(logger)->log(spdlog::source_loc{}, level, __VA_ARGS__)
|
||||
#define SPDLOG_LOGGER_CALL(logger, level, ...) \
|
||||
(logger)->log(spdlog::source_loc{}, level, __VA_ARGS__)
|
||||
#endif
|
||||
|
||||
#if SPDLOG_ACTIVE_LEVEL <= SPDLOG_LEVEL_TRACE
|
||||
#define SPDLOG_LOGGER_TRACE(logger, ...) \
|
||||
SPDLOG_LOGGER_CALL(logger, spdlog::level::trace, __VA_ARGS__)
|
||||
#define SPDLOG_TRACE(...) SPDLOG_LOGGER_TRACE(spdlog::default_logger_raw(), __VA_ARGS__)
|
||||
#define SPDLOG_LOGGER_TRACE(logger, ...) \
|
||||
SPDLOG_LOGGER_CALL(logger, spdlog::level::trace, __VA_ARGS__)
|
||||
#define SPDLOG_TRACE(...) SPDLOG_LOGGER_TRACE(spdlog::default_logger_raw(), __VA_ARGS__)
|
||||
#else
|
||||
#define SPDLOG_LOGGER_TRACE(logger, ...) (void)0
|
||||
#define SPDLOG_TRACE(...) (void)0
|
||||
#define SPDLOG_LOGGER_TRACE(logger, ...) (void)0
|
||||
#define SPDLOG_TRACE(...) (void)0
|
||||
#endif
|
||||
|
||||
#if SPDLOG_ACTIVE_LEVEL <= SPDLOG_LEVEL_DEBUG
|
||||
#define SPDLOG_LOGGER_DEBUG(logger, ...) \
|
||||
SPDLOG_LOGGER_CALL(logger, spdlog::level::debug, __VA_ARGS__)
|
||||
#define SPDLOG_DEBUG(...) SPDLOG_LOGGER_DEBUG(spdlog::default_logger_raw(), __VA_ARGS__)
|
||||
#define SPDLOG_LOGGER_DEBUG(logger, ...) \
|
||||
SPDLOG_LOGGER_CALL(logger, spdlog::level::debug, __VA_ARGS__)
|
||||
#define SPDLOG_DEBUG(...) SPDLOG_LOGGER_DEBUG(spdlog::default_logger_raw(), __VA_ARGS__)
|
||||
#else
|
||||
#define SPDLOG_LOGGER_DEBUG(logger, ...) (void)0
|
||||
#define SPDLOG_DEBUG(...) (void)0
|
||||
#define SPDLOG_LOGGER_DEBUG(logger, ...) (void)0
|
||||
#define SPDLOG_DEBUG(...) (void)0
|
||||
#endif
|
||||
|
||||
#if SPDLOG_ACTIVE_LEVEL <= SPDLOG_LEVEL_INFO
|
||||
#define SPDLOG_LOGGER_INFO(logger, ...) \
|
||||
SPDLOG_LOGGER_CALL(logger, spdlog::level::info, __VA_ARGS__)
|
||||
#define SPDLOG_INFO(...) SPDLOG_LOGGER_INFO(spdlog::default_logger_raw(), __VA_ARGS__)
|
||||
#define SPDLOG_LOGGER_INFO(logger, ...) SPDLOG_LOGGER_CALL(logger, spdlog::level::info, __VA_ARGS__)
|
||||
#define SPDLOG_INFO(...) SPDLOG_LOGGER_INFO(spdlog::default_logger_raw(), __VA_ARGS__)
|
||||
#else
|
||||
#define SPDLOG_LOGGER_INFO(logger, ...) (void)0
|
||||
#define SPDLOG_INFO(...) (void)0
|
||||
#define SPDLOG_LOGGER_INFO(logger, ...) (void)0
|
||||
#define SPDLOG_INFO(...) (void)0
|
||||
#endif
|
||||
|
||||
#if SPDLOG_ACTIVE_LEVEL <= SPDLOG_LEVEL_WARN
|
||||
#define SPDLOG_LOGGER_WARN(logger, ...) \
|
||||
SPDLOG_LOGGER_CALL(logger, spdlog::level::warn, __VA_ARGS__)
|
||||
#define SPDLOG_WARN(...) SPDLOG_LOGGER_WARN(spdlog::default_logger_raw(), __VA_ARGS__)
|
||||
#define SPDLOG_LOGGER_WARN(logger, ...) SPDLOG_LOGGER_CALL(logger, spdlog::level::warn, __VA_ARGS__)
|
||||
#define SPDLOG_WARN(...) SPDLOG_LOGGER_WARN(spdlog::default_logger_raw(), __VA_ARGS__)
|
||||
#else
|
||||
#define SPDLOG_LOGGER_WARN(logger, ...) (void)0
|
||||
#define SPDLOG_WARN(...) (void)0
|
||||
#define SPDLOG_LOGGER_WARN(logger, ...) (void)0
|
||||
#define SPDLOG_WARN(...) (void)0
|
||||
#endif
|
||||
|
||||
#if SPDLOG_ACTIVE_LEVEL <= SPDLOG_LEVEL_ERROR
|
||||
#define SPDLOG_LOGGER_ERROR(logger, ...) \
|
||||
SPDLOG_LOGGER_CALL(logger, spdlog::level::err, __VA_ARGS__)
|
||||
#define SPDLOG_ERROR(...) SPDLOG_LOGGER_ERROR(spdlog::default_logger_raw(), __VA_ARGS__)
|
||||
#define SPDLOG_LOGGER_ERROR(logger, ...) SPDLOG_LOGGER_CALL(logger, spdlog::level::err, __VA_ARGS__)
|
||||
#define SPDLOG_ERROR(...) SPDLOG_LOGGER_ERROR(spdlog::default_logger_raw(), __VA_ARGS__)
|
||||
#else
|
||||
#define SPDLOG_LOGGER_ERROR(logger, ...) (void)0
|
||||
#define SPDLOG_ERROR(...) (void)0
|
||||
#define SPDLOG_LOGGER_ERROR(logger, ...) (void)0
|
||||
#define SPDLOG_ERROR(...) (void)0
|
||||
#endif
|
||||
|
||||
#if SPDLOG_ACTIVE_LEVEL <= SPDLOG_LEVEL_CRITICAL
|
||||
#define SPDLOG_LOGGER_CRITICAL(logger, ...) \
|
||||
SPDLOG_LOGGER_CALL(logger, spdlog::level::critical, __VA_ARGS__)
|
||||
#define SPDLOG_CRITICAL(...) SPDLOG_LOGGER_CRITICAL(spdlog::default_logger_raw(), __VA_ARGS__)
|
||||
#define SPDLOG_LOGGER_CRITICAL(logger, ...) \
|
||||
SPDLOG_LOGGER_CALL(logger, spdlog::level::critical, __VA_ARGS__)
|
||||
#define SPDLOG_CRITICAL(...) SPDLOG_LOGGER_CRITICAL(spdlog::default_logger_raw(), __VA_ARGS__)
|
||||
#else
|
||||
#define SPDLOG_LOGGER_CRITICAL(logger, ...) (void)0
|
||||
#define SPDLOG_CRITICAL(...) (void)0
|
||||
#define SPDLOG_LOGGER_CRITICAL(logger, ...) (void)0
|
||||
#define SPDLOG_CRITICAL(...) (void)0
|
||||
#endif
|
||||
|
||||
#ifdef SPDLOG_HEADER_ONLY
|
||||
#include "spdlog-inl.h"
|
||||
#include "spdlog-inl.h"
|
||||
#endif
|
||||
|
||||
#endif // SPDLOG_H
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
#pragma once
|
||||
|
||||
#define SPDLOG_VER_MAJOR 1
|
||||
#define SPDLOG_VER_MINOR 15
|
||||
#define SPDLOG_VER_PATCH 3
|
||||
#define SPDLOG_VER_MINOR 16
|
||||
#define SPDLOG_VER_PATCH 0
|
||||
|
||||
#define SPDLOG_TO_VERSION(major, minor, patch) (major * 10000 + minor * 100 + patch)
|
||||
#define SPDLOG_VERSION SPDLOG_TO_VERSION(SPDLOG_VER_MAJOR, SPDLOG_VER_MINOR, SPDLOG_VER_PATCH)
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||
|
||||
#ifndef SPDLOG_COMPILED_LIB
|
||||
#error Please define SPDLOG_COMPILED_LIB to compile this file.
|
||||
#error Please define SPDLOG_COMPILED_LIB to compile this file.
|
||||
#endif
|
||||
|
||||
#include <spdlog/async.h>
|
||||
|
||||
@@ -3,44 +3,43 @@
|
||||
// All rights reserved.
|
||||
|
||||
#ifndef SPDLOG_COMPILED_LIB
|
||||
#error Please define SPDLOG_COMPILED_LIB to compile this file.
|
||||
#error Please define SPDLOG_COMPILED_LIB to compile this file.
|
||||
#endif
|
||||
|
||||
#if !defined(SPDLOG_FMT_EXTERNAL) && !defined(SPDLOG_USE_STD_FORMAT)
|
||||
|
||||
#include <spdlog/fmt/bundled/format-inl.h>
|
||||
#include <spdlog/fmt/bundled/format-inl.h>
|
||||
|
||||
FMT_BEGIN_NAMESPACE
|
||||
|
||||
#if FMT_USE_LOCALE
|
||||
template FMT_API locale_ref::locale_ref(const std::locale& loc); // DEPRECATED!
|
||||
template FMT_API auto locale_ref::get<std::locale>() const -> std::locale;
|
||||
#endif
|
||||
|
||||
namespace detail {
|
||||
|
||||
template FMT_API auto dragonbox::to_decimal(float x) noexcept -> dragonbox::decimal_fp<float>;
|
||||
template FMT_API auto dragonbox::to_decimal(double x) noexcept -> dragonbox::decimal_fp<double>;
|
||||
|
||||
#if FMT_USE_LOCALE
|
||||
// DEPRECATED! locale_ref in the detail namespace
|
||||
template FMT_API locale_ref::locale_ref(const std::locale& loc);
|
||||
template FMT_API auto locale_ref::get<std::locale>() const -> std::locale;
|
||||
#endif
|
||||
template FMT_API auto dragonbox::to_decimal(float x) noexcept
|
||||
-> dragonbox::decimal_fp<float>;
|
||||
template FMT_API auto dragonbox::to_decimal(double x) noexcept
|
||||
-> dragonbox::decimal_fp<double>;
|
||||
|
||||
// Explicit instantiations for char.
|
||||
|
||||
template FMT_API auto thousands_sep_impl(locale_ref) -> thousands_sep_result<char>;
|
||||
template FMT_API auto thousands_sep_impl(locale_ref)
|
||||
-> thousands_sep_result<char>;
|
||||
template FMT_API auto decimal_point_impl(locale_ref) -> char;
|
||||
|
||||
// DEPRECATED!
|
||||
template FMT_API void buffer<char>::append(const char*, const char*);
|
||||
|
||||
// DEPRECATED!
|
||||
template FMT_API void vformat_to(buffer<char>&,
|
||||
string_view,
|
||||
typename vformat_args<>::type,
|
||||
locale_ref);
|
||||
|
||||
// Explicit instantiations for wchar_t.
|
||||
|
||||
template FMT_API auto thousands_sep_impl(locale_ref) -> thousands_sep_result<wchar_t>;
|
||||
template FMT_API auto thousands_sep_impl(locale_ref)
|
||||
-> thousands_sep_result<wchar_t>;
|
||||
template FMT_API auto decimal_point_impl(locale_ref) -> wchar_t;
|
||||
|
||||
// DEPRECATED!
|
||||
template FMT_API void buffer<wchar_t>::append(const wchar_t*, const wchar_t*);
|
||||
|
||||
} // namespace detail
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||
|
||||
#ifndef SPDLOG_COMPILED_LIB
|
||||
#error Please define SPDLOG_COMPILED_LIB to compile this file.
|
||||
#error Please define SPDLOG_COMPILED_LIB to compile this file.
|
||||
#endif
|
||||
|
||||
#include <spdlog/cfg/helpers-inl.h>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||
|
||||
#ifndef SPDLOG_COMPILED_LIB
|
||||
#error Please define SPDLOG_COMPILED_LIB to compile this file.
|
||||
#error Please define SPDLOG_COMPILED_LIB to compile this file.
|
||||
#endif
|
||||
|
||||
#include <mutex>
|
||||
@@ -13,7 +13,7 @@
|
||||
// color sinks
|
||||
//
|
||||
#ifdef _WIN32
|
||||
#include <spdlog/sinks/wincolor_sink-inl.h>
|
||||
#include <spdlog/sinks/wincolor_sink-inl.h>
|
||||
template class SPDLOG_API spdlog::sinks::wincolor_sink<spdlog::details::console_mutex>;
|
||||
template class SPDLOG_API spdlog::sinks::wincolor_sink<spdlog::details::console_nullmutex>;
|
||||
template class SPDLOG_API spdlog::sinks::wincolor_stdout_sink<spdlog::details::console_mutex>;
|
||||
@@ -21,7 +21,7 @@ template class SPDLOG_API spdlog::sinks::wincolor_stdout_sink<spdlog::details::c
|
||||
template class SPDLOG_API spdlog::sinks::wincolor_stderr_sink<spdlog::details::console_mutex>;
|
||||
template class SPDLOG_API spdlog::sinks::wincolor_stderr_sink<spdlog::details::console_nullmutex>;
|
||||
#else
|
||||
#include "spdlog/sinks/ansicolor_sink-inl.h"
|
||||
#include "spdlog/sinks/ansicolor_sink-inl.h"
|
||||
template class SPDLOG_API spdlog::sinks::ansicolor_sink<spdlog::details::console_mutex>;
|
||||
template class SPDLOG_API spdlog::sinks::ansicolor_sink<spdlog::details::console_nullmutex>;
|
||||
template class SPDLOG_API spdlog::sinks::ansicolor_stdout_sink<spdlog::details::console_mutex>;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||
|
||||
#ifndef SPDLOG_COMPILED_LIB
|
||||
#error Please define SPDLOG_COMPILED_LIB to compile this file.
|
||||
#error Please define SPDLOG_COMPILED_LIB to compile this file.
|
||||
#endif
|
||||
|
||||
#include <spdlog/details/file_helper-inl.h>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||
|
||||
#ifndef SPDLOG_COMPILED_LIB
|
||||
#error Please define SPDLOG_COMPILED_LIB to compile this file.
|
||||
#error Please define SPDLOG_COMPILED_LIB to compile this file.
|
||||
#endif
|
||||
|
||||
#include <spdlog/common-inl.h>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||
|
||||
#ifndef SPDLOG_COMPILED_LIB
|
||||
#error Please define SPDLOG_COMPILED_LIB to compile this file.
|
||||
#error Please define SPDLOG_COMPILED_LIB to compile this file.
|
||||
#endif
|
||||
|
||||
#include <mutex>
|
||||
|
||||
@@ -49,7 +49,8 @@ set(SPDLOG_UTESTS_SOURCES
|
||||
test_time_point.cpp
|
||||
test_stopwatch.cpp
|
||||
test_circular_q.cpp
|
||||
test_bin_to_hex.cpp)
|
||||
test_bin_to_hex.cpp
|
||||
test_ringbuffer.cpp)
|
||||
|
||||
if(NOT SPDLOG_NO_EXCEPTIONS)
|
||||
list(APPEND SPDLOG_UTESTS_SOURCES test_errors.cpp)
|
||||
@@ -74,7 +75,7 @@ function(spdlog_prepare_test test_target spdlog_lib)
|
||||
elseif(SPDLOG_SANITIZE_THREAD)
|
||||
spdlog_enable_thread_sanitizer(${test_target})
|
||||
endif()
|
||||
add_test(NAME ${test_target} COMMAND ${test_target})
|
||||
add_test(NAME ${test_target} COMMAND ${test_target} --order decl)
|
||||
set_tests_properties(${test_target} PROPERTIES RUN_SERIAL ON)
|
||||
endfunction()
|
||||
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#if defined(__GNUC__) && __GNUC__ == 12
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wmaybe-uninitialized" // Workaround for GCC 12
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wmaybe-uninitialized" // Workaround for GCC 12
|
||||
#endif
|
||||
#include <catch2/catch_all.hpp>
|
||||
#if defined(__GNUC__) && __GNUC__ == 12
|
||||
#pragma GCC diagnostic pop
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
#include "utils.h"
|
||||
@@ -23,13 +23,16 @@
|
||||
|
||||
#define SPDLOG_ACTIVE_LEVEL SPDLOG_LEVEL_DEBUG
|
||||
|
||||
#undef SPDLOG_LEVEL_NAMES
|
||||
#undef SPDLOG_SHORT_LEVEL_NAMES
|
||||
|
||||
#include "spdlog/spdlog.h"
|
||||
#include "spdlog/async.h"
|
||||
#include "spdlog/details/fmt_helper.h"
|
||||
#include "spdlog/details/os.h"
|
||||
|
||||
#ifndef SPDLOG_NO_TLS
|
||||
#include "spdlog/mdc.h"
|
||||
#include "spdlog/mdc.h"
|
||||
#endif
|
||||
|
||||
#include "spdlog/sinks/basic_file_sink.h"
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
#if defined(__GNUC__) && __GNUC__ == 12
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wmaybe-uninitialized" // Workaround for GCC 12
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wmaybe-uninitialized" // Workaround for GCC 12
|
||||
#endif
|
||||
|
||||
#include <catch2/catch_all.hpp>
|
||||
|
||||
#if defined(__GNUC__) && __GNUC__ == 12
|
||||
#pragma GCC diagnostic pop
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
@@ -84,11 +84,11 @@ TEST_CASE("dir_name", "[create_dir]") {
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
//
|
||||
// test windows cases when drive letter is given e.g. C:\\some-folder
|
||||
//
|
||||
#include <windows.h>
|
||||
#include <fileapi.h>
|
||||
//
|
||||
// test windows cases when drive letter is given e.g. C:\\some-folder
|
||||
//
|
||||
#include <windows.h>
|
||||
#include <fileapi.h>
|
||||
|
||||
std::string get_full_path(const std::string &relative_folder_path) {
|
||||
char full_path[MAX_PATH];
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user