Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/gabime/spdlog.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCharless Milette <charles.milette@gmail.com>2021-11-13 19:29:05 +0300
committerCharless Milette <charles.milette@gmail.com>2021-11-13 19:29:05 +0300
commit44a4517e2b1189bde950b86cbf6c2c5943a5a55a (patch)
tree04cadb34e8aaa2fc84db53cd2d2e118e4350863e
parentff9313e6ddccb85dae33df024a5378d5e8377b9b (diff)
Support C++20 std::format as an alternative to fmtlib
-rw-r--r--CMakeLists.txt15
-rw-r--r--appveyor.yml19
-rw-r--r--bench/async_bench.cpp4
-rw-r--r--bench/bench.cpp14
-rw-r--r--include/spdlog/common-inl.h4
-rw-r--r--include/spdlog/common.h48
-rw-r--r--include/spdlog/details/fmt_helper.h54
-rw-r--r--include/spdlog/details/os-inl.h16
-rw-r--r--include/spdlog/details/tcp_client-windows.h4
-rw-r--r--include/spdlog/details/tcp_client.h3
-rw-r--r--include/spdlog/details/udp_client-windows.h4
-rw-r--r--include/spdlog/fmt/bin_to_hex.h12
-rw-r--r--include/spdlog/fmt/chrono.h16
-rw-r--r--include/spdlog/fmt/compile.h18
-rw-r--r--include/spdlog/fmt/fmt.h4
-rw-r--r--include/spdlog/fmt/ostr.h16
-rw-r--r--include/spdlog/fmt/xchar.h18
-rw-r--r--include/spdlog/logger.h97
-rw-r--r--include/spdlog/sinks/daily_file_sink.h8
-rw-r--r--include/spdlog/sinks/hourly_file_sink.h2
-rw-r--r--include/spdlog/sinks/msvc_sink.h4
-rw-r--r--include/spdlog/sinks/ringbuffer_sink.h4
-rw-r--r--include/spdlog/sinks/rotating_file_sink-inl.h2
-rw-r--r--include/spdlog/sinks/win_eventlog_sink.h33
-rw-r--r--include/spdlog/spdlog.h32
-rw-r--r--include/spdlog/tweakme.h7
-rw-r--r--src/fmt.cpp2
-rw-r--r--tests/test_async.cpp2
-rw-r--r--tests/test_daily_logger.cpp30
-rw-r--r--tests/test_errors.cpp2
-rw-r--r--tests/test_file_helper.cpp2
-rw-r--r--tests/test_fmt_helper.cpp20
-rw-r--r--tests/test_macros.cpp4
-rw-r--r--tests/test_pattern_formatter.cpp62
34 files changed, 442 insertions, 140 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 58e76f52..2d9bc279 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -80,6 +80,7 @@ option(SPDLOG_BUILD_WARNINGS "Enable compiler warnings" OFF)
# install options
option(SPDLOG_INSTALL "Generate the install target" ${SPDLOG_MASTER_PROJECT})
+option(SPDLOG_USE_STD_FORMAT "Use std::format instead of fmt library. No compile-time format string checking." OFF)
option(SPDLOG_FMT_EXTERNAL "Use external fmt library instead of bundled" OFF)
option(SPDLOG_FMT_EXTERNAL_HO "Use external fmt header-only library instead of bundled" OFF)
option(SPDLOG_NO_EXCEPTIONS "Compile with -fno-exceptions. Call abort() on any spdlog exceptions" OFF)
@@ -88,6 +89,14 @@ if(SPDLOG_FMT_EXTERNAL AND SPDLOG_FMT_EXTERNAL_HO)
message(FATAL_ERROR "SPDLOG_FMT_EXTERNAL and SPDLOG_FMT_EXTERNAL_HO are mutually exclusive")
endif()
+if(SPDLOG_USE_STD_FORMAT AND SPDLOG_FMT_EXTERNAL_HO)
+ message(FATAL_ERROR "SPDLOG_USE_STD_FORMAT and SPDLOG_FMT_EXTERNAL_HO are mutually exclusive")
+endif()
+
+if(SPDLOG_USE_STD_FORMAT AND SPDLOG_FMT_EXTERNAL)
+ message(FATAL_ERROR "SPDLOG_USE_STD_FORMAT and SPDLOG_FMT_EXTERNAL are mutually exclusive")
+endif()
+
# misc tweakme options
if(WIN32)
option(SPDLOG_WCHAR_SUPPORT "Support wchar api" OFF)
@@ -130,7 +139,7 @@ message(STATUS "Build type: " ${CMAKE_BUILD_TYPE})
# ---------------------------------------------------------------------------------------
set(SPDLOG_SRCS src/spdlog.cpp src/stdout_sinks.cpp src/color_sinks.cpp src/file_sinks.cpp src/async.cpp src/cfg.cpp)
-if(NOT SPDLOG_FMT_EXTERNAL AND NOT SPDLOG_FMT_EXTERNAL_HO)
+if(NOT SPDLOG_USE_STD_FORMAT AND NOT SPDLOG_FMT_EXTERNAL AND NOT SPDLOG_FMT_EXTERNAL_HO)
list(APPEND SPDLOG_SRCS src/fmt.cpp)
endif()
@@ -145,7 +154,7 @@ if(SPDLOG_BUILD_SHARED OR BUILD_SHARED_LIBS)
target_compile_options(spdlog PUBLIC $<$<AND:$<CXX_COMPILER_ID:MSVC>,$<NOT:$<COMPILE_LANGUAGE:CUDA>>>:/wd4251
/wd4275>)
endif()
- if(NOT SPDLOG_FMT_EXTERNAL AND NOT SPDLOG_FMT_EXTERNAL_HO)
+ if(NOT SPDLOG_USE_STD_FORMAT AND NOT SPDLOG_FMT_EXTERNAL AND NOT SPDLOG_FMT_EXTERNAL_HO)
target_compile_definitions(spdlog PRIVATE FMT_EXPORT PUBLIC FMT_SHARED)
endif()
else()
@@ -280,7 +289,7 @@ if(SPDLOG_INSTALL)
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
- if(NOT SPDLOG_FMT_EXTERNAL AND NOT SPDLOG_FMT_EXTERNAL_HO)
+ if(NOT SPDLOG_USE_STD_FORMAT AND NOT SPDLOG_FMT_EXTERNAL AND NOT SPDLOG_FMT_EXTERNAL_HO)
install(DIRECTORY include/${PROJECT_NAME}/fmt/bundled/
DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME}/fmt/bundled/")
endif()
diff --git a/appveyor.yml b/appveyor.yml
index b4574034..42d928e3 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -8,55 +8,72 @@ environment:
WCHAR: 'OFF'
WCHAR_FILES: 'OFF'
BUILD_EXAMPLE: 'ON'
+ USE_STD_FORMAT: 'OFF'
- GENERATOR: '"Visual Studio 14 2015"'
BUILD_TYPE: Release
BUILD_SHARED: 'OFF'
WCHAR: 'ON'
WCHAR_FILES: 'OFF'
BUILD_EXAMPLE: 'ON'
+ USE_STD_FORMAT: 'OFF'
- GENERATOR: '"Visual Studio 14 2015 Win64"'
BUILD_TYPE: Debug
BUILD_SHARED: 'OFF'
WCHAR: 'ON'
WCHAR_FILES: 'OFF'
BUILD_EXAMPLE: 'ON'
+ USE_STD_FORMAT: 'OFF'
- GENERATOR: '"Visual Studio 14 2015 Win64"'
BUILD_TYPE: Release
BUILD_SHARED: 'OFF'
WCHAR: 'ON'
WCHAR_FILES: 'OFF'
BUILD_EXAMPLE: 'ON'
+ USE_STD_FORMAT: 'OFF'
- GENERATOR: '"Visual Studio 15 2017 Win64"'
BUILD_TYPE: Debug
BUILD_SHARED: 'OFF'
WCHAR: 'ON'
WCHAR_FILES: 'OFF'
BUILD_EXAMPLE: 'ON'
+ USE_STD_FORMAT: 'OFF'
- GENERATOR: '"Visual Studio 15 2017 Win64"'
BUILD_TYPE: Release
BUILD_SHARED: 'OFF'
WCHAR: 'OFF'
WCHAR_FILES: 'OFF'
BUILD_EXAMPLE: 'ON'
+ USE_STD_FORMAT: 'OFF'
- GENERATOR: '"Visual Studio 15 2017 Win64"'
BUILD_TYPE: Release
BUILD_SHARED: 'ON'
WCHAR: 'OFF'
WCHAR_FILES: 'OFF'
BUILD_EXAMPLE: 'ON'
+ USE_STD_FORMAT: 'OFF'
- GENERATOR: '"Visual Studio 15 2017 Win64"'
BUILD_TYPE: Release
BUILD_SHARED: 'ON'
WCHAR: 'ON'
WCHAR_FILES: 'ON'
BUILD_EXAMPLE: 'OFF'
+ USE_STD_FORMAT: 'OFF'
- GENERATOR: '"Visual Studio 16 2019" -A x64'
BUILD_TYPE: Release
BUILD_SHARED: 'ON'
WCHAR: 'OFF'
WCHAR_FILES: 'OFF'
BUILD_EXAMPLE: 'OFF'
+ USE_STD_FORMAT: 'OFF'
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
+ - GENERATOR: '"Visual Studio 16 2022" -A x64'
+ BUILD_TYPE: Release
+ BUILD_SHARED: 'ON'
+ WCHAR: 'OFF'
+ WCHAR_FILES: 'OFF'
+ BUILD_EXAMPLE: 'OFF'
+ USE_STD_FORMAT: 'ON'
+ APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2022
build_script:
- cmd: >-
set
@@ -67,7 +84,7 @@ build_script:
set PATH=%PATH%;C:\Program Files\Git\usr\bin
- cmake -G %GENERATOR% -D CMAKE_BUILD_TYPE=%BUILD_TYPE% -D BUILD_SHARED_LIBS=%BUILD_SHARED% -D SPDLOG_WCHAR_SUPPORT=%WCHAR% -D SPDLOG_WCHAR_FILENAMES=%WCHAR_FILES% -D SPDLOG_BUILD_EXAMPLE=%BUILD_EXAMPLE% -D SPDLOG_BUILD_EXAMPLE_HO=%BUILD_EXAMPLE% -D SPDLOG_BUILD_TESTS=ON -D SPDLOG_BUILD_TESTS_HO=OFF -D SPDLOG_BUILD_WARNINGS=ON ..
+ cmake -G %GENERATOR% -D CMAKE_BUILD_TYPE=%BUILD_TYPE% -D BUILD_SHARED_LIBS=%BUILD_SHARED% -D SPDLOG_WCHAR_SUPPORT=%WCHAR% -D SPDLOG_WCHAR_FILENAMES=%WCHAR_FILES% -D SPDLOG_BUILD_EXAMPLE=%BUILD_EXAMPLE% -D SPDLOG_BUILD_EXAMPLE_HO=%BUILD_EXAMPLE% -D SPDLOG_BUILD_TESTS=ON -D SPDLOG_BUILD_TESTS_HO=OFF -D SPDLOG_BUILD_WARNINGS=ON -D SPDLOG_USE_STD_FORMAT=%USE_STD_FORMAT% ..
cmake --build . --config %BUILD_TYPE%
diff --git a/bench/async_bench.cpp b/bench/async_bench.cpp
index 99d8ecb2..ce2c9281 100644
--- a/bench/async_bench.cpp
+++ b/bench/async_bench.cpp
@@ -10,7 +10,9 @@
#include "spdlog/async.h"
#include "spdlog/sinks/basic_file_sink.h"
-#ifdef SPDLOG_FMT_EXTERNAL
+#if defined(SPDLOG_USE_STD_FORMAT)
+# include <format>
+#elif defined(SPDLOG_FMT_EXTERNAL)
# include <fmt/format.h>
#else
# include "spdlog/fmt/bundled/format.h"
diff --git a/bench/bench.cpp b/bench/bench.cpp
index 5a4fc39b..af08c7ac 100644
--- a/bench/bench.cpp
+++ b/bench/bench.cpp
@@ -12,7 +12,9 @@
#include "spdlog/sinks/null_sink.h"
#include "spdlog/sinks/rotating_file_sink.h"
-#ifdef SPDLOG_FMT_EXTERNAL
+#if defined(SPDLOG_USE_STD_FORMAT)
+# include <format>
+#elif defined(SPDLOG_FMT_EXTERNAL)
# include <fmt/locale.h>
#else
# include "spdlog/fmt/bundled/format.h"
@@ -38,7 +40,7 @@ static const int max_threads = 1000;
void bench_threaded_logging(size_t threads, int iters)
{
spdlog::info("**************************************************************");
- spdlog::info(fmt::format(std::locale("en_US.UTF-8"), "Multi threaded: {:L} threads, {:L} messages", threads, iters));
+ spdlog::info(spdlog::fmt_lib::format(std::locale("en_US.UTF-8"), "Multi threaded: {:L} threads, {:L} messages", threads, iters));
spdlog::info("**************************************************************");
auto basic_mt = spdlog::basic_logger_mt("basic_mt", "logs/basic_mt.log", true);
@@ -74,7 +76,7 @@ void bench_threaded_logging(size_t threads, int iters)
void bench_single_threaded(int iters)
{
spdlog::info("**************************************************************");
- spdlog::info(fmt::format(std::locale("en_US.UTF-8"), "Single threaded: {} messages", iters));
+ spdlog::info(spdlog::fmt_lib::format(std::locale("en_US.UTF-8"), "Single threaded: {} messages", iters));
spdlog::info("**************************************************************");
auto basic_st = spdlog::basic_logger_st("basic_st", "logs/basic_st.log", true);
@@ -128,7 +130,7 @@ int main(int argc, char *argv[])
if (threads > max_threads)
{
- throw std::runtime_error(fmt::format("Number of threads exceeds maximum({})", max_threads));
+ throw std::runtime_error(spdlog::fmt_lib::format("Number of threads exceeds maximum({})", max_threads));
}
bench_single_threaded(iters);
@@ -159,7 +161,7 @@ void bench(int howmany, std::shared_ptr<spdlog::logger> log)
auto delta_d = duration_cast<duration<double>>(delta).count();
spdlog::info(
- fmt::format(std::locale("en_US.UTF-8"), "{:<30} Elapsed: {:0.2f} secs {:>16L}/sec", log->name(), delta_d, int(howmany / delta_d)));
+ spdlog::fmt_lib::format(std::locale("en_US.UTF-8"), "{:<30} Elapsed: {:0.2f} secs {:>16L}/sec", log->name(), delta_d, int(howmany / delta_d)));
spdlog::drop(log->name());
}
@@ -190,7 +192,7 @@ void bench_mt(int howmany, std::shared_ptr<spdlog::logger> log, size_t thread_co
auto delta = high_resolution_clock::now() - start;
auto delta_d = duration_cast<duration<double>>(delta).count();
spdlog::info(
- fmt::format(std::locale("en_US.UTF-8"), "{:<30} Elapsed: {:0.2f} secs {:>16L}/sec", log->name(), delta_d, int(howmany / delta_d)));
+ spdlog::fmt_lib::format(std::locale("en_US.UTF-8"), "{:<30} Elapsed: {:0.2f} secs {:>16L}/sec", log->name(), delta_d, int(howmany / delta_d)));
spdlog::drop(log->name());
}
diff --git a/include/spdlog/common-inl.h b/include/spdlog/common-inl.h
index 97cbbddc..9fd2bcb5 100644
--- a/include/spdlog/common-inl.h
+++ b/include/spdlog/common-inl.h
@@ -55,9 +55,13 @@ SPDLOG_INLINE spdlog_ex::spdlog_ex(std::string msg)
SPDLOG_INLINE spdlog_ex::spdlog_ex(const std::string &msg, int last_errno)
{
+#ifdef SPDLOG_USE_STD_FORMAT
+ msg_ = std::system_error(std::error_code(last_errno, std::generic_category()), msg).what();
+#else
memory_buf_t outbuf;
fmt::format_system_error(outbuf, last_errno, msg.c_str());
msg_ = fmt::to_string(outbuf);
+#endif
}
SPDLOG_INLINE const char *spdlog_ex::what() const SPDLOG_NOEXCEPT
diff --git a/include/spdlog/common.h b/include/spdlog/common.h
index ddaa34ce..fb45d2a2 100644
--- a/include/spdlog/common.h
+++ b/include/spdlog/common.h
@@ -16,6 +16,10 @@
#include <functional>
#include <cstdio>
+#ifdef SPDLOG_USE_STD_FORMAT
+#include <string_view>
+#endif
+
#ifdef SPDLOG_COMPILED_LIB
# undef SPDLOG_HEADER_ONLY
# if defined(_WIN32) && defined(SPDLOG_SHARED_LIB)
@@ -36,14 +40,15 @@
#include <spdlog/fmt/fmt.h>
-// backward compatibility with fmt versions older than 8
-#if FMT_VERSION >= 80000
-# define SPDLOG_FMT_RUNTIME(format_string) fmt::runtime(format_string)
-# if defined(SPDLOG_WCHAR_FILENAMES) || defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT)
-# include <spdlog/fmt/xchar.h>
+#ifndef SPDLOG_USE_STD_FORMAT
+# if FMT_VERSION >= 80000 // backward compatibility with fmt versions older than 8
+# define SPDLOG_FMT_RUNTIME(format_string) fmt::runtime(format_string)
+# if defined(SPDLOG_WCHAR_FILENAMES) || defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT)
+# include <spdlog/fmt/xchar.h>
+# endif
+# else
+# define SPDLOG_FMT_RUNTIME(format_string) format_string
# endif
-#else
-# define SPDLOG_FMT_RUNTIME(format_string) format_string
#endif
// visual studio upto 2013 does not support noexcept nor constexpr
@@ -112,11 +117,39 @@ using log_clock = std::chrono::system_clock;
using sink_ptr = std::shared_ptr<sinks::sink>;
using sinks_init_list = std::initializer_list<sink_ptr>;
using err_handler = std::function<void(const std::string &err_msg)>;
+#ifdef SPDLOG_USE_STD_FORMAT
+namespace fmt_lib = std;
+
+using string_view_t = std::string_view;
+using wstring_view_t = std::wstring_view;
+using memory_buf_t = std::string;
+using wmemory_buf_t = std::wstring;
+
+template<typename... Args>
+using format_string_t = std::string_view;
+
+template<typename... Args>
+using wformat_string_t = std::wstring_view;
+
+template<class T, class Char = char>
+struct is_convertible_to_basic_format_string
+ : std::integral_constant<bool,
+ std::is_convertible<T, std::basic_string_view<Char>>::value>
+{};
+#else
+namespace fmt_lib = fmt;
+
using string_view_t = fmt::basic_string_view<char>;
using wstring_view_t = fmt::basic_string_view<wchar_t>;
using memory_buf_t = fmt::basic_memory_buffer<char, 250>;
using wmemory_buf_t = fmt::basic_memory_buffer<wchar_t, 250>;
+template<typename... Args>
+using format_string_t = fmt::format_string<Args...>;
+
+template<typename... Args>
+using wformat_string_t = fmt::wformat_string<Args...>;
+
template<class T>
using remove_cvref_t = typename std::remove_cv<typename std::remove_reference<T>::type>::type;
@@ -127,6 +160,7 @@ struct is_convertible_to_basic_format_string
: std::integral_constant<bool,
std::is_convertible<T, fmt::basic_string_view<Char>>::value || std::is_same<remove_cvref_t<T>, fmt::basic_runtime<Char>>::value>
{};
+#endif
#ifdef SPDLOG_WCHAR_TO_UTF8_SUPPORT
# ifndef _WIN32
diff --git a/include/spdlog/details/fmt_helper.h b/include/spdlog/details/fmt_helper.h
index 01b2aa4d..31ed64fd 100644
--- a/include/spdlog/details/fmt_helper.h
+++ b/include/spdlog/details/fmt_helper.h
@@ -8,6 +8,11 @@
#include <spdlog/fmt/fmt.h>
#include <spdlog/common.h>
+#ifdef SPDLOG_USE_STD_FORMAT
+#include <charconv>
+#include <limits>
+#endif
+
// Some fmt helpers to efficiently format and pad ints and strings
namespace spdlog {
namespace details {
@@ -24,17 +29,63 @@ inline void append_string_view(spdlog::string_view_t view, memory_buf_t &dest)
dest.append(buf_ptr, buf_ptr + view.size());
}
+#ifdef SPDLOG_USE_STD_FORMAT
+template<typename T>
+inline void append_int(T n, memory_buf_t &dest)
+{
+ // Buffer should be large enough to hold all digits (digits10 + 1) and a sign
+ SPDLOG_CONSTEXPR auto BUF_SIZE = std::numeric_limits<T>::digits10 + 2;
+ char buf[BUF_SIZE];
+
+ auto [ptr, ec] = std::to_chars(buf, buf + BUF_SIZE, n, 10);
+ if (ec == std::errc())
+ {
+ dest.append(buf, ptr);
+ }
+ else
+ {
+ throw_spdlog_ex("Failed to format int", static_cast<int>(ec));
+ }
+}
+#else
template<typename T>
inline void append_int(T n, memory_buf_t &dest)
{
fmt::format_int i(n);
dest.append(i.data(), i.data() + i.size());
}
+#endif
+
+template<typename T>
+SPDLOG_CONSTEXPR unsigned int count_digits_fallback(T n)
+{
+ // taken from fmt.
+ unsigned int count = 1;
+ for (;;)
+ {
+ // Integer division is slow so do it for a group of four digits instead
+ // of for every digit. The idea comes from the talk by Alexandrescu
+ // "Three Optimization Tips for C++". See speed-test for a comparison.
+ if (n < 10)
+ return count;
+ if (n < 100)
+ return count + 1;
+ if (n < 1000)
+ return count + 2;
+ if (n < 10000)
+ return count + 3;
+ n /= 10000u;
+ count += 4;
+ }
+}
template<typename T>
inline unsigned int count_digits(T n)
{
using count_type = typename std::conditional<(sizeof(T) > sizeof(uint32_t)), uint64_t, uint32_t>::type;
+#ifdef SPDLOG_USE_STD_FORMAT
+ return count_digits_fallback(static_cast<count_type>(n));
+#else
return static_cast<unsigned int>(fmt::
// fmt 7.0.0 renamed the internal namespace to detail.
// See: https://github.com/fmtlib/fmt/issues/1538
@@ -44,6 +95,7 @@ inline unsigned int count_digits(T n)
detail
#endif
::count_digits(static_cast<count_type>(n)));
+#endif
}
inline void pad2(int n, memory_buf_t &dest)
@@ -55,7 +107,7 @@ inline void pad2(int n, memory_buf_t &dest)
}
else // unlikely, but just in case, let fmt deal with it
{
- fmt::format_to(std::back_inserter(dest), SPDLOG_FMT_RUNTIME("{:02}"), n);
+ fmt_lib::format_to(std::back_inserter(dest), "{:02}", n);
}
}
diff --git a/include/spdlog/details/os-inl.h b/include/spdlog/details/os-inl.h
index 4602782c..9b2ef0d8 100644
--- a/include/spdlog/details/os-inl.h
+++ b/include/spdlog/details/os-inl.h
@@ -381,7 +381,11 @@ SPDLOG_INLINE std::string filename_to_str(const filename_t &filename)
{
memory_buf_t buf;
wstr_to_utf8buf(filename, buf);
+#ifdef SPDLOG_USE_STD_FORMAT
+ return buf;
+#else
return fmt::to_string(buf);
+#endif
}
#else
SPDLOG_INLINE std::string filename_to_str(const filename_t &filename)
@@ -458,8 +462,12 @@ SPDLOG_INLINE void wstr_to_utf8buf(wstring_view_t wstr, memory_buf_t &target)
return;
}
+#ifdef SPDLOG_USE_STD_FORMAT
+ int result_size = 0;
+#else
int result_size = static_cast<int>(target.capacity());
if ((wstr_size + 1) * 2 > result_size)
+#endif
{
result_size = ::WideCharToMultiByte(CP_UTF8, 0, wstr.data(), wstr_size, NULL, 0, NULL, NULL);
}
@@ -476,7 +484,7 @@ SPDLOG_INLINE void wstr_to_utf8buf(wstring_view_t wstr, memory_buf_t &target)
}
}
- throw_spdlog_ex(fmt::format("WideCharToMultiByte failed. Last error: {}", ::GetLastError()));
+ throw_spdlog_ex(fmt_lib::format("WideCharToMultiByte failed. Last error: {}", ::GetLastError()));
}
SPDLOG_INLINE void utf8_to_wstrbuf(string_view_t str, wmemory_buf_t &target)
@@ -493,8 +501,12 @@ SPDLOG_INLINE void utf8_to_wstrbuf(string_view_t str, wmemory_buf_t &target)
return;
}
+#ifdef SPDLOG_USE_STD_FORMAT
+ int result_size = 0;
+#else
int result_size = static_cast<int>(target.capacity());
if (str_size + 1 > result_size)
+#endif
{
result_size = ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, str.data(), str_size, NULL, 0);
}
@@ -511,7 +523,7 @@ SPDLOG_INLINE void utf8_to_wstrbuf(string_view_t str, wmemory_buf_t &target)
}
}
- throw_spdlog_ex(fmt::format("MultiByteToWideChar failed. Last error: {}", ::GetLastError()));
+ throw_spdlog_ex(fmt_lib::format("MultiByteToWideChar failed. Last error: {}", ::GetLastError()));
}
#endif // (defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) || defined(SPDLOG_WCHAR_FILENAMES)) && defined(_WIN32)
diff --git a/include/spdlog/details/tcp_client-windows.h b/include/spdlog/details/tcp_client-windows.h
index 45b69630..b331a500 100644
--- a/include/spdlog/details/tcp_client-windows.h
+++ b/include/spdlog/details/tcp_client-windows.h
@@ -38,10 +38,10 @@ class tcp_client
static void throw_winsock_error_(const std::string &msg, int last_error)
{
char buf[512];
- ::FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, last_error,
+ ::FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, last_error,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), buf, (sizeof(buf) / sizeof(char)), NULL);
- throw_spdlog_ex(fmt::format("tcp_sink - {}: {}", msg, buf));
+ throw_spdlog_ex(fmt_lib::format("tcp_sink - {}: {}", msg, buf));
}
public:
diff --git a/include/spdlog/details/tcp_client.h b/include/spdlog/details/tcp_client.h
index 706d7599..0daff0eb 100644
--- a/include/spdlog/details/tcp_client.h
+++ b/include/spdlog/details/tcp_client.h
@@ -67,8 +67,7 @@ public:
auto rv = ::getaddrinfo(host.c_str(), port_str.c_str(), &hints, &addrinfo_result);
if (rv != 0)
{
- auto msg = fmt::format("::getaddrinfo failed: {}", gai_strerror(rv));
- throw_spdlog_ex(msg);
+ throw_spdlog_ex(fmt_lib::format("::getaddrinfo failed: {}", gai_strerror(rv)));
}
// Try each address until we successfully connect(2).
diff --git a/include/spdlog/details/udp_client-windows.h b/include/spdlog/details/udp_client-windows.h
index 5cc3dd88..372efa6d 100644
--- a/include/spdlog/details/udp_client-windows.h
+++ b/include/spdlog/details/udp_client-windows.h
@@ -40,10 +40,10 @@ class udp_client
static void throw_winsock_error_(const std::string &msg, int last_error)
{
char buf[512];
- ::FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, last_error,
+ ::FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, last_error,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), buf, (sizeof(buf) / sizeof(char)), NULL);
- throw_spdlog_ex(fmt::format("udp_sink - {}: {}", msg, buf));
+ throw_spdlog_ex(fmt_lib::format("udp_sink - {}: {}", msg, buf));
}
void cleanup_()
diff --git a/include/spdlog/fmt/bin_to_hex.h b/include/spdlog/fmt/bin_to_hex.h
index 0b6c3e96..62807d63 100644
--- a/include/spdlog/fmt/bin_to_hex.h
+++ b/include/spdlog/fmt/bin_to_hex.h
@@ -74,12 +74,8 @@ inline details::dump_info<It> to_hex(const It range_begin, const It range_end, s
return details::dump_info<It>(range_begin, range_end, size_per_line);
}
-} // namespace spdlog
-
-namespace fmt {
-
template<typename T>
-struct formatter<spdlog::details::dump_info<T>>
+struct fmt_lib::formatter<spdlog::details::dump_info<T>, char>
{
const char delimiter = ' ';
bool put_newlines = true;
@@ -90,7 +86,7 @@ struct formatter<spdlog::details::dump_info<T>>
// parse the format string flags
template<typename ParseContext>
- FMT_CONSTEXPR auto parse(ParseContext &ctx) -> decltype(ctx.begin())
+ SPDLOG_CONSTEXPR auto parse(ParseContext &ctx) -> decltype(ctx.begin())
{
auto it = ctx.begin();
while (it != ctx.end() && *it != '}')
@@ -210,8 +206,8 @@ struct formatter<spdlog::details::dump_info<T>>
if (put_positions)
{
- fmt::format_to(inserter, "{:04X}: ", pos);
+ fmt_lib::format_to(inserter, "{:04X}: ", pos);
}
}
};
-} // namespace fmt
+} // namespace spdlog
diff --git a/include/spdlog/fmt/chrono.h b/include/spdlog/fmt/chrono.h
index a0544bca..83fad2ff 100644
--- a/include/spdlog/fmt/chrono.h
+++ b/include/spdlog/fmt/chrono.h
@@ -8,13 +8,15 @@
// include bundled or external copy of fmtlib's chrono support
//
-#if !defined(SPDLOG_FMT_EXTERNAL)
-# ifdef SPDLOG_HEADER_ONLY
-# ifndef FMT_HEADER_ONLY
-# define FMT_HEADER_ONLY
+#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
-# include <spdlog/fmt/bundled/chrono.h>
-#else
-# include <fmt/chrono.h>
#endif
diff --git a/include/spdlog/fmt/compile.h b/include/spdlog/fmt/compile.h
index 6f345935..906e9f57 100644
--- a/include/spdlog/fmt/compile.h
+++ b/include/spdlog/fmt/compile.h
@@ -5,16 +5,18 @@
#pragma once
//
-// include bundled or external copy of fmtlib's ostream support
+// include bundled or external copy of fmtlib's compile-time support
//
-#if !defined(SPDLOG_FMT_EXTERNAL)
-# ifdef SPDLOG_HEADER_ONLY
-# ifndef FMT_HEADER_ONLY
-# define FMT_HEADER_ONLY
+#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
-# include <spdlog/fmt/bundled/compile.h>
-#else
-# include <fmt/compile.h>
#endif
diff --git a/include/spdlog/fmt/fmt.h b/include/spdlog/fmt/fmt.h
index 7aaeed81..fa4a2a84 100644
--- a/include/spdlog/fmt/fmt.h
+++ b/include/spdlog/fmt/fmt.h
@@ -10,7 +10,9 @@
// By default spdlog include its own copy.
//
-#if !defined(SPDLOG_FMT_EXTERNAL)
+#if defined(SPDLOG_USE_STD_FORMAT) // SPDLOG_USE_STD_FORMAT is defined - use std::format
+# include <format>
+#elif !defined(SPDLOG_FMT_EXTERNAL)
# if !defined(SPDLOG_COMPILED_LIB) && !defined(FMT_HEADER_ONLY)
# define FMT_HEADER_ONLY
# endif
diff --git a/include/spdlog/fmt/ostr.h b/include/spdlog/fmt/ostr.h
index 9d8efe38..75880341 100644
--- a/include/spdlog/fmt/ostr.h
+++ b/include/spdlog/fmt/ostr.h
@@ -8,13 +8,15 @@
// include bundled or external copy of fmtlib's ostream support
//
-#if !defined(SPDLOG_FMT_EXTERNAL)
-# ifdef SPDLOG_HEADER_ONLY
-# ifndef FMT_HEADER_ONLY
-# define FMT_HEADER_ONLY
+#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
-# include <spdlog/fmt/bundled/ostream.h>
-#else
-# include <fmt/ostream.h>
#endif
diff --git a/include/spdlog/fmt/xchar.h b/include/spdlog/fmt/xchar.h
index 616d8f5b..9a766e5a 100644
--- a/include/spdlog/fmt/xchar.h
+++ b/include/spdlog/fmt/xchar.h
@@ -5,16 +5,18 @@
#pragma once
//
-// include bundled or external copy of fmtlib's ostream support
+// include bundled or external copy of fmtlib's xchar support
//
-#if !defined(SPDLOG_FMT_EXTERNAL)
-# ifdef SPDLOG_HEADER_ONLY
-# ifndef FMT_HEADER_ONLY
-# define FMT_HEADER_ONLY
+#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
-# include <spdlog/fmt/bundled/xchar.h>
-#else
-# include <fmt/xchar.h>
#endif
diff --git a/include/spdlog/logger.h b/include/spdlog/logger.h
index eea0afc2..9adfec97 100644
--- a/include/spdlog/logger.h
+++ b/include/spdlog/logger.h
@@ -33,7 +33,7 @@
{ \
if(location.filename) \
{ \
- err_handler_(fmt::format("{} [{}({})]", ex.what(), location.filename, location.line)); \
+ err_handler_(fmt_lib::format("{} [{}({})]", ex.what(), location.filename, location.line)); \
} \
else \
{ \
@@ -85,13 +85,13 @@ public:
void swap(spdlog::logger &other) SPDLOG_NOEXCEPT;
template<typename... Args>
- void log(source_loc loc, level::level_enum lvl, fmt::format_string<Args...> fmt, Args &&...args)
+ void log(source_loc loc, level::level_enum lvl, format_string_t<Args...> fmt, Args &&...args)
{
log_(loc, lvl, fmt, std::forward<Args>(args)...);
}
template<typename... Args>
- void log(level::level_enum lvl, fmt::format_string<Args...> fmt, Args &&...args)
+ void log(level::level_enum lvl, format_string_t<Args...> fmt, Args &&...args)
{
log(source_loc{}, lvl, fmt, std::forward<Args>(args)...);
}
@@ -102,14 +102,7 @@ public:
log(source_loc{}, lvl, msg);
}
- // T can be statically converted to string_view
- template<class T, typename std::enable_if<std::is_convertible<const T &, spdlog::string_view_t>::value, int>::type = 0>
- void log(source_loc loc, level::level_enum lvl, const T &msg)
- {
- log(loc, lvl, string_view_t{msg});
- }
-
- // T cannot be statically converted to format string (including string_view)
+ // T cannot be statically converted to format string (including string_view/wstring_view)
template<class T, typename std::enable_if<!is_convertible_to_any_format_string<const T &>::value, int>::type = 0>
void log(source_loc loc, level::level_enum lvl, const T &msg)
{
@@ -148,86 +141,121 @@ public:
}
template<typename... Args>
- void trace(fmt::format_string<Args...> fmt, Args &&...args)
+ void trace(format_string_t<Args...> fmt, Args &&...args)
{
log(level::trace, fmt, std::forward<Args>(args)...);
}
template<typename... Args>
- void debug(fmt::format_string<Args...> fmt, Args &&...args)
+ void debug(format_string_t<Args...> fmt, Args &&...args)
{
log(level::debug, fmt, std::forward<Args>(args)...);
}
template<typename... Args>
- void info(fmt::format_string<Args...> fmt, Args &&...args)
+ void info(format_string_t<Args...> fmt, Args &&...args)
{
log(level::info, fmt, std::forward<Args>(args)...);
}
template<typename... Args>
- void warn(fmt::format_string<Args...> fmt, Args &&...args)
+ void warn(format_string_t<Args...> fmt, Args &&...args)
{
log(level::warn, fmt, std::forward<Args>(args)...);
}
template<typename... Args>
- void error(fmt::format_string<Args...> fmt, Args &&...args)
+ void error(format_string_t<Args...> fmt, Args &&...args)
{
log(level::err, fmt, std::forward<Args>(args)...);
}
template<typename... Args>
- void critical(fmt::format_string<Args...> fmt, Args &&...args)
+ void critical(format_string_t<Args...> fmt, Args &&...args)
{
log(level::critical, fmt, std::forward<Args>(args)...);
}
#ifdef SPDLOG_WCHAR_TO_UTF8_SUPPORT
template<typename... Args>
- void log(level::level_enum lvl, fmt::wformat_string<Args...> fmt, Args &&...args)
+ void log(source_loc loc, level::level_enum lvl, wformat_string_t<Args...> fmt, Args &&...args)
{
- log(source_loc{}, lvl, fmt, std::forward<Args>(args)...);
+ log_(loc, lvl, fmt, std::forward<Args>(args)...);
}
template<typename... Args>
- void log(source_loc loc, level::level_enum lvl, fmt::wformat_string<Args...> fmt, Args &&...args)
+ void log(level::level_enum lvl, wformat_string_t<Args...> fmt, Args &&...args)
{
- log_(loc, lvl, fmt, std::forward<Args>(args)...);
+ log(source_loc{}, lvl, fmt, std::forward<Args>(args)...);
+ }
+
+ void log(log_clock::time_point log_time, source_loc loc, level::level_enum lvl, wstring_view_t msg)
+ {
+ bool log_enabled = should_log(lvl);
+ bool traceback_enabled = tracer_.enabled();
+ if (!log_enabled && !traceback_enabled)
+ {
+ return;
+ }
+
+ memory_buf_t buf;
+ details::os::wstr_to_utf8buf(wstring_view_t(msg.data(), msg.size()), buf);
+ details::log_msg log_msg(log_time, loc, name_, lvl, string_view_t(buf.data(), buf.size()));
+ log_it_(log_msg, log_enabled, traceback_enabled);
+ }
+
+ void log(source_loc loc, level::level_enum lvl, wstring_view_t msg)
+ {
+ bool log_enabled = should_log(lvl);
+ bool traceback_enabled = tracer_.enabled();
+ if (!log_enabled && !traceback_enabled)
+ {
+ return;
+ }
+
+ memory_buf_t buf;
+ details::os::wstr_to_utf8buf(wstring_view_t(msg.data(), msg.size()), buf);
+ details::log_msg log_msg(loc, name_, lvl, string_view_t(buf.data(), buf.size()));
+ log_it_(log_msg, log_enabled, traceback_enabled);
+ }
+
+ void log(level::level_enum lvl, wstring_view_t msg)
+ {
+ log(source_loc{}, lvl, msg);
}
template<typename... Args>
- void trace(fmt::wformat_string<Args...> fmt, Args &&...args)
+ void trace(wformat_string_t<Args...> fmt, Args &&...args)
{
log(level::trace, fmt, std::forward<Args>(args)...);
}
template<typename... Args>
- void debug(fmt::wformat_string<Args...> fmt, Args &&...args)
+ void debug(wformat_string_t<Args...> fmt, Args &&...args)
{
log(level::debug, fmt, std::forward<Args>(args)...);
}
template<typename... Args>
- void info(fmt::wformat_string<Args...> fmt, Args &&...args)
+ void info(wformat_string_t<Args...> fmt, Args &&...args)
{
log(level::info, fmt, std::forward<Args>(args)...);
}
template<typename... Args>
- void warn(fmt::wformat_string<Args...> fmt, Args &&...args)
+ void warn(wformat_string_t<Args...> fmt, Args &&...args)
{
log(level::warn, fmt, std::forward<Args>(args)...);
}
template<typename... Args>
- void error(fmt::wformat_string<Args...> fmt, Args &&...args)
+ void error(wformat_string_t<Args...> fmt, Args &&...args)
{
log(level::err, fmt, std::forward<Args>(args)...);
}
template<typename... Args>
- void critical(fmt::wformat_string<Args...> fmt, Args &&...args)
+ void critical(wformat_string_t<Args...> fmt, Args &&...args)
{
log(level::critical, fmt, std::forward<Args>(args)...);
}
@@ -335,8 +363,12 @@ protected:
}
SPDLOG_TRY
{
+#ifdef SPDLOG_USE_STD_FORMAT
+ memory_buf_t buf = std::vformat(fmt, std::make_format_args(std::forward<Args...>(args)...));
+#else
memory_buf_t buf;
- fmt::detail::vformat_to(buf, fmt, fmt::make_format_args(args...));
+ fmt::detail::vformat_to(buf, fmt, fmt::make_format_args(std::forward<Args...>(args)...));
+#endif
details::log_msg log_msg(loc, name_, lvl, string_view_t(buf.data(), buf.size()));
log_it_(log_msg, log_enabled, traceback_enabled);
}
@@ -356,8 +388,13 @@ protected:
SPDLOG_TRY
{
// format to wmemory_buffer and convert to utf8
- fmt::wmemory_buffer wbuf;
- fmt::detail::vformat_to(wbuf, fmt, fmt::make_format_args<fmt::wformat_context>(args...));
+ ;
+#ifdef SPDLOG_USE_STD_FORMAT
+ wmemory_buf_t wbuf = std::vformat(fmt, std::make_wformat_args(std::forward<Args...>(args)...));
+#else
+ wmemory_buf_t wbuf;
+ fmt::detail::vformat_to(wbuf, fmt, fmt::make_format_args<fmt::wformat_context>(std::forward<Args...>(args)...));
+#endif
memory_buf_t buf;
details::os::wstr_to_utf8buf(wstring_view_t(wbuf.data(), wbuf.size()), buf);
details::log_msg log_msg(loc, name_, lvl, string_view_t(buf.data(), buf.size()));
diff --git a/include/spdlog/sinks/daily_file_sink.h b/include/spdlog/sinks/daily_file_sink.h
index fc552398..cf83800a 100644
--- a/include/spdlog/sinks/daily_file_sink.h
+++ b/include/spdlog/sinks/daily_file_sink.h
@@ -32,7 +32,7 @@ struct daily_filename_calculator
{
filename_t basename, ext;
std::tie(basename, ext) = details::file_helper::split_by_extension(filename);
- return fmt::format(
+ return fmt_lib::format(
SPDLOG_FILENAME_T("{}_{:04d}-{:02d}-{:02d}{}"), basename, now_tm.tm_year + 1900, now_tm.tm_mon + 1, now_tm.tm_mday, ext);
}
};
@@ -49,8 +49,10 @@ struct daily_filename_format_calculator
static filename_t calc_filename(const filename_t &filename, const tm &now_tm)
{
// generate fmt datetime format string, e.g. {:%Y-%m-%d}.
- filename_t fmt_filename = fmt::format(SPDLOG_FILENAME_T("{{:{}}}"), filename);
-#if defined(_MSC_VER) && defined(SPDLOG_WCHAR_FILENAMES) // for some reason msvc doesnt allow fmt::runtime(..) with wchar here
+ filename_t fmt_filename = fmt_lib::format(SPDLOG_FILENAME_T("{{:{}}}"), filename);
+#if defined(SPDLOG_USE_STD_FORMAT)
+ return std::vformat(fmt_filename, std::make_format_args(now_tm));
+#elif defined(_MSC_VER) && defined(SPDLOG_WCHAR_FILENAMES) // for some reason msvc doesnt allow fmt::runtime(..) with wchar here
return fmt::format(fmt_filename, now_tm);
#else
return fmt::format(SPDLOG_FMT_RUNTIME(fmt_filename), now_tm);
diff --git a/include/spdlog/sinks/hourly_file_sink.h b/include/spdlog/sinks/hourly_file_sink.h
index 653faceb..71b5a1b4 100644
--- a/include/spdlog/sinks/hourly_file_sink.h
+++ b/include/spdlog/sinks/hourly_file_sink.h
@@ -31,7 +31,7 @@ struct hourly_filename_calculator
{
filename_t basename, ext;
std::tie(basename, ext) = details::file_helper::split_by_extension(filename);
- return fmt::format(SPDLOG_FILENAME_T("{}_{:04d}-{:02d}-{:02d}_{:02d}{}"), basename, now_tm.tm_year + 1900, now_tm.tm_mon + 1,
+ return fmt_lib::format(SPDLOG_FILENAME_T("{}_{:04d}-{:02d}-{:02d}_{:02d}{}"), basename, now_tm.tm_year + 1900, now_tm.tm_mon + 1,
now_tm.tm_mday, now_tm.tm_hour, ext);
}
};
diff --git a/include/spdlog/sinks/msvc_sink.h b/include/spdlog/sinks/msvc_sink.h
index 2ac4a965..76ec40a0 100644
--- a/include/spdlog/sinks/msvc_sink.h
+++ b/include/spdlog/sinks/msvc_sink.h
@@ -30,7 +30,11 @@ protected:
{
memory_buf_t formatted;
base_sink<Mutex>::formatter_->format(msg, formatted);
+#ifdef SPDLOG_USE_STD_FORMAT
+ OutputDebugStringA(formatted.c_str());
+#else
OutputDebugStringA(fmt::to_string(formatted).c_str());
+#endif
}
void flush_() override {}
diff --git a/include/spdlog/sinks/ringbuffer_sink.h b/include/spdlog/sinks/ringbuffer_sink.h
index 1ee3f691..5836d98b 100644
--- a/include/spdlog/sinks/ringbuffer_sink.h
+++ b/include/spdlog/sinks/ringbuffer_sink.h
@@ -50,7 +50,11 @@ public:
{
memory_buf_t formatted;
base_sink<Mutex>::formatter_->format(q_.at(i), formatted);
+#ifdef SPDLOG_USE_STD_FORMAT
+ ret.push_back(std::move(formatted));
+#else
ret.push_back(fmt::to_string(formatted));
+#endif
}
return ret;
}
diff --git a/include/spdlog/sinks/rotating_file_sink-inl.h b/include/spdlog/sinks/rotating_file_sink-inl.h
index 2e3087af..87e80593 100644
--- a/include/spdlog/sinks/rotating_file_sink-inl.h
+++ b/include/spdlog/sinks/rotating_file_sink-inl.h
@@ -51,7 +51,7 @@ SPDLOG_INLINE filename_t rotating_file_sink<Mutex>::calc_filename(const filename
filename_t basename, ext;
std::tie(basename, ext) = details::file_helper::split_by_extension(filename);
- return fmt::format(SPDLOG_FILENAME_T("{}.{}{}"), basename, index, ext);
+ return fmt_lib::format(SPDLOG_FILENAME_T("{}.{}{}"), basename, index, ext);
}
template<typename Mutex>
diff --git a/include/spdlog/sinks/win_eventlog_sink.h b/include/spdlog/sinks/win_eventlog_sink.h
index 5e70599a..202c79f8 100644
--- a/include/spdlog/sinks/win_eventlog_sink.h
+++ b/include/spdlog/sinks/win_eventlog_sink.h
@@ -47,6 +47,24 @@ namespace win_eventlog {
namespace internal {
+struct local_alloc_t
+{
+ HLOCAL hlocal_;
+
+ SPDLOG_CONSTEXPR local_alloc_t() SPDLOG_NOEXCEPT : hlocal_(nullptr) {}
+
+ local_alloc_t(local_alloc_t const&) = delete;
+ local_alloc_t& operator=(local_alloc_t const&) = delete;
+
+ ~local_alloc_t() SPDLOG_NOEXCEPT
+ {
+ if (hlocal_)
+ {
+ LocalFree(hlocal_);
+ }
+ }
+};
+
/** Windows error */
struct win32_error : public spdlog_ex
{
@@ -55,22 +73,17 @@ struct win32_error : public spdlog_ex
{
std::string system_message;
- LPSTR format_message_result{};
+ local_alloc_t format_message_result{};
auto format_message_succeeded =
::FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, nullptr,
- error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&format_message_result, 0, nullptr);
-
- if (format_message_succeeded && format_message_result)
- {
- system_message = fmt::format(" ({})", format_message_result);
- }
+ error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&format_message_result.hlocal_, 0, nullptr);
- if (format_message_result)
+ if (format_message_succeeded && format_message_result.hlocal_)
{
- LocalFree((HLOCAL)format_message_result);
+ system_message = fmt_lib::format(" ({})", (LPSTR)format_message_result.hlocal_);
}
- return fmt::format("{}: {}{}", user_message, error_code, system_message);
+ return fmt_lib::format("{}: {}{}", user_message, error_code, system_message);
}
explicit win32_error(std::string const &func_name, DWORD error = GetLastError())
diff --git a/include/spdlog/spdlog.h b/include/spdlog/spdlog.h
index 812896da..327a0ebe 100644
--- a/include/spdlog/spdlog.h
+++ b/include/spdlog/spdlog.h
@@ -128,49 +128,49 @@ SPDLOG_API spdlog::logger *default_logger_raw();
SPDLOG_API void set_default_logger(std::shared_ptr<spdlog::logger> default_logger);
template<typename... Args>
-inline void log(source_loc source, level::level_enum lvl, fmt::format_string<Args...> fmt, Args &&...args)
+inline void log(source_loc source, level::level_enum lvl, format_string_t<Args...> fmt, Args &&...args)
{
default_logger_raw()->log(source, lvl, fmt, std::forward<Args>(args)...);
}
template<typename... Args>
-inline void log(level::level_enum lvl, fmt::format_string<Args...> fmt, Args &&...args)
+inline void log(level::level_enum lvl, format_string_t<Args...> fmt, Args &&...args)
{
default_logger_raw()->log(source_loc{}, lvl, fmt, std::forward<Args>(args)...);
}
template<typename... Args>
-inline void trace(fmt::format_string<Args...> fmt, Args &&...args)
+inline void trace(format_string_t<Args...> fmt, Args &&...args)
{
default_logger_raw()->trace(fmt, std::forward<Args>(args)...);
}
template<typename... Args>
-inline void debug(fmt::format_string<Args...> fmt, Args &&...args)
+inline void debug(format_string_t<Args...> fmt, Args &&...args)
{
default_logger_raw()->debug(fmt, std::forward<Args>(args)...);
}
template<typename... Args>
-inline void info(fmt::format_string<Args...> fmt, Args &&...args)
+inline void info(format_string_t<Args...> fmt, Args &&...args)
{
default_logger_raw()->info(fmt, std::forward<Args>(args)...);
}
template<typename... Args>
-inline void warn(fmt::format_string<Args...> fmt, Args &&...args)
+inline void warn(format_string_t<Args...> fmt, Args &&...args)
{
default_logger_raw()->warn(fmt, std::forward<Args>(args)...);
}
template<typename... Args>
-inline void error(fmt::format_string<Args...> fmt, Args &&...args)
+inline void error(format_string_t<Args...> fmt, Args &&...args)
{
default_logger_raw()->error(fmt, std::forward<Args>(args)...);
}
template<typename... Args>
-inline void critical(fmt::format_string<Args...> fmt, Args &&...args)
+inline void critical(format_string_t<Args...> fmt, Args &&...args)
{
default_logger_raw()->critical(fmt, std::forward<Args>(args)...);
}
@@ -189,49 +189,49 @@ inline void log(level::level_enum lvl, const T &msg)
#ifdef SPDLOG_WCHAR_TO_UTF8_SUPPORT
template<typename... Args>
-inline void log(source_loc source, level::level_enum lvl, fmt::wformat_string<Args...> fmt, Args &&...args)
+inline void log(source_loc source, level::level_enum lvl, wformat_string_t<Args...> fmt, Args &&...args)
{
default_logger_raw()->log(source, lvl, fmt, std::forward<Args>(args)...);
}
template<typename... Args>
-inline void log(level::level_enum lvl, fmt::wformat_string<Args...> fmt, Args &&...args)
+inline void log(level::level_enum lvl, wformat_string_t<Args...> fmt, Args &&...args)
{
default_logger_raw()->log(source_loc{}, lvl, fmt, std::forward<Args>(args)...);
}
template<typename... Args>
-inline void trace(fmt::wformat_string<Args...> fmt, Args &&...args)
+inline void trace(wformat_string_t<Args...> fmt, Args &&...args)
{
default_logger_raw()->trace(fmt, std::forward<Args>(args)...);
}
template<typename... Args>
-inline void debug(fmt::wformat_string<Args...> fmt, Args &&...args)
+inline void debug(wformat_string_t<Args...> fmt, Args &&...args)
{
default_logger_raw()->debug(fmt, std::forward<Args>(args)...);
}
template<typename... Args>
-inline void info(fmt::wformat_string<Args...> fmt, Args &&...args)
+inline void info(wformat_string_t<Args...> fmt, Args &&...args)
{
default_logger_raw()->info(fmt, std::forward<Args>(args)...);
}
template<typename... Args>
-inline void warn(fmt::wformat_string<Args...> fmt, Args &&...args)
+inline void warn(wformat_string_t<Args...> fmt, Args &&...args)
{
default_logger_raw()->warn(fmt, std::forward<Args>(args)...);
}
template<typename... Args>
-inline void error(fmt::wformat_string<Args...> fmt, Args &&...args)
+inline void error(wformat_string_t<Args...> fmt, Args &&...args)
{
default_logger_raw()->error(fmt, std::forward<Args>(args)...);
}
template<typename... Args>
-inline void critical(fmt::wformat_string<Args...> fmt, Args &&...args)
+inline void critical(wformat_string_t<Args...> fmt, Args &&...args)
{
default_logger_raw()->critical(fmt, std::forward<Args>(args)...);
}
diff --git a/include/spdlog/tweakme.h b/include/spdlog/tweakme.h
index 24361f30..08f0f4e5 100644
--- a/include/spdlog/tweakme.h
+++ b/include/spdlog/tweakme.h
@@ -75,6 +75,13 @@
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
+// Uncomment to use C++20 std::format instead of fmt. This removes compile
+// time checking of format strings, but doesn't depend on the fmt library.
+//
+// #define SPDLOG_USE_STD_FORMAT
+///////////////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////////
// Uncomment to enable wchar_t support (convert to utf8)
//
// #define SPDLOG_WCHAR_TO_UTF8_SUPPORT
diff --git a/src/fmt.cpp b/src/fmt.cpp
index b3cd3cf1..536aa675 100644
--- a/src/fmt.cpp
+++ b/src/fmt.cpp
@@ -6,7 +6,7 @@
# error Please define SPDLOG_COMPILED_LIB to compile this file.
#endif
-#if !defined(SPDLOG_FMT_EXTERNAL)
+#if !defined(SPDLOG_FMT_EXTERNAL) && !defined(SPDLOG_USE_STD_FORMAT)
# include <spdlog/fmt/bundled/format-inl.h>
FMT_BEGIN_NAMESPACE
diff --git a/tests/test_async.cpp b/tests/test_async.cpp
index 83fc0ec6..124f3132 100644
--- a/tests/test_async.cpp
+++ b/tests/test_async.cpp
@@ -166,7 +166,7 @@ TEST_CASE("to_file", "[async]")
require_message_count(TEST_FILENAME, messages);
auto contents = file_contents(TEST_FILENAME);
using spdlog::details::os::default_eol;
- REQUIRE(ends_with(contents, fmt::format("Hello message #1023{}", default_eol)));
+ REQUIRE(ends_with(contents, spdlog::fmt_lib::format("Hello message #1023{}", default_eol)));
}
TEST_CASE("to_file multi-workers", "[async]")
diff --git a/tests/test_daily_logger.cpp b/tests/test_daily_logger.cpp
index 6aeff5b1..93bd4662 100644
--- a/tests/test_daily_logger.cpp
+++ b/tests/test_daily_logger.cpp
@@ -3,7 +3,11 @@
*/
#include "includes.h"
+#ifdef SPDLOG_USE_STD_FORMAT
+using filename_memory_buf_t = std::basic_string<spdlog::filename_t::value_type>;
+#else
using filename_memory_buf_t = fmt::basic_memory_buffer<spdlog::filename_t::value_type, 250>;
+#endif
TEST_CASE("daily_logger with dateonly calculator", "[daily_logger]")
{
@@ -15,7 +19,7 @@ TEST_CASE("daily_logger with dateonly calculator", "[daily_logger]")
spdlog::filename_t basename = SPDLOG_FILENAME_T("test_logs/daily_dateonly");
std::tm tm = spdlog::details::os::localtime();
filename_memory_buf_t w;
- fmt::format_to(
+ spdlog::fmt_lib::format_to(
std::back_inserter(w), SPDLOG_FILENAME_T("{}_{:04d}-{:02d}-{:02d}"), basename, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday);
auto logger = spdlog::create<sink_type>("logger", basename, 0, 0);
@@ -29,10 +33,18 @@ TEST_CASE("daily_logger with dateonly calculator", "[daily_logger]")
#ifdef SPDLOG_WCHAR_FILENAMES
spdlog::memory_buf_t buf;
spdlog::details::os::wstr_to_utf8buf(fmt::to_string(w), buf);
+#ifdef SPDLOG_USE_STD_FORMAT
+ auto &filename = buf;
+#else
auto filename = fmt::to_string(buf);
+#endif
+#else
+#ifdef SPDLOG_USE_STD_FORMAT
+ auto &filename = w;
#else
auto filename = fmt::to_string(w);
#endif
+#endif
require_message_count(filename, 10);
}
@@ -41,9 +53,13 @@ struct custom_daily_file_name_calculator
static spdlog::filename_t calc_filename(const spdlog::filename_t &basename, const tm &now_tm)
{
filename_memory_buf_t w;
- fmt::format_to(std::back_inserter(w), SPDLOG_FILENAME_T("{}{:04d}{:02d}{:02d}"), basename, now_tm.tm_year + 1900, now_tm.tm_mon + 1,
+ spdlog::fmt_lib::format_to(std::back_inserter(w), SPDLOG_FILENAME_T("{}{:04d}{:02d}{:02d}"), basename, now_tm.tm_year + 1900, now_tm.tm_mon + 1,
now_tm.tm_mday);
+#ifdef SPDLOG_USE_STD_FORMAT
+ return w;
+#else
return fmt::to_string(w);
+#endif
}
};
@@ -57,7 +73,7 @@ TEST_CASE("daily_logger with custom calculator", "[daily_logger]")
spdlog::filename_t basename = SPDLOG_FILENAME_T("test_logs/daily_dateonly");
std::tm tm = spdlog::details::os::localtime();
filename_memory_buf_t w;
- fmt::format_to(
+ spdlog::fmt_lib::format_to(
std::back_inserter(w), SPDLOG_FILENAME_T("{}{:04d}{:02d}{:02d}"), basename, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday);
auto logger = spdlog::create<sink_type>("logger", basename, 0, 0);
@@ -71,10 +87,18 @@ TEST_CASE("daily_logger with custom calculator", "[daily_logger]")
#ifdef SPDLOG_WCHAR_FILENAMES
spdlog::memory_buf_t buf;
spdlog::details::os::wstr_to_utf8buf(fmt::to_string(w), buf);
+#ifdef SPDLOG_USE_STD_FORMAT
+ auto &filename = buf;
+#else
auto filename = fmt::to_string(buf);
+#endif
+#else
+#ifdef SPDLOG_USE_STD_FORMAT
+ auto &filename = w;
#else
auto filename = fmt::to_string(w);
#endif
+#endif
require_message_count(filename, 10);
}
diff --git a/tests/test_errors.cpp b/tests/test_errors.cpp
index bcc21d73..41441d0d 100644
--- a/tests/test_errors.cpp
+++ b/tests/test_errors.cpp
@@ -34,7 +34,7 @@ TEST_CASE("default_error_handler", "[errors]]")
logger->flush();
using spdlog::details::os::default_eol;
- REQUIRE(file_contents(SIMPLE_LOG) == fmt::format("Test message 2{}", default_eol));
+ REQUIRE(file_contents(SIMPLE_LOG) == spdlog::fmt_lib::format("Test message 2{}", default_eol));
REQUIRE(count_lines(SIMPLE_LOG) == 1);
}
diff --git a/tests/test_file_helper.cpp b/tests/test_file_helper.cpp
index 37c929f5..168c6601 100644
--- a/tests/test_file_helper.cpp
+++ b/tests/test_file_helper.cpp
@@ -10,7 +10,7 @@ using spdlog::details::file_helper;
static void write_with_helper(file_helper &helper, size_t howmany)
{
spdlog::memory_buf_t formatted;
- fmt::format_to(std::back_inserter(formatted), "{}", std::string(howmany, '1'));
+ spdlog::fmt_lib::format_to(std::back_inserter(formatted), "{}", std::string(howmany, '1'));
helper.write(formatted);
helper.flush();
}
diff --git a/tests/test_fmt_helper.cpp b/tests/test_fmt_helper.cpp
index 3ef18abe..6972d2d2 100644
--- a/tests/test_fmt_helper.cpp
+++ b/tests/test_fmt_helper.cpp
@@ -8,28 +8,48 @@ void test_pad2(int n, const char *expected)
{
memory_buf_t buf;
spdlog::details::fmt_helper::pad2(n, buf);
+
+#ifdef SPDLOG_USE_STD_FORMAT
+ REQUIRE(formatted == expected);
+#else
REQUIRE(fmt::to_string(buf) == expected);
+#endif
}
void test_pad3(uint32_t n, const char *expected)
{
memory_buf_t buf;
spdlog::details::fmt_helper::pad3(n, buf);
+
+#ifdef SPDLOG_USE_STD_FORMAT
+ REQUIRE(formatted == expected);
+#else
REQUIRE(fmt::to_string(buf) == expected);
+#endif
}
void test_pad6(std::size_t n, const char *expected)
{
memory_buf_t buf;
spdlog::details::fmt_helper::pad6(n, buf);
+
+#ifdef SPDLOG_USE_STD_FORMAT
+ REQUIRE(formatted == expected);
+#else
REQUIRE(fmt::to_string(buf) == expected);
+#endif
}
void test_pad9(std::size_t n, const char *expected)
{
memory_buf_t buf;
spdlog::details::fmt_helper::pad9(n, buf);
+
+#ifdef SPDLOG_USE_STD_FORMAT
+ REQUIRE(formatted == expected);
+#else
REQUIRE(fmt::to_string(buf) == expected);
+#endif
}
TEST_CASE("pad2", "[fmt_helper]")
diff --git a/tests/test_macros.cpp b/tests/test_macros.cpp
index dd21ed19..b4ad5654 100644
--- a/tests/test_macros.cpp
+++ b/tests/test_macros.cpp
@@ -25,7 +25,7 @@ TEST_CASE("debug and trace w/o format string", "[macros]]")
logger->flush();
using spdlog::details::os::default_eol;
- REQUIRE(ends_with(file_contents(TEST_FILENAME), fmt::format("Test message 2{}", default_eol)));
+ REQUIRE(ends_with(file_contents(TEST_FILENAME), spdlog::fmt_lib::format("Test message 2{}", default_eol)));
REQUIRE(count_lines(TEST_FILENAME) == 1);
spdlog::set_default_logger(logger);
@@ -35,7 +35,7 @@ TEST_CASE("debug and trace w/o format string", "[macros]]")
logger->flush();
require_message_count(TEST_FILENAME, 2);
- REQUIRE(ends_with(file_contents(TEST_FILENAME), fmt::format("Test message 4{}", default_eol)));
+ REQUIRE(ends_with(file_contents(TEST_FILENAME), spdlog::fmt_lib::format("Test message 4{}", default_eol)));
}
TEST_CASE("disable param evaluation", "[macros]")
diff --git a/tests/test_pattern_formatter.cpp b/tests/test_pattern_formatter.cpp
index 656f93a0..78c4cd30 100644
--- a/tests/test_pattern_formatter.cpp
+++ b/tests/test_pattern_formatter.cpp
@@ -64,7 +64,7 @@ TEST_CASE("color range test1", "[pattern_formatter]")
auto formatter = std::make_shared<spdlog::pattern_formatter>("%^%v%$", spdlog::pattern_time_type::local, "\n");
memory_buf_t buf;
- fmt::format_to(std::back_inserter(buf), "Hello");
+ spdlog::fmt_lib::format_to(std::back_inserter(buf), "Hello");
memory_buf_t formatted;
std::string logger_name = "test";
spdlog::details::log_msg msg(logger_name, spdlog::level::info, spdlog::string_view_t(buf.data(), buf.size()));
@@ -273,7 +273,11 @@ TEST_CASE("clone-default-formatter", "[pattern_formatter]")
formatter_1->format(msg, formatted_1);
formatter_2->format(msg, formatted_2);
+#ifdef SPDLOG_USE_STD_FORMAT
+ REQUIRE(formatted_1 == formatted_2);
+#else
REQUIRE(fmt::to_string(formatted_1) == fmt::to_string(formatted_2));
+#endif
}
TEST_CASE("clone-default-formatter2", "[pattern_formatter]")
@@ -288,7 +292,11 @@ TEST_CASE("clone-default-formatter2", "[pattern_formatter]")
formatter_1->format(msg, formatted_1);
formatter_2->format(msg, formatted_2);
+#ifdef SPDLOG_USE_STD_FORMAT
+ REQUIRE(formatted_1 == formatted_2);
+#else
REQUIRE(fmt::to_string(formatted_1) == fmt::to_string(formatted_2));
+#endif
}
TEST_CASE("clone-formatter", "[pattern_formatter]")
@@ -302,7 +310,12 @@ TEST_CASE("clone-formatter", "[pattern_formatter]")
memory_buf_t formatted_2;
formatter_1->format(msg, formatted_1);
formatter_2->format(msg, formatted_2);
+
+#ifdef SPDLOG_USE_STD_FORMAT
+ REQUIRE(formatted_1 == formatted_2);
+#else
REQUIRE(fmt::to_string(formatted_1) == fmt::to_string(formatted_2));
+#endif
}
TEST_CASE("clone-formatter-2", "[pattern_formatter]")
@@ -317,7 +330,12 @@ TEST_CASE("clone-formatter-2", "[pattern_formatter]")
memory_buf_t formatted_2;
formatter_1->format(msg, formatted_1);
formatter_2->format(msg, formatted_2);
+
+#ifdef SPDLOG_USE_STD_FORMAT
+ REQUIRE(formatted_1 == formatted_2);
+#else
REQUIRE(fmt::to_string(formatted_1) == fmt::to_string(formatted_2));
+#endif
}
class custom_test_flag : public spdlog::custom_flag_formatter
@@ -362,9 +380,15 @@ TEST_CASE("clone-custom_formatter", "[pattern_formatter]")
formatter_1->format(msg, formatted_1);
formatter_2->format(msg, formatted_2);
- auto expected = fmt::format("[logger-name] [custom_output] some message{}", spdlog::details::os::default_eol);
+ auto expected = spdlog::fmt_lib::format("[logger-name] [custom_output] some message{}", spdlog::details::os::default_eol);
+
+#ifdef SPDLOG_USE_STD_FORMAT
+ REQUIRE(formatted_1 == expected);
+ REQUIRE(formatted_2 == expected);
+#else
REQUIRE(fmt::to_string(formatted_1) == expected);
REQUIRE(fmt::to_string(formatted_2) == expected);
+#endif
}
//
@@ -385,7 +409,12 @@ TEST_CASE("short filename formatter-1", "[pattern_formatter]")
spdlog::source_loc source_loc{test_path, 123, "some_func()"};
spdlog::details::log_msg msg(source_loc, "logger-name", spdlog::level::info, "Hello");
formatter.format(msg, formatted);
+
+#ifdef SPDLOG_USE_STD_FORMAT
+ REQUIRE(formatted == "myfile.cpp");
+#else
REQUIRE(fmt::to_string(formatted) == "myfile.cpp");
+#endif
}
TEST_CASE("short filename formatter-2", "[pattern_formatter]")
@@ -396,7 +425,12 @@ TEST_CASE("short filename formatter-2", "[pattern_formatter]")
spdlog::source_loc source_loc{"myfile.cpp", 123, "some_func()"};
spdlog::details::log_msg msg(source_loc, "logger-name", spdlog::level::info, "Hello");
formatter.format(msg, formatted);
+
+#ifdef SPDLOG_USE_STD_FORMAT
+ REQUIRE(formatted == "myfile.cpp:123");
+#else
REQUIRE(fmt::to_string(formatted) == "myfile.cpp:123");
+#endif
}
TEST_CASE("short filename formatter-3", "[pattern_formatter]")
@@ -407,7 +441,12 @@ TEST_CASE("short filename formatter-3", "[pattern_formatter]")
spdlog::source_loc source_loc{"", 123, "some_func()"};
spdlog::details::log_msg msg(source_loc, "logger-name", spdlog::level::info, "Hello");
formatter.format(msg, formatted);
+
+#ifdef SPDLOG_USE_STD_FORMAT
+ REQUIRE(formatted == " Hello");
+#else
REQUIRE(fmt::to_string(formatted) == " Hello");
+#endif
}
TEST_CASE("full filename formatter", "[pattern_formatter]")
@@ -418,7 +457,12 @@ TEST_CASE("full filename formatter", "[pattern_formatter]")
spdlog::source_loc source_loc{test_path, 123, "some_func()"};
spdlog::details::log_msg msg(source_loc, "logger-name", spdlog::level::info, "Hello");
formatter.format(msg, formatted);
+
+#ifdef SPDLOG_USE_STD_FORMAT
+ REQUIRE(formatted == test_path);
+#else
REQUIRE(fmt::to_string(formatted) == test_path);
+#endif
}
TEST_CASE("custom flags", "[pattern_formatter]")
@@ -430,8 +474,13 @@ TEST_CASE("custom flags", "[pattern_formatter]")
spdlog::details::log_msg msg(spdlog::source_loc{}, "logger-name", spdlog::level::info, "some message");
formatter->format(msg, formatted);
- auto expected = fmt::format("[logger-name] [custom1] [custom2] some message{}", spdlog::details::os::default_eol);
+ auto expected = spdlog::fmt_lib::format("[logger-name] [custom1] [custom2] some message{}", spdlog::details::os::default_eol);
+
+#ifdef SPDLOG_USE_STD_FORMAT
+ REQUIRE(formatted == expected);
+#else
REQUIRE(fmt::to_string(formatted) == expected);
+#endif
}
TEST_CASE("custom flags-padding", "[pattern_formatter]")
@@ -443,8 +492,13 @@ TEST_CASE("custom flags-padding", "[pattern_formatter]")
spdlog::details::log_msg msg(spdlog::source_loc{}, "logger-name", spdlog::level::info, "some message");
formatter->format(msg, formatted);
- auto expected = fmt::format("[logger-name] [custom1] [ custom2] some message{}", spdlog::details::os::default_eol);
+ auto expected = spdlog::fmt_lib::format("[logger-name] [custom1] [ custom2] some message{}", spdlog::details::os::default_eol);
+
+#ifdef SPDLOG_USE_STD_FORMAT
+ REQUIRE(formatted == expected);
+#else
REQUIRE(fmt::to_string(formatted) == expected);
+#endif
}
TEST_CASE("custom flags-exception", "[pattern_formatter]")