Merge pull request #1 from gabime/v1.x

spdlog update merge 20190118
pull/1084/head
CodingTrader 7 years ago committed by GitHub
commit cdcd4a6bc3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -104,6 +104,7 @@ script:
-DCMAKE_CXX_STANDARD=$CPP \
-DSPDLOG_BUILD_EXAMPLES=ON \
-DSPDLOG_BUILD_BENCH=OFF \
-DSPDLOG_BUILD_TESTS=ON \
-DSPDLOG_SANITIZE_ADDRESS=$ASAN \
-DSPDLOG_SANITIZE_THREAD=$TSAN
- make VERBOSE=1 -j2

@ -5,7 +5,6 @@
cmake_minimum_required(VERSION 3.1)
project(spdlog VERSION 1.3.0 LANGUAGES CXX)
include(CTest)
include(CMakeDependentOption)
include(GNUInstallDirs)
@ -53,11 +52,12 @@ endif()
option(SPDLOG_BUILD_EXAMPLES "Build examples" ${SPDLOG_MASTER_PROJECT})
option(SPDLOG_BUILD_BENCH "Build benchmarks" ${SPDLOG_MASTER_PROJECT})
option(SPDLOG_BUILD_TESTS "Build tests" ${SPDLOG_MASTER_PROJECT})
option(SPDLOG_FMT_EXTERNAL "Use external fmt library instead of bundled" OFF)
cmake_dependent_option(SPDLOG_BUILD_TESTING
"Build spdlog tests" ${SPDLOG_MASTER_PROJECT}
"BUILD_TESTING" OFF
)
if(SPDLOG_FMT_EXTERNAL)
find_package(fmt REQUIRED CONFIG)
endif()
target_include_directories(
spdlog
@ -66,13 +66,19 @@ target_include_directories(
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>"
)
if(SPDLOG_FMT_EXTERNAL)
target_compile_definitions(spdlog INTERFACE SPDLOG_FMT_EXTERNAL)
target_link_libraries(spdlog INTERFACE fmt::fmt)
endif()
set(HEADER_BASE "${CMAKE_CURRENT_SOURCE_DIR}/include")
if(SPDLOG_BUILD_EXAMPLES)
add_subdirectory(example)
endif()
if(SPDLOG_BUILD_TESTING)
if(SPDLOG_BUILD_TESTS)
include(CTest)
add_subdirectory(tests)
endif()
@ -88,7 +94,8 @@ set(config_install_dir "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}")
set(include_install_dir "${CMAKE_INSTALL_INCLUDEDIR}")
set(pkgconfig_install_dir "${CMAKE_INSTALL_LIBDIR}/pkgconfig")
set(version_config "${CMAKE_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake")
set(project_config "${PROJECT_NAME}Config.cmake")
set(project_config "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake")
set(targets_config "${PROJECT_NAME}Targets.cmake")
set(pkg_config "${CMAKE_BINARY_DIR}/${PROJECT_NAME}.pc")
set(targets_export_name "${PROJECT_NAME}Targets")
set(namespace "${PROJECT_NAME}::")
@ -101,6 +108,8 @@ write_basic_package_version_file(
# configure pkg config file
configure_file("cmake/spdlog.pc.in" "${pkg_config}" @ONLY)
# configure spdlogConfig.cmake file
configure_file("cmake/Config.cmake.in" "${project_config}" @ONLY)
# install targets
install(
@ -114,9 +123,9 @@ install(
DESTINATION "${include_install_dir}"
)
# install project version file
# install project config and version file
install(
FILES "${version_config}"
FILES "${project_config}" "${version_config}"
DESTINATION "${config_install_dir}"
)
@ -126,19 +135,19 @@ install(
DESTINATION "${pkgconfig_install_dir}"
)
# install project config file
# install targets config file
install(
EXPORT "${targets_export_name}"
NAMESPACE "${namespace}"
DESTINATION "${config_install_dir}"
FILE ${project_config}
FILE ${targets_config}
)
# export build directory config file
# export build directory targets file
export(
EXPORT ${targets_export_name}
NAMESPACE "${namespace}"
FILE ${project_config}
FILE ${targets_config}
)
# register project in CMake user registry

@ -77,42 +77,43 @@ async... Elapsed: 0.349851 2,858,358/sec
## Usage samples
#### Basic usage
```c++
#include "spdlog/spdlog.h"
#include "spdlog/sinks/stdout_color_sinks.h"
void stdout_example()
int main()
{
// create color multi threaded logger
auto console = spdlog::stdout_color_mt("console");
console->info("Welcome to spdlog!");
console->error("Some error message with arg: {}", 1);
auto err_logger = spdlog::stderr_color_mt("stderr");
err_logger->error("Some error message");
// Formatting examples
console->warn("Easy padding in numbers like {:08d}", 12);
console->critical("Support for int: {0:d}; hex: {0:x}; oct: {0:o}; bin: {0:b}", 42);
console->info("Support for floats {:03.2f}", 1.23456);
console->info("Positional args are {1} {0}..", "too", "supported");
console->info("{:<30}", "left aligned");
spdlog::info("Welcome to spdlog!");
spdlog::error("Some error message with arg: {}", 1);
spdlog::get("console")->info("loggers can be retrieved from a global registry using the spdlog::get(logger_name)");
spdlog::warn("Easy padding in numbers like {:08d}", 12);
spdlog::critical("Support for int: {0:d}; hex: {0:x}; oct: {0:o}; bin: {0:b}", 42);
spdlog::info("Support for floats {:03.2f}", 1.23456);
spdlog::info("Positional args are {1} {0}..", "too", "supported");
spdlog::info("{:<30}", "left aligned");
// Runtime log levels
spdlog::set_level(spdlog::level::info); // Set global log level to info
console->debug("This message should not be displayed!");
console->set_level(spdlog::level::trace); // Set specific logger's log level
console->debug("This message should be displayed..");
spdlog::set_level(spdlog::level::debug); // Set global log level to debug
spdlog::debug("This message should be displayed..");
// Customize msg format for all loggers
// change log pattern
spdlog::set_pattern("[%H:%M:%S %z] [%n] [%^---%L---%$] [thread %t] %v");
console->info("This an info message with custom format");
// Compile time log levels
// define SPDLOG_DEBUG_ON or SPDLOG_TRACE_ON
SPDLOG_TRACE(console, "Enabled only #ifdef SPDLOG_TRACE_ON..{} ,{}", 1, 3.23);
SPDLOG_DEBUG(console, "Enabled only #ifdef SPDLOG_DEBUG_ON.. {} ,{}", 1, 3.23);
// define SPDLOG_ACTIVE_LEVEL to desired level
SPDLOG_TRACE("Some trace message with param {}", {});
SPDLOG_DEBUG("Some debug message");
}
```
#### create stdout/stderr logger object
```c++
#include "spdlog/spdlog.h"
#include "spdlog/sinks/stdout_color_sinks.h"
void stdout_example()
{
// create color multi threaded logger
auto console = spdlog::stdout_color_mt("console");
auto err_logger = spdlog::stderr_color_mt("stderr");
spdlog::get("console")->info("loggers can be retrieved from a global registry using the spdlog::get(logger_name)");
}
```
---

@ -29,4 +29,6 @@ build_script:
cmake .. -G %GENERATOR% -DCMAKE_BUILD_TYPE=%BUILD_TYPE% -DSPDLOG_BUILD_BENCH=OFF
cmake --build . --config %BUILD_TYPE%
test: off
test_script:
- ctest -VV -C "%BUILD_TYPE%"

@ -30,20 +30,19 @@ if(NOT TARGET spdlog)
endif()
find_package(Threads REQUIRED)
find_package(benchmark CONFIG REQUIRED)
add_executable(bench bench.cpp)
target_link_libraries(bench spdlog::spdlog Threads::Threads)
target_link_libraries(bench PRIVATE spdlog::spdlog Threads::Threads)
add_executable(async_bench async_bench.cpp)
target_link_libraries(async_bench spdlog::spdlog Threads::Threads)
target_link_libraries(async_bench PRIVATE spdlog::spdlog Threads::Threads)
add_executable(latency latency.cpp)
set(CMAKE_CXX_STANDARD_LIBRARIES -lbenchmark)
target_link_libraries(latency spdlog::spdlog Threads::Threads)
target_link_libraries(latency PRIVATE benchmark::benchmark spdlog::spdlog Threads::Threads)
add_executable(formatter-bench formatter-bench.cpp)
set(CMAKE_CXX_STANDARD_LIBRARIES -lbenchmark)
target_link_libraries(formatter-bench spdlog::spdlog Threads::Threads)
target_link_libraries(formatter-bench PRIVATE benchmark::benchmark spdlog::spdlog Threads::Threads)
file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/logs")

@ -68,22 +68,7 @@ int main(int argc, char *argv[])
bench(howmany, spdlog::create<null_sink_st>("null_st"));
spdlog::info("**************************************************************");
spdlog::info("Default API. Single thread, {:n} iterations", howmany);
spdlog::info("**************************************************************");
basic_st = spdlog::basic_logger_st("basic_st", "logs/basic_st.log", true);
bench_default_api(howmany, std::move(basic_st));
rotating_st = spdlog::rotating_logger_st("rotating_st", "logs/rotating_st.log", file_size, rotating_files);
bench_default_api(howmany, std::move(rotating_st));
daily_st = spdlog::daily_logger_st("daily_st", "logs/daily_st.log");
bench_default_api(howmany, std::move(daily_st));
bench_default_api(howmany, spdlog::create<null_sink_st>("null_st"));
spdlog::info("**************************************************************");
spdlog::info("C-string (500 bytes). Single thread, {:n} iterations", howmany);
spdlog::info("C-string (400 bytes). Single thread, {:n} iterations", howmany);
spdlog::info("**************************************************************");
basic_st = spdlog::basic_logger_st("basic_st", "logs/basic_cs.log", true);

@ -21,18 +21,14 @@ void bench_scoped_pad(benchmark::State &state, size_t wrapped_size, spdlog::deta
}
}
void bench_formatter(benchmark::State &state, std::string pattern)
{
auto formatter = spdlog::details::make_unique<spdlog::pattern_formatter>(pattern);
fmt::memory_buffer dest;
std::string logger_name = "logger-name";
const char* text = "Hello. This is some message with length of 80 ";
const char *text = "Hello. This is some message with length of 80 ";
spdlog::details::log_msg msg(&logger_name, spdlog::level::info, text);
// formatter->format(msg, dest);
// printf("%s\n", fmt::to_string(dest).c_str());
for (auto _ : state)
{
@ -47,11 +43,17 @@ void bench_formatters()
// basic patterns(single flag)
std::string all_flags = "+vtPnlLaAbBcCYDmdHIMSefFprRTXzEi%";
std::vector<std::string> basic_patterns;
for(auto &flag:all_flags)
for (auto &flag : all_flags)
{
auto pattern = std::string("%") + flag;
benchmark::RegisterBenchmark(pattern.c_str(), bench_formatter, pattern);
// pattern = std::string("%16") + flag;
// benchmark::RegisterBenchmark(pattern.c_str(), bench_formatter, pattern);
//
// // bench center padding
// pattern = std::string("%=16") + flag;
// benchmark::RegisterBenchmark(pattern.c_str(), bench_formatter, pattern);
}
// complex patterns
@ -60,41 +62,31 @@ void bench_formatters()
"[%Y-%m-%d %H:%M:%S.%e] [%l] [%n] %v",
"[%Y-%m-%d %H:%M:%S.%e] [%l] [%n] [%t] %v",
};
for(auto &pattern:patterns)
for (auto &pattern : patterns)
{
benchmark::RegisterBenchmark(pattern.c_str(), bench_formatter, pattern);
benchmark::RegisterBenchmark(pattern.c_str(), bench_formatter, pattern)->Iterations(2500000);
}
}
void bench_padders()
int main(int argc, char *argv[])
{
using spdlog::details::padding_info;
std::vector<size_t> sizes = {0, 2, 4, 8, 16, 32, 64, 128};
for (auto size : sizes)
spdlog::set_pattern("[%^%l%$] %v");
if (argc != 2)
{
size_t wrapped_size = 8;
size_t padding_size = wrapped_size + size;
std::string title = "scoped_pad::left::" + std::to_string(size);
benchmark::RegisterBenchmark(title.c_str(), bench_scoped_pad, wrapped_size, padding_info(padding_size, padding_info::left));
title = "scoped_pad::right::" + std::to_string(size);
benchmark::RegisterBenchmark(title.c_str(), bench_scoped_pad, wrapped_size, padding_info(padding_size, padding_info::right));
title = "scoped_pad::center::" + std::to_string(size);
benchmark::RegisterBenchmark(title.c_str(), bench_scoped_pad, wrapped_size, padding_info(padding_size, padding_info::center));
spdlog::error("Usage: {} <pattern> (or \"all\" to bench all)", argv[0]);
exit(1);
}
}
int main(int argc, char *argv[])
{
std::string pattern = argv[1];
if (pattern == "all")
{
bench_formatters();
//bench_padders();
}
else
{
benchmark::RegisterBenchmark(pattern.c_str(), bench_formatter, pattern);
}
benchmark::Initialize(&argc, argv);
benchmark::RunSpecifiedBenchmarks();
}

@ -74,7 +74,6 @@ void bench_disabled_macro(benchmark::State &state, std::shared_ptr<spdlog::logge
int main(int argc, char *argv[])
{
spdlog::set_pattern("[tid %t] %v");
using spdlog::sinks::basic_file_sink_mt;
using spdlog::sinks::basic_file_sink_st;
using spdlog::sinks::null_sink_mt;

@ -21,4 +21,11 @@
# * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
# *************************************************************************/
set(SPDLOG_FMT_EXTERNAL @SPDLOG_FMT_EXTERNAL@)
include("${CMAKE_CURRENT_LIST_DIR}/@targets_export_name@.cmake")
if(SPDLOG_FMT_EXTERNAL)
include(CMakeFindDependencyMacro)
find_dependency(fmt CONFIG)
endif()

@ -31,7 +31,7 @@ int main(int, char *[])
spdlog::critical("Support for int: {0:d}; hex: {0:x}; oct: {0:o}; bin: {0:b}", 42);
spdlog::info("Support for floats {:03.2f}", 1.23456);
spdlog::info("Positional args are {1} {0}..", "too", "supported");
spdlog::info("{:>8} aligned, {:>8} aligned", "right", "left");
spdlog::info("{:>8} aligned, {:<8} aligned", "right", "left");
// Runtime log levels
spdlog::set_level(spdlog::level::info); // Set global log level to info
@ -161,11 +161,10 @@ void binary_example()
// define SPDLOG_ACTIVE_LEVEL to required level (e.g. SPDLOG_LEVEL_TRACE)
void trace_example()
{
// trace from default logger
SPDLOG_TRACE("Enabled only #ifdef SPDLOG_TRACE_ON..{} ,{}", 1, 3.23);
SPDLOG_TRACE("Some trace message.. {} ,{}", 1, 3.23);
// debug from default logger
SPDLOG_DEBUG("Enabled only #ifdef SPDLOG_DEBUG_ON.. {} ,{}", 1, 3.23);
SPDLOG_DEBUG("Some debug message.. {} ,{}", 1, 3.23);
// trace from logger object
auto logger = spdlog::get("file_logger");

@ -14,6 +14,7 @@
#include <memory>
#include <stdexcept>
#include <string>
#include <cstring>
#include <type_traits>
#include <unordered_map>
@ -24,6 +25,8 @@
#include "spdlog/details/null_mutex.h"
#include "spdlog/fmt/fmt.h"
// visual studio upto 2013 does not support noexcept nor constexpr
#if defined(_MSC_VER) && (_MSC_VER < 1900)
#define SPDLOG_NOEXCEPT throw()
@ -41,7 +44,29 @@
#define SPDLOG_DEPRECATED
#endif
#include "spdlog/fmt/fmt.h"
// disable thread local on msvc 2013
#ifndef SPDLOG_NO_TLS
#if (defined(_MSC_VER) && (_MSC_VER < 1900)) || defined(__cplusplus_winrt)
#define SPDLOG_NO_TLS 1
#endif
#endif
// Get the basename of __FILE__ (at compile time if possible)
#if FMT_HAS_FEATURE(__builtin_strrchr)
#define SPDLOG_STRRCHR(str, sep) __builtin_strrchr(str, sep)
#else
#define SPDLOG_STRRCHR(str, sep) strrchr(str, sep)
#endif //__builtin_strrchr not defined
#ifdef _WIN32
#define SPDLOG_FILE_BASENAME(file) SPDLOG_STRRCHR("\\" file, '\\') + 1
#else
#define SPDLOG_FILE_BASENAME(file) SPDLOG_STRRCHR("/" file, '/') + 1
#endif
#ifndef SPDLOG_FUNCTION
#define SPDLOG_FUNCTION __FUNCTION__
#endif
namespace spdlog {
@ -100,13 +125,13 @@ enum level_enum
"trace", "debug", "info", "warning", "error", "critical", "off" \
}
#endif
static const char *level_names[] SPDLOG_LEVEL_NAMES;
static string_view_t level_string_views[] SPDLOG_LEVEL_NAMES;
static const char *short_level_names[]{"T", "D", "I", "W", "E", "C", "O"};
inline const char *to_c_str(spdlog::level::level_enum l) SPDLOG_NOEXCEPT
inline string_view_t &to_string_view(spdlog::level::level_enum l) SPDLOG_NOEXCEPT
{
return level_names[l];
return level_string_views[l];
}
inline const char *to_short_c_str(spdlog::level::level_enum l) SPDLOG_NOEXCEPT
@ -116,17 +141,16 @@ inline const char *to_short_c_str(spdlog::level::level_enum l) SPDLOG_NOEXCEPT
inline spdlog::level::level_enum from_str(const std::string &name) SPDLOG_NOEXCEPT
{
static std::unordered_map<std::string, level_enum> name_to_level = // map string->level
{{level_names[0], level::trace}, // trace
{level_names[1], level::debug}, // debug
{level_names[2], level::info}, // info
{level_names[3], level::warn}, // warn
{level_names[4], level::err}, // err
{level_names[5], level::critical}, // critical
{level_names[6], level::off}}; // off
auto lvl_it = name_to_level.find(name);
return lvl_it != name_to_level.end() ? lvl_it->second : level::off;
int level = 0;
for (const auto &level_str : level_string_views)
{
if (level_str == name)
{
return static_cast<level::level_enum>(level);
}
level++;
}
return level::off;
}
using level_hasher = std::hash<int>;
@ -178,6 +202,30 @@ using filename_t = std::wstring;
using filename_t = std::string;
#endif
struct source_loc
{
SPDLOG_CONSTEXPR source_loc()
: filename{""}
, line{0}
, funcname{""}
{
}
SPDLOG_CONSTEXPR source_loc(const char *filename, int line, const char *funcname)
: filename{filename}
, line{static_cast<uint32_t>(line)}
, funcname{funcname}
{
}
SPDLOG_CONSTEXPR bool empty() const SPDLOG_NOEXCEPT
{
return line == 0;
}
const char *filename;
uint32_t line;
const char *funcname;
};
namespace details {
// make_unique support for pre c++14

@ -122,7 +122,7 @@ public:
// ".mylog" => (".mylog". "")
// "my_folder/.mylog" => ("my_folder/.mylog", "")
// "my_folder/.mylog.txt" => ("my_folder/.mylog", ".txt")
static std::tuple<filename_t, filename_t> split_by_extenstion(const spdlog::filename_t &fname)
static std::tuple<filename_t, filename_t> split_by_extension(const spdlog::filename_t &fname)
{
auto ext_index = fname.rfind('.');

@ -4,7 +4,8 @@
#pragma once
#include "chrono"
#include <chrono>
#include <type_traits>
#include "spdlog/fmt/fmt.h"
// Some fmt helpers to efficiently format and pad ints and strings
@ -17,6 +18,7 @@ inline spdlog::string_view_t to_string_view(const fmt::basic_memory_buffer<char,
{
return spdlog::string_view_t(buf.data(), buf.size());
}
template<size_t Buffer_Size1, size_t Buffer_Size2>
inline void append_buf(const fmt::basic_memory_buffer<char, Buffer_Size1> &buf, fmt::basic_memory_buffer<char, Buffer_Size2> &dest)
{
@ -41,73 +43,65 @@ inline void append_int(T n, fmt::basic_memory_buffer<char, Buffer_Size> &dest)
dest.append(i.data(), i.data() + i.size());
}
template<typename T>
inline unsigned count_digits(T n)
{
using count_type = typename std::conditional<(sizeof(T) > sizeof(uint32_t)), uint64_t, uint32_t>::type;
return static_cast<unsigned>(fmt::internal::count_digits(static_cast<count_type>(n)));
}
template<size_t Buffer_Size>
inline void pad2(int n, fmt::basic_memory_buffer<char, Buffer_Size> &dest)
{
if (n > 99)
{
append_int(n, dest);
return;
}
if (n > 9) // 10-99
else if (n > 9) // 10-99
{
dest.push_back(static_cast<char>('0' + n / 10));
dest.push_back(static_cast<char>('0' + n % 10));
return;
}
if (n >= 0) // 0-9
else if (n >= 0) // 0-9
{
dest.push_back('0');
dest.push_back(static_cast<char>('0' + n));
return;
}
// negatives (unlikely, but just in case, let fmt deal with it)
else // negatives (unlikely, but just in case, let fmt deal with it)
{
fmt::format_to(dest, "{:02}", n);
}
}
template<size_t Buffer_Size>
inline void pad3(int n, fmt::basic_memory_buffer<char, Buffer_Size> &dest)
template<typename T, size_t Buffer_Size>
inline void pad_uint(T n, unsigned int width, fmt::basic_memory_buffer<char, Buffer_Size> &dest)
{
if (n > 999)
static_assert(std::is_unsigned<T>::value, "pad_uint must get unsigned T");
auto digits = count_digits(n);
if (width > digits)
{
append_int(n, dest);
return;
const char *zeroes = "0000000000000000000";
dest.append(zeroes, zeroes + width - digits);
}
append_int(n, dest);
}
if (n > 99) // 100-999
{
dest.push_back(static_cast<char>('0' + n / 100));
pad2(n % 100, dest);
return;
}
if (n > 9) // 10-99
{
dest.push_back('0');
dest.push_back(static_cast<char>('0' + n / 10));
dest.push_back(static_cast<char>('0' + n % 10));
return;
}
if (n >= 0)
{
dest.push_back('0');
dest.push_back('0');
dest.push_back(static_cast<char>('0' + n));
return;
}
// negatives (unlikely, but just in case let fmt deal with it)
fmt::format_to(dest, "{:03}", n);
template<typename T, size_t Buffer_Size>
inline void pad3(T n, fmt::basic_memory_buffer<char, Buffer_Size> &dest)
{
pad_uint(n, 3, dest);
}
template<size_t Buffer_Size>
inline void pad6(size_t n, fmt::basic_memory_buffer<char, Buffer_Size> &dest)
template<typename T, size_t Buffer_Size>
inline void pad6(T n, fmt::basic_memory_buffer<char, Buffer_Size> &dest)
{
if (n > 99999)
{
append_int(n, dest);
return;
}
pad3(static_cast<int>(n / 1000), dest);
pad3(static_cast<int>(n % 1000), dest);
pad_uint(n, 6, dest);
}
template<typename T, size_t Buffer_Size>
inline void pad9(T n, fmt::basic_memory_buffer<char, Buffer_Size> &dest)
{
pad_uint(n, 9, dest);
}
// return fraction of a second of the given time_point.

@ -16,7 +16,7 @@ namespace details {
struct log_msg
{
log_msg(const std::string *loggers_name, level::level_enum lvl, string_view_t view)
log_msg(source_loc loc, const std::string *loggers_name, level::level_enum lvl, string_view_t view)
: logger_name(loggers_name)
, level(lvl)
#ifndef SPDLOG_NO_DATETIME
@ -25,13 +25,18 @@ struct log_msg
#ifndef SPDLOG_NO_THREAD_ID
, thread_id(os::thread_id())
, payload(view)
#endif
, source(loc)
, payload(view)
{
}
log_msg(const std::string *loggers_name, level::level_enum lvl, string_view_t view)
: log_msg(source_loc{}, loggers_name, lvl, view)
{
}
log_msg(const log_msg &other) = default;
log_msg &operator=(const log_msg &other) = default;
const std::string *logger_name{nullptr};
level::level_enum level{level::off};
@ -43,6 +48,7 @@ struct log_msg
mutable size_t color_range_start{0};
mutable size_t color_range_end{0};
source_loc source;
const string_view_t payload;
};
} // namespace details

@ -58,7 +58,7 @@ inline void spdlog::logger::set_pattern(std::string pattern, pattern_time_type t
}
template<typename... Args>
inline void spdlog::logger::log(level::level_enum lvl, const char *fmt, const Args &... args)
inline void spdlog::logger::log(source_loc source, level::level_enum lvl, const char *fmt, const Args &... args)
{
if (!should_log(lvl))
{
@ -70,13 +70,19 @@ inline void spdlog::logger::log(level::level_enum lvl, const char *fmt, const Ar
using details::fmt_helper::to_string_view;
fmt::memory_buffer buf;
fmt::format_to(buf, fmt, args...);
details::log_msg log_msg(&name_, lvl, to_string_view(buf));
details::log_msg log_msg(source, &name_, lvl, to_string_view(buf));
sink_it_(log_msg);
}
SPDLOG_CATCH_AND_HANDLE
}
inline void spdlog::logger::log(level::level_enum lvl, const char *msg)
template<typename... Args>
inline void spdlog::logger::log(level::level_enum lvl, const char *fmt, const Args &... args)
{
log(source_loc{}, lvl, fmt, args...);
}
inline void spdlog::logger::log(source_loc source, level::level_enum lvl, const char *msg)
{
if (!should_log(lvl))
{
@ -85,14 +91,19 @@ inline void spdlog::logger::log(level::level_enum lvl, const char *msg)
try
{
details::log_msg log_msg(&name_, lvl, spdlog::string_view_t(msg));
details::log_msg log_msg(source, &name_, lvl, spdlog::string_view_t(msg));
sink_it_(log_msg);
}
SPDLOG_CATCH_AND_HANDLE
}
inline void spdlog::logger::log(level::level_enum lvl, const char *msg)
{
log(source_loc{}, lvl, msg);
}
template<class T, typename std::enable_if<std::is_convertible<T, spdlog::string_view_t>::value, T>::type *>
inline void spdlog::logger::log(level::level_enum lvl, const T &msg)
inline void spdlog::logger::log(source_loc source, level::level_enum lvl, const T &msg)
{
if (!should_log(lvl))
{
@ -100,14 +111,20 @@ inline void spdlog::logger::log(level::level_enum lvl, const T &msg)
}
try
{
details::log_msg log_msg(&name_, lvl, msg);
details::log_msg log_msg(source, &name_, lvl, msg);
sink_it_(log_msg);
}
SPDLOG_CATCH_AND_HANDLE
}
template<class T, typename std::enable_if<!std::is_convertible<T, spdlog::string_view_t>::value, T>::type *>
template<class T, typename std::enable_if<std::is_convertible<T, spdlog::string_view_t>::value, T>::type *>
inline void spdlog::logger::log(level::level_enum lvl, const T &msg)
{
log(source_loc{}, lvl, msg);
}
template<class T, typename std::enable_if<!std::is_convertible<T, spdlog::string_view_t>::value, T>::type *>
inline void spdlog::logger::log(source_loc source, level::level_enum lvl, const T &msg)
{
if (!should_log(lvl))
{
@ -118,12 +135,18 @@ inline void spdlog::logger::log(level::level_enum lvl, const T &msg)
using details::fmt_helper::to_string_view;
fmt::memory_buffer buf;
fmt::format_to(buf, "{}", msg);
details::log_msg log_msg(&name_, lvl, to_string_view(buf));
details::log_msg log_msg(source, &name_, lvl, to_string_view(buf));
sink_it_(log_msg);
}
SPDLOG_CATCH_AND_HANDLE
}
template<class T, typename std::enable_if<!std::is_convertible<T, spdlog::string_view_t>::value, T>::type *>
inline void spdlog::logger::log(level::level_enum lvl, const T &msg)
{
log(source_loc{}, lvl, msg);
}
template<typename... Args>
inline void spdlog::logger::trace(const char *fmt, const Args &... args)
{
@ -220,7 +243,7 @@ inline void wbuf_to_utf8buf(const fmt::wmemory_buffer &wbuf, fmt::memory_buffer
}
template<typename... Args>
inline void spdlog::logger::log(level::level_enum lvl, const wchar_t *fmt, const Args &... args)
inline void spdlog::logger::log(source_loc source, level::level_enum lvl, const wchar_t *fmt, const Args &... args)
{
if (!should_log(lvl))
{
@ -235,12 +258,18 @@ inline void spdlog::logger::log(level::level_enum lvl, const wchar_t *fmt, const
fmt::format_to(wbuf, fmt, args...);
fmt::memory_buffer buf;
wbuf_to_utf8buf(wbuf, buf);
details::log_msg log_msg(&name_, lvl, to_string_view(buf));
details::log_msg log_msg(source, &name_, lvl, to_string_view(buf));
sink_it_(log_msg);
}
SPDLOG_CATCH_AND_HANDLE
}
template<typename... Args>
inline void spdlog::logger::log(level::level_enum lvl, const wchar_t *fmt, const Args &... args)
{
log(source_loc{}, lvl, fmt, args...);
}
template<typename... Args>
inline void spdlog::logger::trace(const wchar_t *fmt, const Args &... args)
{
@ -361,7 +390,7 @@ inline void spdlog::logger::sink_it_(details::log_msg &msg)
if (should_flush_(msg))
{
flush();
flush_();
}
}

@ -210,10 +210,10 @@ inline size_t filesize(FILE *f)
#if defined(_WIN32) && !defined(__CYGWIN__)
int fd = _fileno(f);
#if _WIN64 // 64 bits
struct _stat64 st;
if (_fstat64(fd, &st) == 0)
__int64 ret = _filelengthi64(fd);
if (ret >= 0)
{
return st.st_size;
return static_cast<size_t>(ret);
}
#else // windows 32 bits
@ -338,8 +338,7 @@ inline size_t _thread_id() SPDLOG_NOEXCEPT
// Return current thread id as size_t (from thread local storage)
inline size_t thread_id() SPDLOG_NOEXCEPT
{
#if defined(SPDLOG_DISABLE_TID_CACHING) || (defined(_MSC_VER) && (_MSC_VER < 1900)) || defined(__cplusplus_winrt) || \
(defined(__clang__) && !__has_feature(cxx_thread_local))
#if defined(SPDLOG_NO_TLS)
return _thread_id();
#else // cache thread id in tls
static thread_local const size_t tid = _thread_id();

@ -41,6 +41,11 @@ struct padding_info
, side_(side)
{
}
bool enabled() const
{
return width_ != 0;
}
const size_t width_ = 0;
const pad_side side_ = left;
};
@ -130,10 +135,17 @@ public:
}
void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override
{
if (padinfo_.enabled())
{
scoped_pad p(*msg.logger_name, padinfo_, dest);
fmt_helper::append_string_view(*msg.logger_name, dest);
}
else
{
fmt_helper::append_string_view(*msg.logger_name, dest);
}
}
};
// log level appender
@ -147,10 +159,17 @@ public:
void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override
{
string_view_t level_name{level::to_c_str(msg.level)};
string_view_t &level_name = level::to_string_view(msg.level);
if (padinfo_.enabled())
{
scoped_pad p(level_name, padinfo_, dest);
fmt_helper::append_string_view(level_name, dest);
}
else
{
fmt_helper::append_string_view(level_name, dest);
}
}
};
// short log level appender
@ -447,12 +466,18 @@ public:
: flag_formatter(padinfo){};
void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override
{
auto millis = fmt_helper::time_fraction<std::chrono::milliseconds>(msg.time);
if (padinfo_.enabled())
{
const size_t field_size = 3;
scoped_pad p(field_size, padinfo_, dest);
auto millis = fmt_helper::time_fraction<std::chrono::milliseconds>(msg.time);
fmt_helper::pad3(static_cast<int>(millis.count()), dest);
fmt_helper::pad3(static_cast<uint32_t>(millis.count()), dest);
}
else
{
fmt_helper::pad3(static_cast<uint32_t>(millis.count()), dest);
}
}
};
@ -464,13 +489,19 @@ public:
: flag_formatter(padinfo){};
void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override
{
auto micros = fmt_helper::time_fraction<std::chrono::microseconds>(msg.time);
if (padinfo_.enabled())
{
const size_t field_size = 6;
scoped_pad p(field_size, padinfo_, dest);
auto micros = fmt_helper::time_fraction<std::chrono::microseconds>(msg.time);
fmt_helper::pad6(static_cast<size_t>(micros.count()), dest);
}
else
{
fmt_helper::pad6(static_cast<size_t>(micros.count()), dest);
}
}
};
// nanoseconds
@ -481,12 +512,18 @@ public:
: flag_formatter(padinfo){};
void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override
{
auto ns = fmt_helper::time_fraction<std::chrono::nanoseconds>(msg.time);
if (padinfo_.enabled())
{
const size_t field_size = 9;
scoped_pad p(field_size, padinfo_, dest);
auto ns = fmt_helper::time_fraction<std::chrono::nanoseconds>(msg.time);
fmt::format_to(dest, "{:09}", ns.count());
fmt_helper::pad9(static_cast<size_t>(ns.count()), dest);
}
else
{
fmt_helper::pad9(static_cast<size_t>(ns.count()), dest);
}
}
};
@ -501,7 +538,6 @@ public:
{
const size_t field_size = 10;
scoped_pad p(field_size, padinfo_, dest);
auto duration = msg.time.time_since_epoch();
auto seconds = std::chrono::duration_cast<std::chrono::seconds>(duration).count();
fmt_helper::append_int(seconds, dest);
@ -572,7 +608,6 @@ public:
void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override
{
const size_t field_size = 8;
scoped_pad p(field_size, padinfo_, dest);
@ -652,9 +687,16 @@ public:
void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override
{
const size_t field_size = 6;
if (padinfo_.enabled())
{
const auto field_size = fmt_helper::count_digits(msg.thread_id);
scoped_pad p(field_size, padinfo_, dest);
fmt_helper::pad6(msg.thread_id, dest);
fmt_helper::append_int(msg.thread_id, dest);
}
else
{
fmt_helper::append_int(msg.thread_id, dest);
}
}
};
@ -667,9 +709,17 @@ public:
void format(const details::log_msg &, const std::tm &, fmt::memory_buffer &dest) override
{
const size_t field_size = 6;
const auto pid = static_cast<uint32_t>(details::os::pid());
if (padinfo_.enabled())
{
auto field_size = fmt_helper::count_digits(pid);
scoped_pad p(field_size, padinfo_, dest);
fmt_helper::pad6(static_cast<size_t>(details::os::pid()), dest);
fmt_helper::append_int(pid, dest);
}
else
{
fmt_helper::append_int(pid, dest);
}
}
};
@ -695,15 +745,21 @@ public:
: flag_formatter(padinfo){};
void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override
{
if (padinfo_.enabled())
{
scoped_pad p(msg.payload, padinfo_, dest);
fmt_helper::append_string_view(msg.payload, dest);
}
else
{
fmt_helper::append_string_view(msg.payload, dest);
}
}
};
class ch_formatter final : public flag_formatter
{
public:
public:
explicit ch_formatter(char ch)
: ch_(ch)
@ -768,6 +824,95 @@ public:
}
};
// print source location
class source_location_formatter final : public flag_formatter
{
public:
explicit source_location_formatter(padding_info padinfo)
: flag_formatter(padinfo){};
void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override
{
if (msg.source.empty())
{
return;
}
if (padinfo_.enabled())
{
const auto text_size = std::char_traits<char>::length(msg.source.filename) + fmt_helper::count_digits(msg.source.line) + 1;
scoped_pad p(text_size, padinfo_, dest);
fmt_helper::append_string_view(msg.source.filename, dest);
dest.push_back(':');
fmt_helper::append_int(msg.source.line, dest);
}
else
{
fmt_helper::append_string_view(msg.source.filename, dest);
dest.push_back(':');
fmt_helper::append_int(msg.source.line, dest);
}
}
};
// print source filename
class source_filename_formatter final : public flag_formatter
{
public:
explicit source_filename_formatter(padding_info padinfo)
: flag_formatter(padinfo){};
void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override
{
if (msg.source.empty())
{
return;
}
scoped_pad p(msg.source.filename, padinfo_, dest);
fmt_helper::append_string_view(msg.source.filename, dest);
}
};
class source_linenum_formatter final : public flag_formatter
{
public:
explicit source_linenum_formatter(padding_info padinfo)
: flag_formatter(padinfo){};
void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override
{
if (msg.source.empty())
{
return;
}
if (padinfo_.enabled())
{
auto field_size = fmt_helper::count_digits(msg.source.line);
scoped_pad p(field_size, padinfo_, dest);
fmt_helper::append_int(msg.source.line, dest);
}
else
{
fmt_helper::append_int(msg.source.line, dest);
}
}
};
// print source funcname
class source_funcname_formatter final : public flag_formatter
{
public:
explicit source_funcname_formatter(padding_info padinfo)
: flag_formatter(padinfo){};
void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override
{
if (msg.source.empty())
{
return;
}
scoped_pad p(msg.source.funcname, padinfo_, dest);
fmt_helper::append_string_view(msg.source.funcname, dest);
}
};
// Full info formatter
// pattern: [%Y-%m-%d %H:%M:%S.%e] [%n] [%l] %v
class full_formatter final : public flag_formatter
@ -817,7 +962,7 @@ public:
fmt_helper::append_buf(cached_datetime_, dest);
auto millis = fmt_helper::time_fraction<milliseconds>(msg.time);
fmt_helper::pad3(static_cast<int>(millis.count()), dest);
fmt_helper::pad3(static_cast<uint32_t>(millis.count()), dest);
dest.push_back(']');
dest.push_back(' ');
@ -840,10 +985,21 @@ public:
// wrap the level name with color
msg.color_range_start = dest.size();
// fmt_helper::append_string_view(level::to_c_str(msg.level), dest);
fmt_helper::append_string_view(level::to_c_str(msg.level), dest);
fmt_helper::append_string_view(level::to_string_view(msg.level), dest);
msg.color_range_end = dest.size();
dest.push_back(']');
dest.push_back(' ');
// add source location if present
if (!msg.source.empty())
{
dest.push_back('[');
fmt_helper::append_string_view(msg.source.filename, dest);
dest.push_back(':');
fmt_helper::append_int(msg.source.line, dest);
dest.push_back(']');
dest.push_back(' ');
}
// fmt_helper::append_string_view(msg.msg(), dest);
fmt_helper::append_string_view(msg.payload, dest);
}
@ -928,141 +1084,160 @@ private:
{
switch (flag)
{
// logger name
case 'n':
case ('+'): // default formatter
formatters_.push_back(details::make_unique<details::full_formatter>(padding));
break;
case 'n': // logger name
formatters_.push_back(details::make_unique<details::name_formatter>(padding));
break;
case 'l':
case 'l': // level
formatters_.push_back(details::make_unique<details::level_formatter>(padding));
break;
case 'L':
case 'L': // short level
formatters_.push_back(details::make_unique<details::short_level_formatter>(padding));
break;
case ('t'):
case ('t'): // thread id
formatters_.push_back(details::make_unique<details::t_formatter>(padding));
break;
case ('v'):
case ('v'): // the message text
formatters_.push_back(details::make_unique<details::v_formatter>(padding));
break;
case ('a'):
case ('a'): // weekday
formatters_.push_back(details::make_unique<details::a_formatter>(padding));
break;
case ('A'):
case ('A'): // short weekday
formatters_.push_back(details::make_unique<details::A_formatter>(padding));
break;
case ('b'):
case ('h'):
case ('h'): // month
formatters_.push_back(details::make_unique<details::b_formatter>(padding));
break;
case ('B'):
case ('B'): // short month
formatters_.push_back(details::make_unique<details::B_formatter>(padding));
break;
case ('c'):
case ('c'): // datetime
formatters_.push_back(details::make_unique<details::c_formatter>(padding));
break;
case ('C'):
case ('C'): // year 2 digits
formatters_.push_back(details::make_unique<details::C_formatter>(padding));
break;
case ('Y'):
case ('Y'): // year 4 digits
formatters_.push_back(details::make_unique<details::Y_formatter>(padding));
break;
case ('D'):
case ('x'):
case ('x'): // datetime MM/DD/YY
formatters_.push_back(details::make_unique<details::D_formatter>(padding));
break;
case ('m'):
case ('m'): // month 1-12
formatters_.push_back(details::make_unique<details::m_formatter>(padding));
break;
case ('d'):
case ('d'): // day of month 1-31
formatters_.push_back(details::make_unique<details::d_formatter>(padding));
break;
case ('H'):
case ('H'): // hours 24
formatters_.push_back(details::make_unique<details::H_formatter>(padding));
break;
case ('I'):
case ('I'): // hours 12
formatters_.push_back(details::make_unique<details::I_formatter>(padding));
break;
case ('M'):
case ('M'): // minutes
formatters_.push_back(details::make_unique<details::M_formatter>(padding));
break;
case ('S'):
case ('S'): // seconds
formatters_.push_back(details::make_unique<details::S_formatter>(padding));
break;
case ('e'):
case ('e'): // milliseconds
formatters_.push_back(details::make_unique<details::e_formatter>(padding));
break;
case ('f'):
case ('f'): // microseconds
formatters_.push_back(details::make_unique<details::f_formatter>(padding));
break;
case ('F'):
case ('F'): // nanoseconds
formatters_.push_back(details::make_unique<details::F_formatter>(padding));
break;
case ('E'):
case ('E'): // seconds since epoch
formatters_.push_back(details::make_unique<details::E_formatter>(padding));
break;
case ('p'):
case ('p'): // am/pm
formatters_.push_back(details::make_unique<details::p_formatter>(padding));
break;
case ('r'):
case ('r'): // 12 hour clock 02:55:02 pm
formatters_.push_back(details::make_unique<details::r_formatter>(padding));
break;
case ('R'):
case ('R'): // 24-hour HH:MM time
formatters_.push_back(details::make_unique<details::R_formatter>(padding));
break;
case ('T'):
case ('X'):
case ('X'): // ISO 8601 time format (HH:MM:SS)
formatters_.push_back(details::make_unique<details::T_formatter>(padding));
break;
case ('z'):
case ('z'): // timezone
formatters_.push_back(details::make_unique<details::z_formatter>(padding));
break;
case ('+'):
formatters_.push_back(details::make_unique<details::full_formatter>(padding));
break;
case ('P'):
case ('P'): // pid
formatters_.push_back(details::make_unique<details::pid_formatter>(padding));
break;
#ifdef SPDLOG_ENABLE_MESSAGE_COUNTER
case ('i'):
formatters_.push_back(details::make_unique<details::i_formatter>(padding));
break;
#endif
case ('^'):
case ('^'): // color range start
formatters_.push_back(details::make_unique<details::color_start_formatter>(padding));
break;
case ('$'):
case ('$'): // color range end
formatters_.push_back(details::make_unique<details::color_stop_formatter>(padding));
break;
case ('%'):
case ('@'): // source location (filename:filenumber)
formatters_.push_back(details::make_unique<details::source_location_formatter>(padding));
break;
case ('s'): // source filename
formatters_.push_back(details::make_unique<details::source_filename_formatter>(padding));
break;
case ('#'): // source line number
formatters_.push_back(details::make_unique<details::source_linenum_formatter>(padding));
break;
case ('!'): // source funcname
formatters_.push_back(details::make_unique<details::source_funcname_formatter>(padding));
break;
case ('%'): // % char
formatters_.push_back(details::make_unique<details::ch_formatter>('%'));
break;

@ -33,6 +33,7 @@ struct async_msg
fmt::basic_memory_buffer<char, 176> raw;
size_t msg_id;
source_loc source;
async_logger_ptr worker_ptr;
async_msg() = default;
@ -49,6 +50,7 @@ struct async_msg
thread_id(other.thread_id),
raw(move(other.raw)),
msg_id(other.msg_id),
source(other.source),
worker_ptr(std::move(other.worker_ptr))
{
}
@ -61,6 +63,7 @@ struct async_msg
thread_id = other.thread_id;
raw = std::move(other.raw);
msg_id = other.msg_id;
source = other.source;
worker_ptr = std::move(other.worker_ptr);
return *this;
}
@ -76,6 +79,7 @@ struct async_msg
, time(m.time)
, thread_id(m.thread_id)
, msg_id(m.msg_id)
, source(m.source)
, worker_ptr(std::move(worker))
{
fmt_helper::append_string_view(m.payload, raw);
@ -87,6 +91,7 @@ struct async_msg
, time()
, thread_id(0)
, msg_id(0)
, source()
, worker_ptr(std::move(worker))
{
}
@ -103,6 +108,7 @@ struct async_msg
msg.time = time;
msg.thread_id = thread_id;
msg.msg_id = msg_id;
msg.source = source;
msg.color_range_start = 0;
msg.color_range_end = 0;
return msg;

@ -0,0 +1,452 @@
// Formatting library for C++ - chrono support
//
// Copyright (c) 2012 - present, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
#ifndef FMT_CHRONO_H_
#define FMT_CHRONO_H_
#include "format.h"
#include "locale.h"
#include <chrono>
#include <ctime>
#include <locale>
#include <sstream>
FMT_BEGIN_NAMESPACE
namespace internal{
enum class numeric_system {
standard,
// Alternative numeric system, e.g. 十二 instead of 12 in ja_JP locale.
alternative
};
// Parses a put_time-like format string and invokes handler actions.
template <typename Char, typename Handler>
FMT_CONSTEXPR const Char *parse_chrono_format(
const Char *begin, const Char *end, Handler &&handler) {
auto ptr = begin;
while (ptr != end) {
auto c = *ptr;
if (c == '}') break;
if (c != '%') {
++ptr;
continue;
}
if (begin != ptr)
handler.on_text(begin, ptr);
++ptr; // consume '%'
if (ptr == end)
throw format_error("invalid format");
c = *ptr++;
switch (c) {
case '%':
handler.on_text(ptr - 1, ptr);
break;
case 'n': {
const char newline[] = "\n";
handler.on_text(newline, newline + 1);
break;
}
case 't': {
const char tab[] = "\t";
handler.on_text(tab, tab + 1);
break;
}
// Day of the week:
case 'a':
handler.on_abbr_weekday();
break;
case 'A':
handler.on_full_weekday();
break;
case 'w':
handler.on_dec0_weekday(numeric_system::standard);
break;
case 'u':
handler.on_dec1_weekday(numeric_system::standard);
break;
// Month:
case 'b':
handler.on_abbr_month();
break;
case 'B':
handler.on_full_month();
break;
// Hour, minute, second:
case 'H':
handler.on_24_hour(numeric_system::standard);
break;
case 'I':
handler.on_12_hour(numeric_system::standard);
break;
case 'M':
handler.on_minute(numeric_system::standard);
break;
case 'S':
handler.on_second(numeric_system::standard);
break;
// Other:
case 'c':
handler.on_datetime(numeric_system::standard);
break;
case 'x':
handler.on_loc_date(numeric_system::standard);
break;
case 'X':
handler.on_loc_time(numeric_system::standard);
break;
case 'D':
handler.on_us_date();
break;
case 'F':
handler.on_iso_date();
break;
case 'r':
handler.on_12_hour_time();
break;
case 'R':
handler.on_24_hour_time();
break;
case 'T':
handler.on_iso_time();
break;
case 'p':
handler.on_am_pm();
break;
case 'z':
handler.on_utc_offset();
break;
case 'Z':
handler.on_tz_name();
break;
// Alternative representation:
case 'E': {
if (ptr == end)
throw format_error("invalid format");
c = *ptr++;
switch (c) {
case 'c':
handler.on_datetime(numeric_system::alternative);
break;
case 'x':
handler.on_loc_date(numeric_system::alternative);
break;
case 'X':
handler.on_loc_time(numeric_system::alternative);
break;
default:
throw format_error("invalid format");
}
break;
}
case 'O':
if (ptr == end)
throw format_error("invalid format");
c = *ptr++;
switch (c) {
case 'w':
handler.on_dec0_weekday(numeric_system::alternative);
break;
case 'u':
handler.on_dec1_weekday(numeric_system::alternative);
break;
case 'H':
handler.on_24_hour(numeric_system::alternative);
break;
case 'I':
handler.on_12_hour(numeric_system::alternative);
break;
case 'M':
handler.on_minute(numeric_system::alternative);
break;
case 'S':
handler.on_second(numeric_system::alternative);
break;
default:
throw format_error("invalid format");
}
break;
default:
throw format_error("invalid format");
}
begin = ptr;
}
if (begin != ptr)
handler.on_text(begin, ptr);
return ptr;
}
struct chrono_format_checker {
void report_no_date() { throw format_error("no date"); }
template <typename Char>
void on_text(const Char *, const Char *) {}
void on_abbr_weekday() { report_no_date(); }
void on_full_weekday() { report_no_date(); }
void on_dec0_weekday(numeric_system) { report_no_date(); }
void on_dec1_weekday(numeric_system) { report_no_date(); }
void on_abbr_month() { report_no_date(); }
void on_full_month() { report_no_date(); }
void on_24_hour(numeric_system) {}
void on_12_hour(numeric_system) {}
void on_minute(numeric_system) {}
void on_second(numeric_system) {}
void on_datetime(numeric_system) { report_no_date(); }
void on_loc_date(numeric_system) { report_no_date(); }
void on_loc_time(numeric_system) { report_no_date(); }
void on_us_date() { report_no_date(); }
void on_iso_date() { report_no_date(); }
void on_12_hour_time() {}
void on_24_hour_time() {}
void on_iso_time() {}
void on_am_pm() {}
void on_utc_offset() { report_no_date(); }
void on_tz_name() { report_no_date(); }
};
template <typename Int>
inline int to_int(Int value) {
FMT_ASSERT(value >= (std::numeric_limits<int>::min)() &&
value <= (std::numeric_limits<int>::max)(), "invalid value");
return static_cast<int>(value);
}
template <typename FormatContext, typename OutputIt>
struct chrono_formatter {
FormatContext &context;
OutputIt out;
std::chrono::seconds s;
std::chrono::milliseconds ms;
typedef typename FormatContext::char_type char_type;
explicit chrono_formatter(FormatContext &ctx, OutputIt o)
: context(ctx), out(o) {}
int hour() const { return to_int((s.count() / 3600) % 24); }
int hour12() const {
auto hour = to_int((s.count() / 3600) % 12);
return hour > 0 ? hour : 12;
}
int minute() const { return to_int((s.count() / 60) % 60); }
int second() const { return to_int(s.count() % 60); }
std::tm time() const {
auto time = std::tm();
time.tm_hour = hour();
time.tm_min = minute();
time.tm_sec = second();
return time;
}
void write(int value, int width) {
typedef typename int_traits<int>::main_type main_type;
main_type n = to_unsigned(value);
int num_digits = internal::count_digits(n);
if (width > num_digits)
out = std::fill_n(out, width - num_digits, '0');
out = format_decimal<char_type>(out, n, num_digits);
}
void format_localized(const tm &time, const char *format) {
auto locale = context.locale().template get<std::locale>();
auto &facet = std::use_facet<std::time_put<char_type>>(locale);
std::basic_ostringstream<char_type> os;
os.imbue(locale);
facet.put(os, os, ' ', &time, format, format + std::strlen(format));
auto str = os.str();
std::copy(str.begin(), str.end(), out);
}
void on_text(const char_type *begin, const char_type *end) {
std::copy(begin, end, out);
}
// These are not implemented because durations don't have date information.
void on_abbr_weekday() {}
void on_full_weekday() {}
void on_dec0_weekday(numeric_system) {}
void on_dec1_weekday(numeric_system) {}
void on_abbr_month() {}
void on_full_month() {}
void on_datetime(numeric_system) {}
void on_loc_date(numeric_system) {}
void on_loc_time(numeric_system) {}
void on_us_date() {}
void on_iso_date() {}
void on_utc_offset() {}
void on_tz_name() {}
void on_24_hour(numeric_system ns) {
if (ns == numeric_system::standard)
return write(hour(), 2);
auto time = tm();
time.tm_hour = hour();
format_localized(time, "%OH");
}
void on_12_hour(numeric_system ns) {
if (ns == numeric_system::standard)
return write(hour12(), 2);
auto time = tm();
time.tm_hour = hour();
format_localized(time, "%OI");
}
void on_minute(numeric_system ns) {
if (ns == numeric_system::standard)
return write(minute(), 2);
auto time = tm();
time.tm_min = minute();
format_localized(time, "%OM");
}
void on_second(numeric_system ns) {
if (ns == numeric_system::standard) {
write(second(), 2);
if (ms != std::chrono::milliseconds(0)) {
*out++ = '.';
write(to_int(ms.count()), 3);
}
return;
}
auto time = tm();
time.tm_sec = second();
format_localized(time, "%OS");
}
void on_12_hour_time() { format_localized(time(), "%r"); }
void on_24_hour_time() {
write(hour(), 2);
*out++ = ':';
write(minute(), 2);
}
void on_iso_time() {
on_24_hour_time();
*out++ = ':';
write(second(), 2);
}
void on_am_pm() { format_localized(time(), "%p"); }
};
} // namespace internal
template <typename Period> FMT_CONSTEXPR const char *get_units() {
return FMT_NULL;
}
template <> FMT_CONSTEXPR const char *get_units<std::atto>() { return "as"; }
template <> FMT_CONSTEXPR const char *get_units<std::femto>() { return "fs"; }
template <> FMT_CONSTEXPR const char *get_units<std::pico>() { return "ps"; }
template <> FMT_CONSTEXPR const char *get_units<std::nano>() { return "ns"; }
template <> FMT_CONSTEXPR const char *get_units<std::micro>() { return "µs"; }
template <> FMT_CONSTEXPR const char *get_units<std::milli>() { return "ms"; }
template <> FMT_CONSTEXPR const char *get_units<std::centi>() { return "cs"; }
template <> FMT_CONSTEXPR const char *get_units<std::deci>() { return "ds"; }
template <> FMT_CONSTEXPR const char *get_units<std::ratio<1>>() { return "s"; }
template <> FMT_CONSTEXPR const char *get_units<std::deca>() { return "das"; }
template <> FMT_CONSTEXPR const char *get_units<std::hecto>() { return "hs"; }
template <> FMT_CONSTEXPR const char *get_units<std::kilo>() { return "ks"; }
template <> FMT_CONSTEXPR const char *get_units<std::mega>() { return "Ms"; }
template <> FMT_CONSTEXPR const char *get_units<std::giga>() { return "Gs"; }
template <> FMT_CONSTEXPR const char *get_units<std::tera>() { return "Ts"; }
template <> FMT_CONSTEXPR const char *get_units<std::peta>() { return "Ps"; }
template <> FMT_CONSTEXPR const char *get_units<std::exa>() { return "Es"; }
template <> FMT_CONSTEXPR const char *get_units<std::ratio<60>>() {
return "m";
}
template <> FMT_CONSTEXPR const char *get_units<std::ratio<3600>>() {
return "h";
}
template <typename Rep, typename Period, typename Char>
struct formatter<std::chrono::duration<Rep, Period>, Char> {
private:
align_spec spec;
internal::arg_ref<Char> width_ref;
mutable basic_string_view<Char> format_str;
typedef std::chrono::duration<Rep, Period> duration;
struct spec_handler {
formatter &f;
basic_parse_context<Char> &context;
typedef internal::arg_ref<Char> arg_ref_type;
template <typename Id>
FMT_CONSTEXPR arg_ref_type make_arg_ref(Id arg_id) {
context.check_arg_id(arg_id);
return arg_ref_type(arg_id);
}
FMT_CONSTEXPR arg_ref_type make_arg_ref(internal::auto_id) {
return arg_ref_type(context.next_arg_id());
}
void on_error(const char *msg) { throw format_error(msg); }
void on_fill(Char fill) { f.spec.fill_ = fill; }
void on_align(alignment align) { f.spec.align_ = align; }
void on_width(unsigned width) { f.spec.width_ = width; }
template <typename Id>
void on_dynamic_width(Id arg_id) {
f.width_ref = make_arg_ref(arg_id);
}
};
public:
formatter() : spec() {}
FMT_CONSTEXPR auto parse(basic_parse_context<Char> &ctx)
-> decltype(ctx.begin()) {
auto begin = ctx.begin(), end = ctx.end();
if (begin == end) return begin;
spec_handler handler{*this, ctx};
begin = internal::parse_align(begin, end, handler);
if (begin == end) return begin;
begin = internal::parse_width(begin, end, handler);
end = parse_chrono_format(begin, end, internal::chrono_format_checker());
format_str = basic_string_view<Char>(&*begin, internal::to_unsigned(end - begin));
return end;
}
template <typename FormatContext>
auto format(const duration &d, FormatContext &ctx)
-> decltype(ctx.out()) {
auto begin = format_str.begin(), end = format_str.end();
memory_buffer buf;
typedef output_range<decltype(ctx.out()), Char> range;
basic_writer<range> w(range(ctx.out()));
if (begin == end || *begin == '}') {
if (const char *unit = get_units<Period>())
format_to(buf, "{}{}", d.count(), unit);
else if (Period::den == 1)
format_to(buf, "{}[{}]s", d.count(), Period::num);
else
format_to(buf, "{}[{}/{}]s", d.count(), Period::num, Period::den);
internal::handle_dynamic_spec<internal::width_checker>(
spec.width_, width_ref, ctx);
} else {
auto out = std::back_inserter(buf);
internal::chrono_formatter<FormatContext, decltype(out)> f(ctx, out);
f.s = std::chrono::duration_cast<std::chrono::seconds>(d);
f.ms = std::chrono::duration_cast<std::chrono::milliseconds>(d - f.s);
parse_chrono_format(begin, end, f);
}
w.write(buf.data(), buf.size(), spec);
return w.out();
}
};
FMT_END_NAMESPACE
#endif // FMT_CHRONO_H_

@ -0,0 +1,577 @@
// Formatting library for C++ - color support
//
// Copyright (c) 2018 - present, Victor Zverovich and fmt contributors
// All rights reserved.
//
// For the license information refer to format.h.
#ifndef FMT_COLOR_H_
#define FMT_COLOR_H_
#include "format.h"
FMT_BEGIN_NAMESPACE
#ifdef FMT_DEPRECATED_COLORS
// color and (v)print_colored are deprecated.
enum color { black, red, green, yellow, blue, magenta, cyan, white };
FMT_API void vprint_colored(color c, string_view format, format_args args);
FMT_API void vprint_colored(color c, wstring_view format, wformat_args args);
template <typename... Args>
inline void print_colored(color c, string_view format_str,
const Args & ... args) {
vprint_colored(c, format_str, make_format_args(args...));
}
template <typename... Args>
inline void print_colored(color c, wstring_view format_str,
const Args & ... args) {
vprint_colored(c, format_str, make_format_args<wformat_context>(args...));
}
inline void vprint_colored(color c, string_view format, format_args args) {
char escape[] = "\x1b[30m";
escape[3] = static_cast<char>('0' + c);
std::fputs(escape, stdout);
vprint(format, args);
std::fputs(internal::data::RESET_COLOR, stdout);
}
inline void vprint_colored(color c, wstring_view format, wformat_args args) {
wchar_t escape[] = L"\x1b[30m";
escape[3] = static_cast<wchar_t>('0' + c);
std::fputws(escape, stdout);
vprint(format, args);
std::fputws(internal::data::WRESET_COLOR, stdout);
}
#else
enum class color : uint32_t {
alice_blue = 0xF0F8FF, // rgb(240,248,255)
antique_white = 0xFAEBD7, // rgb(250,235,215)
aqua = 0x00FFFF, // rgb(0,255,255)
aquamarine = 0x7FFFD4, // rgb(127,255,212)
azure = 0xF0FFFF, // rgb(240,255,255)
beige = 0xF5F5DC, // rgb(245,245,220)
bisque = 0xFFE4C4, // rgb(255,228,196)
black = 0x000000, // rgb(0,0,0)
blanched_almond = 0xFFEBCD, // rgb(255,235,205)
blue = 0x0000FF, // rgb(0,0,255)
blue_violet = 0x8A2BE2, // rgb(138,43,226)
brown = 0xA52A2A, // rgb(165,42,42)
burly_wood = 0xDEB887, // rgb(222,184,135)
cadet_blue = 0x5F9EA0, // rgb(95,158,160)
chartreuse = 0x7FFF00, // rgb(127,255,0)
chocolate = 0xD2691E, // rgb(210,105,30)
coral = 0xFF7F50, // rgb(255,127,80)
cornflower_blue = 0x6495ED, // rgb(100,149,237)
cornsilk = 0xFFF8DC, // rgb(255,248,220)
crimson = 0xDC143C, // rgb(220,20,60)
cyan = 0x00FFFF, // rgb(0,255,255)
dark_blue = 0x00008B, // rgb(0,0,139)
dark_cyan = 0x008B8B, // rgb(0,139,139)
dark_golden_rod = 0xB8860B, // rgb(184,134,11)
dark_gray = 0xA9A9A9, // rgb(169,169,169)
dark_green = 0x006400, // rgb(0,100,0)
dark_khaki = 0xBDB76B, // rgb(189,183,107)
dark_magenta = 0x8B008B, // rgb(139,0,139)
dark_olive_green = 0x556B2F, // rgb(85,107,47)
dark_orange = 0xFF8C00, // rgb(255,140,0)
dark_orchid = 0x9932CC, // rgb(153,50,204)
dark_red = 0x8B0000, // rgb(139,0,0)
dark_salmon = 0xE9967A, // rgb(233,150,122)
dark_sea_green = 0x8FBC8F, // rgb(143,188,143)
dark_slate_blue = 0x483D8B, // rgb(72,61,139)
dark_slate_gray = 0x2F4F4F, // rgb(47,79,79)
dark_turquoise = 0x00CED1, // rgb(0,206,209)
dark_violet = 0x9400D3, // rgb(148,0,211)
deep_pink = 0xFF1493, // rgb(255,20,147)
deep_sky_blue = 0x00BFFF, // rgb(0,191,255)
dim_gray = 0x696969, // rgb(105,105,105)
dodger_blue = 0x1E90FF, // rgb(30,144,255)
fire_brick = 0xB22222, // rgb(178,34,34)
floral_white = 0xFFFAF0, // rgb(255,250,240)
forest_green = 0x228B22, // rgb(34,139,34)
fuchsia = 0xFF00FF, // rgb(255,0,255)
gainsboro = 0xDCDCDC, // rgb(220,220,220)
ghost_white = 0xF8F8FF, // rgb(248,248,255)
gold = 0xFFD700, // rgb(255,215,0)
golden_rod = 0xDAA520, // rgb(218,165,32)
gray = 0x808080, // rgb(128,128,128)
green = 0x008000, // rgb(0,128,0)
green_yellow = 0xADFF2F, // rgb(173,255,47)
honey_dew = 0xF0FFF0, // rgb(240,255,240)
hot_pink = 0xFF69B4, // rgb(255,105,180)
indian_red = 0xCD5C5C, // rgb(205,92,92)
indigo = 0x4B0082, // rgb(75,0,130)
ivory = 0xFFFFF0, // rgb(255,255,240)
khaki = 0xF0E68C, // rgb(240,230,140)
lavender = 0xE6E6FA, // rgb(230,230,250)
lavender_blush = 0xFFF0F5, // rgb(255,240,245)
lawn_green = 0x7CFC00, // rgb(124,252,0)
lemon_chiffon = 0xFFFACD, // rgb(255,250,205)
light_blue = 0xADD8E6, // rgb(173,216,230)
light_coral = 0xF08080, // rgb(240,128,128)
light_cyan = 0xE0FFFF, // rgb(224,255,255)
light_golden_rod_yellow = 0xFAFAD2, // rgb(250,250,210)
light_gray = 0xD3D3D3, // rgb(211,211,211)
light_green = 0x90EE90, // rgb(144,238,144)
light_pink = 0xFFB6C1, // rgb(255,182,193)
light_salmon = 0xFFA07A, // rgb(255,160,122)
light_sea_green = 0x20B2AA, // rgb(32,178,170)
light_sky_blue = 0x87CEFA, // rgb(135,206,250)
light_slate_gray = 0x778899, // rgb(119,136,153)
light_steel_blue = 0xB0C4DE, // rgb(176,196,222)
light_yellow = 0xFFFFE0, // rgb(255,255,224)
lime = 0x00FF00, // rgb(0,255,0)
lime_green = 0x32CD32, // rgb(50,205,50)
linen = 0xFAF0E6, // rgb(250,240,230)
magenta = 0xFF00FF, // rgb(255,0,255)
maroon = 0x800000, // rgb(128,0,0)
medium_aquamarine = 0x66CDAA, // rgb(102,205,170)
medium_blue = 0x0000CD, // rgb(0,0,205)
medium_orchid = 0xBA55D3, // rgb(186,85,211)
medium_purple = 0x9370DB, // rgb(147,112,219)
medium_sea_green = 0x3CB371, // rgb(60,179,113)
medium_slate_blue = 0x7B68EE, // rgb(123,104,238)
medium_spring_green = 0x00FA9A, // rgb(0,250,154)
medium_turquoise = 0x48D1CC, // rgb(72,209,204)
medium_violet_red = 0xC71585, // rgb(199,21,133)
midnight_blue = 0x191970, // rgb(25,25,112)
mint_cream = 0xF5FFFA, // rgb(245,255,250)
misty_rose = 0xFFE4E1, // rgb(255,228,225)
moccasin = 0xFFE4B5, // rgb(255,228,181)
navajo_white = 0xFFDEAD, // rgb(255,222,173)
navy = 0x000080, // rgb(0,0,128)
old_lace = 0xFDF5E6, // rgb(253,245,230)
olive = 0x808000, // rgb(128,128,0)
olive_drab = 0x6B8E23, // rgb(107,142,35)
orange = 0xFFA500, // rgb(255,165,0)
orange_red = 0xFF4500, // rgb(255,69,0)
orchid = 0xDA70D6, // rgb(218,112,214)
pale_golden_rod = 0xEEE8AA, // rgb(238,232,170)
pale_green = 0x98FB98, // rgb(152,251,152)
pale_turquoise = 0xAFEEEE, // rgb(175,238,238)
pale_violet_red = 0xDB7093, // rgb(219,112,147)
papaya_whip = 0xFFEFD5, // rgb(255,239,213)
peach_puff = 0xFFDAB9, // rgb(255,218,185)
peru = 0xCD853F, // rgb(205,133,63)
pink = 0xFFC0CB, // rgb(255,192,203)
plum = 0xDDA0DD, // rgb(221,160,221)
powder_blue = 0xB0E0E6, // rgb(176,224,230)
purple = 0x800080, // rgb(128,0,128)
rebecca_purple = 0x663399, // rgb(102,51,153)
red = 0xFF0000, // rgb(255,0,0)
rosy_brown = 0xBC8F8F, // rgb(188,143,143)
royal_blue = 0x4169E1, // rgb(65,105,225)
saddle_brown = 0x8B4513, // rgb(139,69,19)
salmon = 0xFA8072, // rgb(250,128,114)
sandy_brown = 0xF4A460, // rgb(244,164,96)
sea_green = 0x2E8B57, // rgb(46,139,87)
sea_shell = 0xFFF5EE, // rgb(255,245,238)
sienna = 0xA0522D, // rgb(160,82,45)
silver = 0xC0C0C0, // rgb(192,192,192)
sky_blue = 0x87CEEB, // rgb(135,206,235)
slate_blue = 0x6A5ACD, // rgb(106,90,205)
slate_gray = 0x708090, // rgb(112,128,144)
snow = 0xFFFAFA, // rgb(255,250,250)
spring_green = 0x00FF7F, // rgb(0,255,127)
steel_blue = 0x4682B4, // rgb(70,130,180)
tan = 0xD2B48C, // rgb(210,180,140)
teal = 0x008080, // rgb(0,128,128)
thistle = 0xD8BFD8, // rgb(216,191,216)
tomato = 0xFF6347, // rgb(255,99,71)
turquoise = 0x40E0D0, // rgb(64,224,208)
violet = 0xEE82EE, // rgb(238,130,238)
wheat = 0xF5DEB3, // rgb(245,222,179)
white = 0xFFFFFF, // rgb(255,255,255)
white_smoke = 0xF5F5F5, // rgb(245,245,245)
yellow = 0xFFFF00, // rgb(255,255,0)
yellow_green = 0x9ACD32 // rgb(154,205,50)
}; // enum class color
enum class terminal_color : uint8_t {
black = 30,
red,
green,
yellow,
blue,
magenta,
cyan,
white,
bright_black = 90,
bright_red,
bright_green,
bright_yellow,
bright_blue,
bright_magenta,
bright_cyan,
bright_white
}; // enum class terminal_color
enum class emphasis : uint8_t {
bold = 1,
italic = 1 << 1,
underline = 1 << 2,
strikethrough = 1 << 3
}; // enum class emphasis
// rgb is a struct for red, green and blue colors.
// We use rgb as name because some editors will show it as color direct in the
// editor.
struct rgb {
FMT_CONSTEXPR_DECL rgb() : r(0), g(0), b(0) {}
FMT_CONSTEXPR_DECL rgb(uint8_t r_, uint8_t g_, uint8_t b_)
: r(r_), g(g_), b(b_) {}
FMT_CONSTEXPR_DECL rgb(uint32_t hex)
: r((hex >> 16) & 0xFF), g((hex >> 8) & 0xFF), b((hex) & 0xFF) {}
FMT_CONSTEXPR_DECL rgb(color hex)
: r((uint32_t(hex) >> 16) & 0xFF), g((uint32_t(hex) >> 8) & 0xFF),
b(uint32_t(hex) & 0xFF) {}
uint8_t r;
uint8_t g;
uint8_t b;
};
namespace internal {
// color is a struct of either a rgb color or a terminal color.
struct color_type {
FMT_CONSTEXPR color_type() FMT_NOEXCEPT
: is_rgb(), value{} {}
FMT_CONSTEXPR color_type(color rgb_color) FMT_NOEXCEPT
: is_rgb(true), value{} {
value.rgb_color = static_cast<uint32_t>(rgb_color);
}
FMT_CONSTEXPR color_type(rgb rgb_color) FMT_NOEXCEPT
: is_rgb(true), value{} {
value.rgb_color = (static_cast<uint32_t>(rgb_color.r) << 16)
| (static_cast<uint32_t>(rgb_color.g) << 8) | rgb_color.b;
}
FMT_CONSTEXPR color_type(terminal_color term_color) FMT_NOEXCEPT
: is_rgb(), value{} {
value.term_color = static_cast<uint8_t>(term_color);
}
bool is_rgb;
union color_union {
uint8_t term_color;
uint32_t rgb_color;
} value;
};
} // namespace internal
// Experimental text formatting support.
class text_style {
public:
FMT_CONSTEXPR text_style(emphasis em = emphasis()) FMT_NOEXCEPT
: set_foreground_color(), set_background_color(), ems(em) {}
FMT_CONSTEXPR text_style &operator|=(const text_style &rhs) {
if (!set_foreground_color) {
set_foreground_color = rhs.set_foreground_color;
foreground_color = rhs.foreground_color;
} else if (rhs.set_foreground_color) {
if (!foreground_color.is_rgb || !rhs.foreground_color.is_rgb)
throw format_error("can't OR a terminal color");
foreground_color.value.rgb_color |= rhs.foreground_color.value.rgb_color;
}
if (!set_background_color) {
set_background_color = rhs.set_background_color;
background_color = rhs.background_color;
} else if (rhs.set_background_color) {
if (!background_color.is_rgb || !rhs.background_color.is_rgb)
throw format_error("can't OR a terminal color");
background_color.value.rgb_color |= rhs.background_color.value.rgb_color;
}
ems = static_cast<emphasis>(static_cast<uint8_t>(ems) |
static_cast<uint8_t>(rhs.ems));
return *this;
}
friend FMT_CONSTEXPR
text_style operator|(text_style lhs, const text_style &rhs) {
return lhs |= rhs;
}
FMT_CONSTEXPR text_style &operator&=(const text_style &rhs) {
if (!set_foreground_color) {
set_foreground_color = rhs.set_foreground_color;
foreground_color = rhs.foreground_color;
} else if (rhs.set_foreground_color) {
if (!foreground_color.is_rgb || !rhs.foreground_color.is_rgb)
throw format_error("can't AND a terminal color");
foreground_color.value.rgb_color &= rhs.foreground_color.value.rgb_color;
}
if (!set_background_color) {
set_background_color = rhs.set_background_color;
background_color = rhs.background_color;
} else if (rhs.set_background_color) {
if (!background_color.is_rgb || !rhs.background_color.is_rgb)
throw format_error("can't AND a terminal color");
background_color.value.rgb_color &= rhs.background_color.value.rgb_color;
}
ems = static_cast<emphasis>(static_cast<uint8_t>(ems) &
static_cast<uint8_t>(rhs.ems));
return *this;
}
friend FMT_CONSTEXPR
text_style operator&(text_style lhs, const text_style &rhs) {
return lhs &= rhs;
}
FMT_CONSTEXPR bool has_foreground() const FMT_NOEXCEPT {
return set_foreground_color;
}
FMT_CONSTEXPR bool has_background() const FMT_NOEXCEPT {
return set_background_color;
}
FMT_CONSTEXPR bool has_emphasis() const FMT_NOEXCEPT {
return static_cast<uint8_t>(ems) != 0;
}
FMT_CONSTEXPR internal::color_type get_foreground() const FMT_NOEXCEPT {
assert(has_foreground() && "no foreground specified for this style");
return foreground_color;
}
FMT_CONSTEXPR internal::color_type get_background() const FMT_NOEXCEPT {
assert(has_background() && "no background specified for this style");
return background_color;
}
FMT_CONSTEXPR emphasis get_emphasis() const FMT_NOEXCEPT {
assert(has_emphasis() && "no emphasis specified for this style");
return ems;
}
private:
FMT_CONSTEXPR text_style(bool is_foreground,
internal::color_type text_color) FMT_NOEXCEPT
: set_foreground_color(),
set_background_color(),
ems() {
if (is_foreground) {
foreground_color = text_color;
set_foreground_color = true;
} else {
background_color = text_color;
set_background_color = true;
}
}
friend FMT_CONSTEXPR_DECL text_style fg(internal::color_type foreground)
FMT_NOEXCEPT;
friend FMT_CONSTEXPR_DECL text_style bg(internal::color_type background)
FMT_NOEXCEPT;
internal::color_type foreground_color;
internal::color_type background_color;
bool set_foreground_color;
bool set_background_color;
emphasis ems;
};
FMT_CONSTEXPR text_style fg(internal::color_type foreground) FMT_NOEXCEPT {
return text_style(/*is_foreground=*/true, foreground);
}
FMT_CONSTEXPR text_style bg(internal::color_type background) FMT_NOEXCEPT {
return text_style(/*is_foreground=*/false, background);
}
FMT_CONSTEXPR text_style operator|(emphasis lhs, emphasis rhs) FMT_NOEXCEPT {
return text_style(lhs) | rhs;
}
namespace internal {
template <typename Char>
struct ansi_color_escape {
FMT_CONSTEXPR ansi_color_escape(internal::color_type text_color,
const char * esc) FMT_NOEXCEPT {
// If we have a terminal color, we need to output another escape code
// sequence.
if (!text_color.is_rgb) {
bool is_background = esc == internal::data::BACKGROUND_COLOR;
uint32_t value = text_color.value.term_color;
// Background ASCII codes are the same as the foreground ones but with
// 10 more.
if (is_background)
value += 10u;
std::size_t index = 0;
buffer[index++] = static_cast<Char>('\x1b');
buffer[index++] = static_cast<Char>('[');
if (value >= 100u) {
buffer[index++] = static_cast<Char>('1');
value %= 100u;
}
buffer[index++] = static_cast<Char>('0' + value / 10u);
buffer[index++] = static_cast<Char>('0' + value % 10u);
buffer[index++] = static_cast<Char>('m');
buffer[index++] = static_cast<Char>('\0');
return;
}
for (int i = 0; i < 7; i++) {
buffer[i] = static_cast<Char>(esc[i]);
}
rgb color(text_color.value.rgb_color);
to_esc(color.r, buffer + 7, ';');
to_esc(color.g, buffer + 11, ';');
to_esc(color.b, buffer + 15, 'm');
buffer[19] = static_cast<Char>(0);
}
FMT_CONSTEXPR ansi_color_escape(emphasis em) FMT_NOEXCEPT {
uint8_t em_codes[4] = {};
uint8_t em_bits = static_cast<uint8_t>(em);
if (em_bits & static_cast<uint8_t>(emphasis::bold))
em_codes[0] = 1;
if (em_bits & static_cast<uint8_t>(emphasis::italic))
em_codes[1] = 3;
if (em_bits & static_cast<uint8_t>(emphasis::underline))
em_codes[2] = 4;
if (em_bits & static_cast<uint8_t>(emphasis::strikethrough))
em_codes[3] = 9;
std::size_t index = 0;
for (int i = 0; i < 4; ++i) {
if (!em_codes[i])
continue;
buffer[index++] = static_cast<Char>('\x1b');
buffer[index++] = static_cast<Char>('[');
buffer[index++] = static_cast<Char>('0' + em_codes[i]);
buffer[index++] = static_cast<Char>('m');
}
buffer[index++] = static_cast<Char>(0);
}
FMT_CONSTEXPR operator const Char *() const FMT_NOEXCEPT { return buffer; }
private:
Char buffer[7u + 3u * 4u + 1u];
static FMT_CONSTEXPR void to_esc(uint8_t c, Char *out,
char delimiter) FMT_NOEXCEPT {
out[0] = static_cast<Char>('0' + c / 100);
out[1] = static_cast<Char>('0' + c / 10 % 10);
out[2] = static_cast<Char>('0' + c % 10);
out[3] = static_cast<Char>(delimiter);
}
};
template <typename Char>
FMT_CONSTEXPR ansi_color_escape<Char>
make_foreground_color(internal::color_type foreground) FMT_NOEXCEPT {
return ansi_color_escape<Char>(foreground, internal::data::FOREGROUND_COLOR);
}
template <typename Char>
FMT_CONSTEXPR ansi_color_escape<Char>
make_background_color(internal::color_type background) FMT_NOEXCEPT {
return ansi_color_escape<Char>(background, internal::data::BACKGROUND_COLOR);
}
template <typename Char>
FMT_CONSTEXPR ansi_color_escape<Char>
make_emphasis(emphasis em) FMT_NOEXCEPT {
return ansi_color_escape<Char>(em);
}
template <typename Char>
inline void fputs(const Char *chars, FILE *stream) FMT_NOEXCEPT {
std::fputs(chars, stream);
}
template <>
inline void fputs<wchar_t>(const wchar_t *chars, FILE *stream) FMT_NOEXCEPT {
std::fputws(chars, stream);
}
template <typename Char>
inline void reset_color(FILE *stream) FMT_NOEXCEPT {
fputs(internal::data::RESET_COLOR, stream);
}
template <>
inline void reset_color<wchar_t>(FILE *stream) FMT_NOEXCEPT {
fputs(internal::data::WRESET_COLOR, stream);
}
// The following specialiazation disables using std::FILE as a character type,
// which is needed because or else
// fmt::print(stderr, fmt::emphasis::bold, "");
// would take stderr (a std::FILE *) as the format string.
template <>
struct is_string<std::FILE *> : std::false_type {};
template <>
struct is_string<const std::FILE *> : std::false_type {};
} // namespace internal
template <
typename S, typename Char = typename internal::char_t<S>::type>
void vprint(std::FILE *f, const text_style &ts, const S &format,
basic_format_args<typename buffer_context<Char>::type> args) {
bool has_style = false;
if (ts.has_emphasis()) {
has_style = true;
internal::fputs<Char>(
internal::make_emphasis<Char>(ts.get_emphasis()), f);
}
if (ts.has_foreground()) {
has_style = true;
internal::fputs<Char>(
internal::make_foreground_color<Char>(ts.get_foreground()), f);
}
if (ts.has_background()) {
has_style = true;
internal::fputs<Char>(
internal::make_background_color<Char>(ts.get_background()), f);
}
vprint(f, format, args);
if (has_style) {
internal::reset_color<Char>(f);
}
}
/**
Formats a string and prints it to the specified file stream using ANSI
escape sequences to specify text formatting.
Example:
fmt::print(fmt::emphasis::bold | fg(fmt::color::red),
"Elapsed time: {0:.2f} seconds", 1.23);
*/
template <typename String, typename... Args>
typename std::enable_if<internal::is_string<String>::value>::type print(
std::FILE *f, const text_style &ts, const String &format_str,
const Args &... args) {
internal::check_format_string<Args...>(format_str);
typedef typename internal::char_t<String>::type char_t;
typedef typename buffer_context<char_t>::type context_t;
format_arg_store<context_t, Args...> as{args...};
vprint(f, ts, format_str, basic_format_args<context_t>(as));
}
/**
Formats a string and prints it to stdout using ANSI escape sequences to
specify text formatting.
Example:
fmt::print(fmt::emphasis::bold | fg(fmt::color::red),
"Elapsed time: {0:.2f} seconds", 1.23);
*/
template <typename String, typename... Args>
typename std::enable_if<internal::is_string<String>::value>::type print(
const text_style &ts, const String &format_str,
const Args &... args) {
return print(stdout, ts, format_str, args...);
}
#endif
FMT_END_NAMESPACE
#endif // FMT_COLOR_H_

@ -1,257 +0,0 @@
// Formatting library for C++ - the core API
//
// Copyright (c) 2012 - present, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
//
// Copyright (c) 2018 - present, Remotion (Igor Schulz)
// All Rights Reserved
// {fmt} support for rgb color output.
#ifndef FMT_COLORS_H_
#define FMT_COLORS_H_
#include "format.h"
FMT_BEGIN_NAMESPACE
// rgb is a struct for red, green and blue colors.
// We use rgb as name because some editors will show it as color direct in the
// editor.
struct rgb
{
FMT_CONSTEXPR_DECL rgb()
: r(0)
, g(0)
, b(0)
{
}
FMT_CONSTEXPR_DECL rgb(uint8_t r_, uint8_t g_, uint8_t b_)
: r(r_)
, g(g_)
, b(b_)
{
}
FMT_CONSTEXPR_DECL rgb(uint32_t hex)
: r((hex >> 16) & 0xFF)
, g((hex >> 8) & 0xFF)
, b((hex)&0xFF)
{
}
uint8_t r;
uint8_t g;
uint8_t b;
};
namespace internal {
FMT_CONSTEXPR inline void to_esc(uint8_t c, char out[], int offset)
{
out[offset + 0] = static_cast<char>('0' + c / 100);
out[offset + 1] = static_cast<char>('0' + c / 10 % 10);
out[offset + 2] = static_cast<char>('0' + c % 10);
}
} // namespace internal
FMT_FUNC void vprint_rgb(rgb fd, string_view format, format_args args)
{
char escape_fd[] = "\x1b[38;2;000;000;000m";
static FMT_CONSTEXPR_DECL const char RESET_COLOR[] = "\x1b[0m";
internal::to_esc(fd.r, escape_fd, 7);
internal::to_esc(fd.g, escape_fd, 11);
internal::to_esc(fd.b, escape_fd, 15);
std::fputs(escape_fd, stdout);
vprint(format, args);
std::fputs(RESET_COLOR, stdout);
}
FMT_FUNC void vprint_rgb(rgb fd, rgb bg, string_view format, format_args args)
{
char escape_fd[] = "\x1b[38;2;000;000;000m"; // foreground color
char escape_bg[] = "\x1b[48;2;000;000;000m"; // background color
static FMT_CONSTEXPR_DECL const char RESET_COLOR[] = "\x1b[0m";
internal::to_esc(fd.r, escape_fd, 7);
internal::to_esc(fd.g, escape_fd, 11);
internal::to_esc(fd.b, escape_fd, 15);
internal::to_esc(bg.r, escape_bg, 7);
internal::to_esc(bg.g, escape_bg, 11);
internal::to_esc(bg.b, escape_bg, 15);
std::fputs(escape_fd, stdout);
std::fputs(escape_bg, stdout);
vprint(format, args);
std::fputs(RESET_COLOR, stdout);
}
template<typename... Args>
inline void print_rgb(rgb fd, string_view format_str, const Args &... args)
{
vprint_rgb(fd, format_str, make_format_args(args...));
}
// rgb foreground color
template<typename... Args>
inline void print(rgb fd, string_view format_str, const Args &... args)
{
vprint_rgb(fd, format_str, make_format_args(args...));
}
// rgb foreground color and background color
template<typename... Args>
inline void print(rgb fd, rgb bg, string_view format_str, const Args &... args)
{
vprint_rgb(fd, bg, format_str, make_format_args(args...));
}
enum class color : uint32_t
{
alice_blue = 0xF0F8FF, // rgb(240,248,255)
antique_white = 0xFAEBD7, // rgb(250,235,215)
aqua = 0x00FFFF, // rgb(0,255,255)
aquamarine = 0x7FFFD4, // rgb(127,255,212)
azure = 0xF0FFFF, // rgb(240,255,255)
beige = 0xF5F5DC, // rgb(245,245,220)
bisque = 0xFFE4C4, // rgb(255,228,196)
black = 0x000000, // rgb(0,0,0)
blanched_almond = 0xFFEBCD, // rgb(255,235,205)
blue = 0x0000FF, // rgb(0,0,255)
blue_violet = 0x8A2BE2, // rgb(138,43,226)
brown = 0xA52A2A, // rgb(165,42,42)
burly_wood = 0xDEB887, // rgb(222,184,135)
cadet_blue = 0x5F9EA0, // rgb(95,158,160)
chartreuse = 0x7FFF00, // rgb(127,255,0)
chocolate = 0xD2691E, // rgb(210,105,30)
coral = 0xFF7F50, // rgb(255,127,80)
cornflower_blue = 0x6495ED, // rgb(100,149,237)
cornsilk = 0xFFF8DC, // rgb(255,248,220)
crimson = 0xDC143C, // rgb(220,20,60)
cyan = 0x00FFFF, // rgb(0,255,255)
dark_blue = 0x00008B, // rgb(0,0,139)
dark_cyan = 0x008B8B, // rgb(0,139,139)
dark_golden_rod = 0xB8860B, // rgb(184,134,11)
dark_gray = 0xA9A9A9, // rgb(169,169,169)
dark_green = 0x006400, // rgb(0,100,0)
dark_khaki = 0xBDB76B, // rgb(189,183,107)
dark_magenta = 0x8B008B, // rgb(139,0,139)
dark_olive_green = 0x556B2F, // rgb(85,107,47)
dark_orange = 0xFF8C00, // rgb(255,140,0)
dark_orchid = 0x9932CC, // rgb(153,50,204)
dark_red = 0x8B0000, // rgb(139,0,0)
dark_salmon = 0xE9967A, // rgb(233,150,122)
dark_sea_green = 0x8FBC8F, // rgb(143,188,143)
dark_slate_blue = 0x483D8B, // rgb(72,61,139)
dark_slate_gray = 0x2F4F4F, // rgb(47,79,79)
dark_turquoise = 0x00CED1, // rgb(0,206,209)
dark_violet = 0x9400D3, // rgb(148,0,211)
deep_pink = 0xFF1493, // rgb(255,20,147)
deep_sky_blue = 0x00BFFF, // rgb(0,191,255)
dim_gray = 0x696969, // rgb(105,105,105)
dodger_blue = 0x1E90FF, // rgb(30,144,255)
fire_brick = 0xB22222, // rgb(178,34,34)
floral_white = 0xFFFAF0, // rgb(255,250,240)
forest_green = 0x228B22, // rgb(34,139,34)
fuchsia = 0xFF00FF, // rgb(255,0,255)
gainsboro = 0xDCDCDC, // rgb(220,220,220)
ghost_white = 0xF8F8FF, // rgb(248,248,255)
gold = 0xFFD700, // rgb(255,215,0)
golden_rod = 0xDAA520, // rgb(218,165,32)
gray = 0x808080, // rgb(128,128,128)
green = 0x008000, // rgb(0,128,0)
green_yellow = 0xADFF2F, // rgb(173,255,47)
honey_dew = 0xF0FFF0, // rgb(240,255,240)
hot_pink = 0xFF69B4, // rgb(255,105,180)
indian_red = 0xCD5C5C, // rgb(205,92,92)
indigo = 0x4B0082, // rgb(75,0,130)
ivory = 0xFFFFF0, // rgb(255,255,240)
khaki = 0xF0E68C, // rgb(240,230,140)
lavender = 0xE6E6FA, // rgb(230,230,250)
lavender_blush = 0xFFF0F5, // rgb(255,240,245)
lawn_green = 0x7CFC00, // rgb(124,252,0)
lemon_chiffon = 0xFFFACD, // rgb(255,250,205)
light_blue = 0xADD8E6, // rgb(173,216,230)
light_coral = 0xF08080, // rgb(240,128,128)
light_cyan = 0xE0FFFF, // rgb(224,255,255)
light_golden_rod_yellow = 0xFAFAD2, // rgb(250,250,210)
light_gray = 0xD3D3D3, // rgb(211,211,211)
light_green = 0x90EE90, // rgb(144,238,144)
light_pink = 0xFFB6C1, // rgb(255,182,193)
light_salmon = 0xFFA07A, // rgb(255,160,122)
light_sea_green = 0x20B2AA, // rgb(32,178,170)
light_sky_blue = 0x87CEFA, // rgb(135,206,250)
light_slate_gray = 0x778899, // rgb(119,136,153)
light_steel_blue = 0xB0C4DE, // rgb(176,196,222)
light_yellow = 0xFFFFE0, // rgb(255,255,224)
lime = 0x00FF00, // rgb(0,255,0)
lime_green = 0x32CD32, // rgb(50,205,50)
linen = 0xFAF0E6, // rgb(250,240,230)
magenta = 0xFF00FF, // rgb(255,0,255)
maroon = 0x800000, // rgb(128,0,0)
medium_aqua_marine = 0x66CDAA, // rgb(102,205,170)
medium_blue = 0x0000CD, // rgb(0,0,205)
medium_orchid = 0xBA55D3, // rgb(186,85,211)
medium_purple = 0x9370DB, // rgb(147,112,219)
medium_sea_green = 0x3CB371, // rgb(60,179,113)
medium_slate_blue = 0x7B68EE, // rgb(123,104,238)
medium_spring_green = 0x00FA9A, // rgb(0,250,154)
medium_turquoise = 0x48D1CC, // rgb(72,209,204)
medium_violet_red = 0xC71585, // rgb(199,21,133)
midnight_blue = 0x191970, // rgb(25,25,112)
mint_cream = 0xF5FFFA, // rgb(245,255,250)
misty_rose = 0xFFE4E1, // rgb(255,228,225)
moccasin = 0xFFE4B5, // rgb(255,228,181)
navajo_white = 0xFFDEAD, // rgb(255,222,173)
navy = 0x000080, // rgb(0,0,128)
old_lace = 0xFDF5E6, // rgb(253,245,230)
olive = 0x808000, // rgb(128,128,0)
olive_drab = 0x6B8E23, // rgb(107,142,35)
orange = 0xFFA500, // rgb(255,165,0)
orange_red = 0xFF4500, // rgb(255,69,0)
orchid = 0xDA70D6, // rgb(218,112,214)
pale_golden_rod = 0xEEE8AA, // rgb(238,232,170)
pale_green = 0x98FB98, // rgb(152,251,152)
pale_turquoise = 0xAFEEEE, // rgb(175,238,238)
pale_violet_red = 0xDB7093, // rgb(219,112,147)
papaya_whip = 0xFFEFD5, // rgb(255,239,213)
peach_puff = 0xFFDAB9, // rgb(255,218,185)
peru = 0xCD853F, // rgb(205,133,63)
pink = 0xFFC0CB, // rgb(255,192,203)
plum = 0xDDA0DD, // rgb(221,160,221)
powder_blue = 0xB0E0E6, // rgb(176,224,230)
purple = 0x800080, // rgb(128,0,128)
rebecca_purple = 0x663399, // rgb(102,51,153)
red = 0xFF0000, // rgb(255,0,0)
rosy_brown = 0xBC8F8F, // rgb(188,143,143)
royal_blue = 0x4169E1, // rgb(65,105,225)
saddle_brown = 0x8B4513, // rgb(139,69,19)
salmon = 0xFA8072, // rgb(250,128,114)
sandy_brown = 0xF4A460, // rgb(244,164,96)
sea_green = 0x2E8B57, // rgb(46,139,87)
sea_shell = 0xFFF5EE, // rgb(255,245,238)
sienna = 0xA0522D, // rgb(160,82,45)
silver = 0xC0C0C0, // rgb(192,192,192)
sky_blue = 0x87CEEB, // rgb(135,206,235)
slate_blue = 0x6A5ACD, // rgb(106,90,205)
slate_gray = 0x708090, // rgb(112,128,144)
snow = 0xFFFAFA, // rgb(255,250,250)
spring_green = 0x00FF7F, // rgb(0,255,127)
steel_blue = 0x4682B4, // rgb(70,130,180)
tan = 0xD2B48C, // rgb(210,180,140)
teal = 0x008080, // rgb(0,128,128)
thistle = 0xD8BFD8, // rgb(216,191,216)
tomato = 0xFF6347, // rgb(255,99,71)
turquoise = 0x40E0D0, // rgb(64,224,208)
violet = 0xEE82EE, // rgb(238,130,238)
wheat = 0xF5DEB3, // rgb(245,222,179)
white = 0xFFFFFF, // rgb(255,255,255)
white_smoke = 0xF5F5F5, // rgb(245,245,245)
yellow = 0xFFFF00, // rgb(255,255,0)
yellow_green = 0x9ACD32, // rgb(154,205,50)
}; // enum class colors
FMT_END_NAMESPACE
#endif // FMT_COLORS_H_

File diff suppressed because it is too large Load Diff

@ -136,12 +136,14 @@ int safe_strerror(
ERANGE : result;
}
#if !FMT_MSC_VER
// Fallback to strerror if strerror_r and strerror_s are not available.
int fallback(internal::null<>) {
errno = 0;
buffer_ = strerror(error_code_);
return errno;
}
#endif
public:
dispatcher(int err_code, char *&buf, std::size_t buf_size)
@ -170,7 +172,7 @@ void format_error_code(internal::buffer &out, int error_code,
abs_value = 0 - abs_value;
++error_code_size;
}
error_code_size += internal::count_digits(abs_value);
error_code_size += internal::to_unsigned(internal::count_digits(abs_value));
writer w(out);
if (message.size() <= inline_buffer_size - error_code_size) {
w.write(message);
@ -192,34 +194,39 @@ void report_error(FormatFunc func, int error_code,
}
} // namespace
#if !defined(FMT_STATIC_THOUSANDS_SEPARATOR)
class locale {
private:
std::locale locale_;
public:
explicit locale(std::locale loc = std::locale()) : locale_(loc) {}
std::locale get() { return locale_; }
};
FMT_FUNC size_t internal::count_code_points(u8string_view s) {
FMT_FUNC size_t internal::count_code_points(basic_string_view<char8_t> s) {
const char8_t *data = s.data();
int num_code_points = 0;
size_t num_code_points = 0;
for (size_t i = 0, size = s.size(); i != size; ++i) {
if ((data[i].value & 0xc0) != 0x80)
if ((data[i] & 0xc0) != 0x80)
++num_code_points;
}
return num_code_points;
}
#if !defined(FMT_STATIC_THOUSANDS_SEPARATOR)
namespace internal {
template <typename Locale>
locale_ref::locale_ref(const Locale &loc) : locale_(&loc) {
static_assert(std::is_same<Locale, std::locale>::value, "");
}
template <typename Locale>
Locale locale_ref::get() const {
static_assert(std::is_same<Locale, std::locale>::value, "");
return locale_ ? *static_cast<const std::locale*>(locale_) : std::locale();
}
template <typename Char>
FMT_FUNC Char internal::thousands_sep(locale_provider *lp) {
std::locale loc = lp ? lp->locale().get() : std::locale();
return std::use_facet<std::numpunct<Char>>(loc).thousands_sep();
FMT_FUNC Char thousands_sep_impl(locale_ref loc) {
return std::use_facet<std::numpunct<Char> >(
loc.get<std::locale>()).thousands_sep();
}
}
#else
template <typename Char>
FMT_FUNC Char internal::thousands_sep(locale_provider *lp) {
FMT_FUNC Char internal::thousands_sep_impl(locale_ref) {
return FMT_STATIC_THOUSANDS_SEPARATOR;
}
#endif
@ -236,19 +243,19 @@ FMT_FUNC void system_error::init(
namespace internal {
template <typename T>
int char_traits<char>::format_float(
char *buffer, std::size_t size, const char *format, int precision, T value) {
char *buf, std::size_t size, const char *format, int precision, T value) {
return precision < 0 ?
FMT_SNPRINTF(buffer, size, format, value) :
FMT_SNPRINTF(buffer, size, format, precision, value);
FMT_SNPRINTF(buf, size, format, value) :
FMT_SNPRINTF(buf, size, format, precision, value);
}
template <typename T>
int char_traits<wchar_t>::format_float(
wchar_t *buffer, std::size_t size, const wchar_t *format, int precision,
wchar_t *buf, std::size_t size, const wchar_t *format, int precision,
T value) {
return precision < 0 ?
FMT_SWPRINTF(buffer, size, format, value) :
FMT_SWPRINTF(buffer, size, format, precision, value);
FMT_SWPRINTF(buf, size, format, value) :
FMT_SWPRINTF(buf, size, format, precision, value);
}
template <typename T>
@ -337,6 +344,8 @@ const int16_t basic_data<T>::POW10_EXPONENTS[] = {
827, 853, 880, 907, 933, 960, 986, 1013, 1039, 1066
};
template <typename T> const char basic_data<T>::FOREGROUND_COLOR[] = "\x1b[38;2;";
template <typename T> const char basic_data<T>::BACKGROUND_COLOR[] = "\x1b[48;2;";
template <typename T> const char basic_data<T>::RESET_COLOR[] = "\x1b[0m";
template <typename T> const wchar_t basic_data<T>::WRESET_COLOR[] = L"\x1b[0m";
@ -363,7 +372,7 @@ class fp {
sizeof(significand_type) * char_size;
fp(): f(0), e(0) {}
fp(uint64_t f, int e): f(f), e(e) {}
fp(uint64_t f_val, int e_val): f(f_val), e(e_val) {}
// Constructs fp from an IEEE754 double. It is a template to prevent compile
// errors on platforms where double is not IEEE754.
@ -454,19 +463,28 @@ FMT_FUNC fp get_cached_power(int min_exponent, int &pow10_exponent) {
return fp(data::POW10_SIGNIFICANDS[index], data::POW10_EXPONENTS[index]);
}
FMT_FUNC bool grisu2_round(
char *buf, int &size, int max_digits, uint64_t delta,
uint64_t remainder, uint64_t exp, uint64_t diff, int &exp10) {
while (remainder < diff && delta - remainder >= exp &&
(remainder + exp < diff || diff - remainder > remainder + exp - diff)) {
--buf[size - 1];
remainder += exp;
}
if (size > max_digits) {
--size;
++exp10;
if (buf[size] >= '5')
return false;
}
return true;
}
// Generates output using Grisu2 digit-gen algorithm.
FMT_FUNC void grisu2_gen_digits(
const fp &scaled_value, const fp &scaled_upper, uint64_t delta,
char *buffer, size_t &size, int &dec_exp) {
internal::fp one(1ull << -scaled_upper.e, scaled_upper.e);
// hi (p1 in Grisu) contains the most significant digits of scaled_upper.
// hi = floor(scaled_upper / one).
uint32_t hi = static_cast<uint32_t>(scaled_upper.f >> -one.e);
// lo (p2 in Grisu) contains the least significants digits of scaled_upper.
// lo = scaled_upper mod 1.
uint64_t lo = scaled_upper.f & (one.f - 1);
size = 0;
auto exp = count_digits(hi); // kappa in Grisu.
FMT_FUNC bool grisu2_gen_digits(
char *buf, int &size, uint32_t hi, uint64_t lo, int &exp,
uint64_t delta, const fp &one, const fp &diff, int max_digits) {
// Generate digits for the most significant part (hi).
while (exp > 0) {
uint32_t digit = 0;
// This optimization by miloyip reduces the number of integer divisions by
@ -486,208 +504,304 @@ FMT_FUNC void grisu2_gen_digits(
FMT_ASSERT(false, "invalid number of digits");
}
if (digit != 0 || size != 0)
buffer[size++] = static_cast<char>('0' + digit);
buf[size++] = static_cast<char>('0' + digit);
--exp;
uint64_t remainder = (static_cast<uint64_t>(hi) << -one.e) + lo;
if (remainder <= delta) {
dec_exp += exp;
// TODO: use scaled_value
(void)scaled_value;
return;
if (remainder <= delta || size > max_digits) {
return grisu2_round(
buf, size, max_digits, delta, remainder,
static_cast<uint64_t>(data::POWERS_OF_10_32[exp]) << -one.e,
diff.f, exp);
}
}
// Generate digits for the least significant part (lo).
for (;;) {
lo *= 10;
delta *= 10;
char digit = static_cast<char>(lo >> -one.e);
if (digit != 0 || size != 0)
buffer[size++] = static_cast<char>('0' + digit);
buf[size++] = static_cast<char>('0' + digit);
lo &= one.f - 1;
--exp;
if (lo < delta) {
dec_exp += exp;
return;
if (lo < delta || size > max_digits) {
return grisu2_round(buf, size, max_digits, delta, lo, one.f,
diff.f * data::POWERS_OF_10_32[-exp], exp);
}
}
}
FMT_FUNC void grisu2_format_positive(double value, char *buffer, size_t &size,
int &dec_exp) {
FMT_ASSERT(value > 0, "value is nonpositive");
fp fp_value(value);
fp lower, upper; // w^- and w^+ in the Grisu paper.
fp_value.compute_boundaries(lower, upper);
// Find a cached power of 10 close to 1 / upper.
const int min_exp = -60; // alpha in Grisu.
auto dec_pow = get_cached_power( // \tilde{c}_{-k} in Grisu.
min_exp - (upper.e + fp::significand_size), dec_exp);
dec_exp = -dec_exp;
fp_value.normalize();
fp scaled_value = fp_value * dec_pow;
fp scaled_lower = lower * dec_pow; // \tilde{M}^- in Grisu.
fp scaled_upper = upper * dec_pow; // \tilde{M}^+ in Grisu.
++scaled_lower.f; // \tilde{M}^- + 1 ulp -> M^-_{\uparrow}.
--scaled_upper.f; // \tilde{M}^+ - 1 ulp -> M^+_{\downarrow}.
uint64_t delta = scaled_upper.f - scaled_lower.f;
grisu2_gen_digits(scaled_value, scaled_upper, delta, buffer, size, dec_exp);
}
#if FMT_CLANG_VERSION
# define FMT_FALLTHROUGH [[clang::fallthrough]];
#elif FMT_GCC_VERSION >= 700
# define FMT_FALLTHROUGH [[gnu::fallthrough]];
#else
# define FMT_FALLTHROUGH
#endif
struct gen_digits_params {
int num_digits;
bool fixed;
bool upper;
bool trailing_zeros;
};
FMT_FUNC void round(char *buffer, size_t &size, int &exp,
int digits_to_remove) {
size -= to_unsigned(digits_to_remove);
exp += digits_to_remove;
int digit = buffer[size] - '0';
// TODO: proper rounding and carry
if (digit > 5 || (digit == 5 && (digits_to_remove > 1 ||
(buffer[size - 1] - '0') % 2) != 0)) {
++buffer[size - 1];
struct prettify_handler {
char *data;
ptrdiff_t size;
buffer &buf;
explicit prettify_handler(buffer &b, ptrdiff_t n)
: data(b.data()), size(n), buf(b) {}
~prettify_handler() {
assert(buf.size() >= to_unsigned(size));
buf.resize(to_unsigned(size));
}
}
// Writes the exponent exp in the form "[+-]d{1,3}" to buffer.
FMT_FUNC char *write_exponent(char *buffer, int exp) {
template <typename F>
void insert(ptrdiff_t pos, ptrdiff_t n, F f) {
std::memmove(data + pos + n, data + pos, to_unsigned(size - pos));
f(data + pos);
size += n;
}
void insert(ptrdiff_t pos, char c) {
std::memmove(data + pos + 1, data + pos, to_unsigned(size - pos));
data[pos] = c;
++size;
}
void append(ptrdiff_t n, char c) {
std::uninitialized_fill_n(data + size, n, c);
size += n;
}
void append(char c) { data[size++] = c; }
void remove_trailing(char c) {
while (data[size - 1] == c) --size;
}
};
// Writes the exponent exp in the form "[+-]d{2,3}" to buffer.
template <typename Handler>
FMT_FUNC void write_exponent(int exp, Handler &&h) {
FMT_ASSERT(-1000 < exp && exp < 1000, "exponent out of range");
if (exp < 0) {
*buffer++ = '-';
h.append('-');
exp = -exp;
} else {
*buffer++ = '+';
h.append('+');
}
if (exp >= 100) {
*buffer++ = static_cast<char>('0' + exp / 100);
h.append(static_cast<char>('0' + exp / 100));
exp %= 100;
const char *d = data::DIGITS + exp * 2;
*buffer++ = d[0];
*buffer++ = d[1];
h.append(d[0]);
h.append(d[1]);
} else {
const char *d = data::DIGITS + exp * 2;
*buffer++ = d[0];
*buffer++ = d[1];
h.append(d[0]);
h.append(d[1]);
}
return buffer;
}
FMT_FUNC void format_exp_notation(
char *buffer, size_t &size, int exp, int precision, bool upper) {
struct fill {
size_t n;
void operator()(char *buf) const {
buf[0] = '0';
buf[1] = '.';
std::uninitialized_fill_n(buf + 2, n, '0');
}
};
// The number is given as v = f * pow(10, exp), where f has size digits.
template <typename Handler>
FMT_FUNC void grisu2_prettify(const gen_digits_params &params,
int size, int exp, Handler &&handler) {
if (!params.fixed) {
// Insert a decimal point after the first digit and add an exponent.
std::memmove(buffer + 2, buffer + 1, size - 1);
buffer[1] = '.';
exp += static_cast<int>(size) - 1;
int num_digits = precision - static_cast<int>(size) + 1;
if (num_digits > 0) {
std::uninitialized_fill_n(buffer + size + 1, num_digits, '0');
size += to_unsigned(num_digits);
} else if (num_digits < 0) {
round(buffer, size, exp, -num_digits);
}
char *p = buffer + size + 1;
*p++ = upper ? 'E' : 'e';
size = to_unsigned(write_exponent(p, exp) - buffer);
}
// Prettifies the output of the Grisu2 algorithm.
// The number is given as v = buffer * 10^exp.
FMT_FUNC void grisu2_prettify(char *buffer, size_t &size, int exp,
int precision, bool upper) {
handler.insert(1, '.');
exp += size - 1;
if (size < params.num_digits)
handler.append(params.num_digits - size, '0');
handler.append(params.upper ? 'E' : 'e');
write_exponent(exp, handler);
return;
}
// pow(10, full_exp - 1) <= v <= pow(10, full_exp).
int int_size = static_cast<int>(size);
int full_exp = int_size + exp;
int full_exp = size + exp;
const int exp_threshold = 21;
if (int_size <= full_exp && full_exp <= exp_threshold) {
if (size <= full_exp && full_exp <= exp_threshold) {
// 1234e7 -> 12340000000[.0+]
std::uninitialized_fill_n(buffer + int_size, full_exp - int_size, '0');
char *p = buffer + full_exp;
if (precision > 0) {
*p++ = '.';
std::uninitialized_fill_n(p, precision, '0');
p += precision;
}
size = to_unsigned(p - buffer);
} else if (0 < full_exp && full_exp <= exp_threshold) {
handler.append(full_exp - size, '0');
int num_zeros = params.num_digits - full_exp;
if (num_zeros > 0 && params.trailing_zeros) {
handler.append('.');
handler.append(num_zeros, '0');
}
} else if (full_exp > 0) {
// 1234e-2 -> 12.34[0+]
int fractional_size = -exp;
std::memmove(buffer + full_exp + 1, buffer + full_exp,
to_unsigned(fractional_size));
buffer[full_exp] = '.';
int num_zeros = precision - fractional_size;
if (num_zeros > 0) {
std::uninitialized_fill_n(buffer + size + 1, num_zeros, '0');
size += to_unsigned(num_zeros);
handler.insert(full_exp, '.');
if (!params.trailing_zeros) {
// Remove trailing zeros.
handler.remove_trailing('0');
} else if (params.num_digits > size) {
// Add trailing zeros.
ptrdiff_t num_zeros = params.num_digits - size;
handler.append(num_zeros, '0');
}
++size;
} else if (-6 < full_exp && full_exp <= 0) {
// 1234e-6 -> 0.001234
int offset = 2 - full_exp;
std::memmove(buffer + offset, buffer, size);
buffer[0] = '0';
buffer[1] = '.';
std::uninitialized_fill_n(buffer + 2, -full_exp, '0');
size = to_unsigned(int_size + offset);
} else {
format_exp_notation(buffer, size, exp, precision, upper);
// 1234e-6 -> 0.001234
handler.insert(0, 2 - full_exp, fill{to_unsigned(-full_exp)});
}
}
#if FMT_CLANG_VERSION
# define FMT_FALLTHROUGH [[clang::fallthrough]];
#elif FMT_GCC_VERSION >= 700
# define FMT_FALLTHROUGH [[gnu::fallthrough]];
#else
# define FMT_FALLTHROUGH
#endif
struct char_counter {
ptrdiff_t size;
// Formats a nonnegative value using Grisu2 algorithm. Grisu2 doesn't give any
// guarantees on the shortness of the result.
FMT_FUNC void grisu2_format(double value, char *buffer, size_t &size, char type,
int precision, bool write_decimal_point) {
FMT_ASSERT(value >= 0, "value is negative");
int dec_exp = 0; // K in Grisu.
if (value > 0) {
grisu2_format_positive(value, buffer, size, dec_exp);
} else {
*buffer = '0';
size = 1;
}
const int default_precision = 6;
if (precision < 0)
precision = default_precision;
bool upper = false;
switch (type) {
template <typename F>
void insert(ptrdiff_t, ptrdiff_t n, F) { size += n; }
void insert(ptrdiff_t, char) { ++size; }
void append(ptrdiff_t n, char) { size += n; }
void append(char) { ++size; }
void remove_trailing(char) {}
};
// Converts format specifiers into parameters for digit generation and computes
// output buffer size for a number in the range [pow(10, exp - 1), pow(10, exp)
// or 0 if exp == 1.
FMT_FUNC gen_digits_params process_specs(const core_format_specs &specs,
int exp, buffer &buf) {
auto params = gen_digits_params();
int num_digits = specs.precision >= 0 ? specs.precision : 6;
switch (specs.type) {
case 'G':
upper = true;
params.upper = true;
FMT_FALLTHROUGH
case '\0': case 'g': {
int digits_to_remove = static_cast<int>(size) - precision;
if (digits_to_remove > 0) {
round(buffer, size, dec_exp, digits_to_remove);
// Remove trailing zeros.
while (size > 0 && buffer[size - 1] == '0') {
--size;
++dec_exp;
}
case '\0': case 'g':
params.trailing_zeros = (specs.flags & HASH_FLAG) != 0;
if (-4 <= exp && exp < num_digits + 1) {
params.fixed = true;
if (!specs.type && params.trailing_zeros && exp >= 0)
num_digits = exp + 1;
}
precision = 0;
break;
}
case 'F':
upper = true;
params.upper = true;
FMT_FALLTHROUGH
case 'f': {
int digits_to_remove = -dec_exp - precision;
if (digits_to_remove > 0) {
if (digits_to_remove >= static_cast<int>(size))
digits_to_remove = static_cast<int>(size) - 1;
round(buffer, size, dec_exp, digits_to_remove);
params.fixed = true;
params.trailing_zeros = true;
int adjusted_min_digits = num_digits + exp;
if (adjusted_min_digits > 0)
num_digits = adjusted_min_digits;
break;
}
case 'E':
params.upper = true;
FMT_FALLTHROUGH
case 'e':
++num_digits;
break;
}
case 'e': case 'E':
format_exp_notation(buffer, size, dec_exp, precision, type == 'E');
return;
params.num_digits = num_digits;
char_counter counter{num_digits};
grisu2_prettify(params, params.num_digits, exp - num_digits, counter);
buf.resize(to_unsigned(counter.size));
return params;
}
template <typename Double>
FMT_FUNC typename std::enable_if<sizeof(Double) == sizeof(uint64_t), bool>::type
grisu2_format(Double value, buffer &buf, core_format_specs specs) {
FMT_ASSERT(value >= 0, "value is negative");
if (value == 0) {
gen_digits_params params = process_specs(specs, 1, buf);
const size_t size = 1;
buf[0] = '0';
grisu2_prettify(params, size, 0, prettify_handler(buf, size));
return true;
}
fp fp_value(value);
fp lower, upper; // w^- and w^+ in the Grisu paper.
fp_value.compute_boundaries(lower, upper);
// Find a cached power of 10 close to 1 / upper and use it to scale upper.
const int min_exp = -60; // alpha in Grisu.
int cached_exp = 0; // K in Grisu.
auto cached_pow = get_cached_power( // \tilde{c}_{-k} in Grisu.
min_exp - (upper.e + fp::significand_size), cached_exp);
cached_exp = -cached_exp;
upper = upper * cached_pow; // \tilde{M}^+ in Grisu.
--upper.f; // \tilde{M}^+ - 1 ulp -> M^+_{\downarrow}.
fp one(1ull << -upper.e, upper.e);
// hi (p1 in Grisu) contains the most significant digits of scaled_upper.
// hi = floor(upper / one).
uint32_t hi = static_cast<uint32_t>(upper.f >> -one.e);
int exp = count_digits(hi); // kappa in Grisu.
gen_digits_params params = process_specs(specs, cached_exp + exp, buf);
fp_value.normalize();
fp scaled_value = fp_value * cached_pow;
lower = lower * cached_pow; // \tilde{M}^- in Grisu.
++lower.f; // \tilde{M}^- + 1 ulp -> M^-_{\uparrow}.
uint64_t delta = upper.f - lower.f;
fp diff = upper - scaled_value; // wp_w in Grisu.
// lo (p2 in Grisu) contains the least significants digits of scaled_upper.
// lo = supper % one.
uint64_t lo = upper.f & (one.f - 1);
int size = 0;
if (!grisu2_gen_digits(buf.data(), size, hi, lo, exp, delta, one, diff,
params.num_digits)) {
buf.clear();
return false;
}
grisu2_prettify(params, size, cached_exp + exp, prettify_handler(buf, size));
return true;
}
template <typename Double>
void sprintf_format(Double value, internal::buffer &buf,
core_format_specs spec) {
// Buffer capacity must be non-zero, otherwise MSVC's vsnprintf_s will fail.
FMT_ASSERT(buf.capacity() != 0, "empty buffer");
// Build format string.
enum { MAX_FORMAT_SIZE = 10}; // longest format: %#-*.*Lg
char format[MAX_FORMAT_SIZE];
char *format_ptr = format;
*format_ptr++ = '%';
if (spec.has(HASH_FLAG))
*format_ptr++ = '#';
if (spec.precision >= 0) {
*format_ptr++ = '.';
*format_ptr++ = '*';
}
if (std::is_same<Double, long double>::value)
*format_ptr++ = 'L';
*format_ptr++ = spec.type;
*format_ptr = '\0';
// Format using snprintf.
char *start = FMT_NULL;
for (;;) {
std::size_t buffer_size = buf.capacity();
start = &buf[0];
int result = internal::char_traits<char>::format_float(
start, buffer_size, format, spec.precision, value);
if (result >= 0) {
unsigned n = internal::to_unsigned(result);
if (n < buf.capacity()) {
buf.resize(n);
break; // The buffer is large enough - continue with formatting.
}
buf.reserve(n + 1);
} else {
// If result is negative we ask to increase the capacity by at least 1,
// but as std::vector, the buffer grows exponentially.
buf.reserve(buf.capacity() + 1);
}
}
if (write_decimal_point && precision < 1)
precision = 1;
grisu2_prettify(buffer, size, dec_exp, precision, upper);
}
} // namespace internal
@ -812,11 +926,6 @@ FMT_FUNC void format_system_error(
format_error_code(out, error_code, message);
}
template <typename Char>
void basic_fixed_buffer<Char>::grow(std::size_t) {
FMT_THROW(std::runtime_error("buffer overflow"));
}
FMT_FUNC void internal::error_handler::on_error(const char *message) {
FMT_THROW(format_error(message));
}
@ -835,13 +944,14 @@ FMT_FUNC void report_windows_error(
FMT_FUNC void vprint(std::FILE *f, string_view format_str, format_args args) {
memory_buffer buffer;
vformat_to(buffer, format_str, args);
internal::vformat_to(buffer, format_str,
basic_format_args<buffer_context<char>::type>(args));
std::fwrite(buffer.data(), 1, buffer.size(), f);
}
FMT_FUNC void vprint(std::FILE *f, wstring_view format_str, wformat_args args) {
wmemory_buffer buffer;
vformat_to(buffer, format_str, args);
internal::vformat_to(buffer, format_str, args);
std::fwrite(buffer.data(), sizeof(wchar_t), buffer.size(), f);
}
@ -853,10 +963,6 @@ FMT_FUNC void vprint(wstring_view format_str, wformat_args args) {
vprint(stdout, format_str, args);
}
#if !defined(FMT_STATIC_THOUSANDS_SEPARATOR)
FMT_FUNC locale locale_provider::locale() { return fmt::locale(); }
#endif
FMT_END_NAMESPACE
#ifdef _MSC_VER

File diff suppressed because it is too large Load Diff

@ -0,0 +1,77 @@
// Formatting library for C++ - std::locale support
//
// Copyright (c) 2012 - present, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
#ifndef FMT_LOCALE_H_
#define FMT_LOCALE_H_
#include "format.h"
#include <locale>
FMT_BEGIN_NAMESPACE
namespace internal {
template <typename Char>
typename buffer_context<Char>::type::iterator vformat_to(
const std::locale &loc, basic_buffer<Char> &buf,
basic_string_view<Char> format_str,
basic_format_args<typename buffer_context<Char>::type> args) {
typedef back_insert_range<basic_buffer<Char> > range;
return vformat_to<arg_formatter<range>>(
buf, to_string_view(format_str), args, internal::locale_ref(loc));
}
template <typename Char>
std::basic_string<Char> vformat(
const std::locale &loc, basic_string_view<Char> format_str,
basic_format_args<typename buffer_context<Char>::type> args) {
basic_memory_buffer<Char> buffer;
internal::vformat_to(loc, buffer, format_str, args);
return fmt::to_string(buffer);
}
}
template <typename S, typename Char = FMT_CHAR(S)>
inline std::basic_string<Char> vformat(
const std::locale &loc, const S &format_str,
basic_format_args<typename buffer_context<Char>::type> args) {
return internal::vformat(loc, to_string_view(format_str), args);
}
template <typename S, typename... Args>
inline std::basic_string<FMT_CHAR(S)> format(
const std::locale &loc, const S &format_str, const Args &... args) {
return internal::vformat(
loc, to_string_view(format_str),
*internal::checked_args<S, Args...>(format_str, args...));
}
template <typename String, typename OutputIt, typename... Args>
inline typename std::enable_if<internal::is_output_iterator<OutputIt>::value,
OutputIt>::type
vformat_to(OutputIt out, const std::locale &loc, const String &format_str,
typename format_args_t<OutputIt, FMT_CHAR(String)>::type args) {
typedef output_range<OutputIt, FMT_CHAR(String)> range;
return vformat_to<arg_formatter<range>>(
range(out), to_string_view(format_str), args, internal::locale_ref(loc));
}
template <typename OutputIt, typename S, typename... Args>
inline typename std::enable_if<
internal::is_string<S>::value &&
internal::is_output_iterator<OutputIt>::value, OutputIt>::type
format_to(OutputIt out, const std::locale &loc, const S &format_str,
const Args &... args) {
internal::check_format_string<Args...>(format_str);
typedef typename format_context_t<OutputIt, FMT_CHAR(S)>::type context;
format_arg_store<context, Args...> as{args...};
return vformat_to(out, loc, to_string_view(format_str),
basic_format_args<context>(as));
}
FMT_END_NAMESPACE
#endif // FMT_LOCALE_H_

@ -1,6 +1,6 @@
// Formatting library for C++ - std::ostream support
//
// Copyright (c) 2012 - 2016, Victor Zverovich
// Copyright (c) 2012 - present, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
@ -129,7 +129,7 @@ inline void vprint(std::basic_ostream<Char> &os,
basic_string_view<Char> format_str,
basic_format_args<typename buffer_context<Char>::type> args) {
basic_memory_buffer<Char> buffer;
vformat_to(buffer, format_str, args);
internal::vformat_to(buffer, format_str, args);
internal::write(os, buffer);
}
/**
@ -141,16 +141,12 @@ inline void vprint(std::basic_ostream<Char> &os,
fmt::print(cerr, "Don't {}!", "panic");
\endrst
*/
template <typename... Args>
inline void print(std::ostream &os, string_view format_str,
template <typename S, typename... Args>
inline typename std::enable_if<internal::is_string<S>::value>::type
print(std::basic_ostream<FMT_CHAR(S)> &os, const S &format_str,
const Args & ... args) {
vprint<char>(os, format_str, make_format_args<format_context>(args...));
}
template <typename... Args>
inline void print(std::wostream &os, wstring_view format_str,
const Args & ... args) {
vprint<wchar_t>(os, format_str, make_format_args<wformat_context>(args...));
internal::checked_args<S, Args...> ca(format_str, args...);
vprint(os, to_string_view(format_str), *ca);
}
FMT_END_NAMESPACE

@ -137,7 +137,7 @@ class buffered_file {
buffered_file() FMT_NOEXCEPT : file_(FMT_NULL) {}
// Destroys the object closing the file it represents if any.
FMT_API ~buffered_file() FMT_DTOR_NOEXCEPT;
FMT_API ~buffered_file() FMT_NOEXCEPT;
private:
buffered_file(const buffered_file &) = delete;
@ -223,7 +223,7 @@ class file {
}
// Destroys the object closing the file it represents if any.
FMT_API ~file() FMT_DTOR_NOEXCEPT;
FMT_API ~file() FMT_NOEXCEPT;
// Returns the file descriptor.
int descriptor() const FMT_NOEXCEPT { return fd_; }

@ -16,6 +16,130 @@
FMT_BEGIN_NAMESPACE
namespace internal {
// An iterator that produces a null terminator on *end. This simplifies parsing
// and allows comparing the performance of processing a null-terminated string
// vs string_view.
template <typename Char>
class null_terminating_iterator {
public:
typedef std::ptrdiff_t difference_type;
typedef Char value_type;
typedef const Char* pointer;
typedef const Char& reference;
typedef std::random_access_iterator_tag iterator_category;
null_terminating_iterator() : ptr_(0), end_(0) {}
FMT_CONSTEXPR null_terminating_iterator(const Char *ptr, const Char *end)
: ptr_(ptr), end_(end) {}
template <typename Range>
FMT_CONSTEXPR explicit null_terminating_iterator(const Range &r)
: ptr_(r.begin()), end_(r.end()) {}
FMT_CONSTEXPR null_terminating_iterator &operator=(const Char *ptr) {
assert(ptr <= end_);
ptr_ = ptr;
return *this;
}
FMT_CONSTEXPR Char operator*() const {
return ptr_ != end_ ? *ptr_ : Char();
}
FMT_CONSTEXPR null_terminating_iterator operator++() {
++ptr_;
return *this;
}
FMT_CONSTEXPR null_terminating_iterator operator++(int) {
null_terminating_iterator result(*this);
++ptr_;
return result;
}
FMT_CONSTEXPR null_terminating_iterator operator--() {
--ptr_;
return *this;
}
FMT_CONSTEXPR null_terminating_iterator operator+(difference_type n) {
return null_terminating_iterator(ptr_ + n, end_);
}
FMT_CONSTEXPR null_terminating_iterator operator-(difference_type n) {
return null_terminating_iterator(ptr_ - n, end_);
}
FMT_CONSTEXPR null_terminating_iterator operator+=(difference_type n) {
ptr_ += n;
return *this;
}
FMT_CONSTEXPR difference_type operator-(
null_terminating_iterator other) const {
return ptr_ - other.ptr_;
}
FMT_CONSTEXPR bool operator!=(null_terminating_iterator other) const {
return ptr_ != other.ptr_;
}
bool operator>=(null_terminating_iterator other) const {
return ptr_ >= other.ptr_;
}
// This should be a friend specialization pointer_from<Char> but the latter
// doesn't compile by gcc 5.1 due to a compiler bug.
template <typename CharT>
friend FMT_CONSTEXPR_DECL const CharT *pointer_from(
null_terminating_iterator<CharT> it);
private:
const Char *ptr_;
const Char *end_;
};
template <typename T>
FMT_CONSTEXPR const T *pointer_from(const T *p) { return p; }
template <typename Char>
FMT_CONSTEXPR const Char *pointer_from(null_terminating_iterator<Char> it) {
return it.ptr_;
}
// DEPRECATED: Parses the input as an unsigned integer. This function assumes
// that the first character is a digit and presence of a non-digit character at
// the end.
// it: an iterator pointing to the beginning of the input range.
template <typename Iterator, typename ErrorHandler>
FMT_CONSTEXPR unsigned parse_nonnegative_int(Iterator &it, ErrorHandler &&eh) {
assert('0' <= *it && *it <= '9');
if (*it == '0') {
++it;
return 0;
}
unsigned value = 0;
// Convert to unsigned to prevent a warning.
unsigned max_int = (std::numeric_limits<int>::max)();
unsigned big = max_int / 10;
do {
// Check for overflow.
if (value > big) {
value = max_int + 1;
break;
}
value = value * 10 + unsigned(*it - '0');
// Workaround for MSVC "setup_exception stack overflow" error:
auto next = it;
++next;
it = next;
} while ('0' <= *it && *it <= '9');
if (value > max_int)
eh.on_error("number is too big");
return value;
}
// Checks if a value fits in int - used to avoid warnings about comparing
// signed and unsigned integers.
template <bool IsSigned>
@ -133,7 +257,7 @@ class arg_converter: public function<void> {
// unsigned).
template <typename T, typename Context, typename Char>
void convert_arg(basic_format_arg<Context> &arg, Char type) {
fmt::visit(arg_converter<T, Context>(arg, type), arg);
visit_format_arg(arg_converter<T, Context>(arg, type), arg);
}
// Converts an integer argument to char for printf.
@ -192,8 +316,16 @@ class printf_width_handler: public function<unsigned> {
return 0;
}
};
template <typename Char, typename Context>
void printf(basic_buffer<Char> &buf, basic_string_view<Char> format,
basic_format_args<Context> args) {
Context(std::back_inserter(buf), format, args).format();
}
} // namespace internal
using internal::printf; // For printing into memory_buffer.
template <typename Range>
class printf_arg_formatter;
@ -222,12 +354,12 @@ class printf_arg_formatter:
context_type &context_;
void write_null_pointer(char) {
this->spec()->type_ = 0;
this->spec()->type = 0;
this->write("(nil)");
}
void write_null_pointer(wchar_t) {
this->spec()->type_ = 0;
this->spec()->type = 0;
this->write(L"(nil)");
}
@ -243,7 +375,8 @@ class printf_arg_formatter:
*/
printf_arg_formatter(internal::basic_buffer<char_type> &buffer,
format_specs &spec, context_type &ctx)
: base(back_insert_range<internal::basic_buffer<char_type>>(buffer), &spec),
: base(back_insert_range<internal::basic_buffer<char_type>>(buffer), &spec,
ctx.locale()),
context_(ctx) {}
template <typename T>
@ -253,15 +386,15 @@ class printf_arg_formatter:
// use std::is_same instead.
if (std::is_same<T, bool>::value) {
format_specs &fmt_spec = *this->spec();
if (fmt_spec.type_ != 's')
if (fmt_spec.type != 's')
return base::operator()(value ? 1 : 0);
fmt_spec.type_ = 0;
fmt_spec.type = 0;
this->write(value != 0);
} else if (std::is_same<T, char_type>::value) {
format_specs &fmt_spec = *this->spec();
if (fmt_spec.type_ && fmt_spec.type_ != 'c')
if (fmt_spec.type && fmt_spec.type != 'c')
return (*this)(static_cast<int>(value));
fmt_spec.flags_ = 0;
fmt_spec.flags = 0;
fmt_spec.align_ = ALIGN_RIGHT;
return base::operator()(value);
} else {
@ -280,7 +413,7 @@ class printf_arg_formatter:
iterator operator()(const char *value) {
if (value)
base::operator()(value);
else if (this->spec()->type_ == 'p')
else if (this->spec()->type == 'p')
write_null_pointer(char_type());
else
this->write("(null)");
@ -291,7 +424,7 @@ class printf_arg_formatter:
iterator operator()(const wchar_t *value) {
if (value)
base::operator()(value);
else if (this->spec()->type_ == 'p')
else if (this->spec()->type == 'p')
write_null_pointer(char_type());
else
this->write(L"(null)");
@ -310,7 +443,7 @@ class printf_arg_formatter:
iterator operator()(const void *value) {
if (value)
return base::operator()(value);
this->spec()->type_ = 0;
this->spec()->type = 0;
write_null_pointer(char_type());
return this->out();
}
@ -394,16 +527,16 @@ void basic_printf_context<OutputIt, Char, AF>::parse_flags(
spec.align_ = ALIGN_LEFT;
break;
case '+':
spec.flags_ |= SIGN_FLAG | PLUS_FLAG;
spec.flags |= SIGN_FLAG | PLUS_FLAG;
break;
case '0':
spec.fill_ = '0';
break;
case ' ':
spec.flags_ |= SIGN_FLAG;
spec.flags |= SIGN_FLAG;
break;
case '#':
spec.flags_ |= HASH_FLAG;
spec.flags |= HASH_FLAG;
break;
default:
--it;
@ -453,8 +586,8 @@ unsigned basic_printf_context<OutputIt, Char, AF>::parse_header(
spec.width_ = parse_nonnegative_int(it, eh);
} else if (*it == '*') {
++it;
spec.width_ =
fmt::visit(internal::printf_width_handler<char_type>(spec), get_arg(it));
spec.width_ = visit_format_arg(
internal::printf_width_handler<char_type>(spec), get_arg(it));
}
return arg_index;
}
@ -486,19 +619,19 @@ void basic_printf_context<OutputIt, Char, AF>::format() {
++it;
if ('0' <= *it && *it <= '9') {
internal::error_handler eh;
spec.precision_ = static_cast<int>(parse_nonnegative_int(it, eh));
spec.precision = static_cast<int>(parse_nonnegative_int(it, eh));
} else if (*it == '*') {
++it;
spec.precision_ =
fmt::visit(internal::printf_precision_handler(), get_arg(it));
spec.precision =
visit_format_arg(internal::printf_precision_handler(), get_arg(it));
} else {
spec.precision_ = 0;
spec.precision = 0;
}
}
format_arg arg = get_arg(it, arg_index);
if (spec.flag(HASH_FLAG) && fmt::visit(internal::is_zero_int(), arg))
spec.flags_ &= ~internal::to_unsigned<int>(HASH_FLAG);
if (spec.has(HASH_FLAG) && visit_format_arg(internal::is_zero_int(), arg))
spec.flags = static_cast<uint_least8_t>(spec.flags & (~internal::to_unsigned<int>(HASH_FLAG)));
if (spec.fill_ == '0') {
if (arg.is_arithmetic())
spec.align_ = ALIGN_NUMERIC;
@ -542,16 +675,17 @@ void basic_printf_context<OutputIt, Char, AF>::format() {
// Parse type.
if (!*it)
FMT_THROW(format_error("invalid format string"));
spec.type_ = static_cast<char>(*it++);
spec.type = static_cast<char>(*it++);
if (arg.is_integral()) {
// Normalize type.
switch (spec.type_) {
switch (spec.type) {
case 'i': case 'u':
spec.type_ = 'd';
spec.type = 'd';
break;
case 'c':
// TODO: handle wchar_t better?
fmt::visit(internal::char_converter<basic_printf_context>(arg), arg);
visit_format_arg(
internal::char_converter<basic_printf_context>(arg), arg);
break;
}
}
@ -559,35 +693,50 @@ void basic_printf_context<OutputIt, Char, AF>::format() {
start = it;
// Format argument.
fmt::visit(AF(buffer, spec, *this), arg);
visit_format_arg(AF(buffer, spec, *this), arg);
}
buffer.append(pointer_from(start), pointer_from(it));
}
template <typename Char, typename Context>
void printf(internal::basic_buffer<Char> &buf, basic_string_view<Char> format,
basic_format_args<Context> args) {
Context(std::back_inserter(buf), format, args).format();
}
template <typename Buffer>
struct printf_context {
struct basic_printf_context_t {
typedef basic_printf_context<
std::back_insert_iterator<Buffer>, typename Buffer::value_type> type;
};
template <typename ...Args>
inline format_arg_store<printf_context<internal::buffer>::type, Args...>
make_printf_args(const Args & ... args) {
return format_arg_store<printf_context<internal::buffer>::type, Args...>(
args...);
}
typedef basic_format_args<printf_context<internal::buffer>::type> printf_args;
typedef basic_format_args<printf_context<internal::wbuffer>::type> wprintf_args;
typedef basic_printf_context_t<internal::buffer>::type printf_context;
typedef basic_printf_context_t<internal::wbuffer>::type wprintf_context;
inline std::string vsprintf(string_view format, printf_args args) {
memory_buffer buffer;
printf(buffer, format, args);
typedef basic_format_args<printf_context> printf_args;
typedef basic_format_args<wprintf_context> wprintf_args;
/**
\rst
Constructs an `~fmt::format_arg_store` object that contains references to
arguments and can be implicitly converted to `~fmt::printf_args`.
\endrst
*/
template<typename... Args>
inline format_arg_store<printf_context, Args...>
make_printf_args(const Args &... args) { return {args...}; }
/**
\rst
Constructs an `~fmt::format_arg_store` object that contains references to
arguments and can be implicitly converted to `~fmt::wprintf_args`.
\endrst
*/
template<typename... Args>
inline format_arg_store<wprintf_context, Args...>
make_wprintf_args(const Args &... args) { return {args...}; }
template <typename S, typename Char = FMT_CHAR(S)>
inline std::basic_string<Char>
vsprintf(const S &format,
basic_format_args<typename basic_printf_context_t<
internal::basic_buffer<Char>>::type> args) {
basic_memory_buffer<Char> buffer;
printf(buffer, to_string_view(format), args);
return to_string(buffer);
}
@ -600,30 +749,24 @@ inline std::string vsprintf(string_view format, printf_args args) {
std::string message = fmt::sprintf("The answer is %d", 42);
\endrst
*/
template <typename... Args>
inline std::string sprintf(string_view format_str, const Args & ... args) {
return vsprintf(format_str,
make_format_args<typename printf_context<internal::buffer>::type>(args...));
}
inline std::wstring vsprintf(wstring_view format, wprintf_args args) {
wmemory_buffer buffer;
printf(buffer, format, args);
return to_string(buffer);
}
template <typename... Args>
inline std::wstring sprintf(wstring_view format_str, const Args & ... args) {
return vsprintf(format_str,
make_format_args<typename printf_context<internal::wbuffer>::type>(args...));
template <typename S, typename... Args>
inline FMT_ENABLE_IF_T(
internal::is_string<S>::value, std::basic_string<FMT_CHAR(S)>)
sprintf(const S &format, const Args & ... args) {
internal::check_format_string<Args...>(format);
typedef internal::basic_buffer<FMT_CHAR(S)> buffer;
typedef typename basic_printf_context_t<buffer>::type context;
format_arg_store<context, Args...> as{ args... };
return vsprintf(to_string_view(format),
basic_format_args<context>(as));
}
template <typename Char>
inline int vfprintf(std::FILE *f, basic_string_view<Char> format,
basic_format_args<typename printf_context<
template <typename S, typename Char = FMT_CHAR(S)>
inline int vfprintf(std::FILE *f, const S &format,
basic_format_args<typename basic_printf_context_t<
internal::basic_buffer<Char>>::type> args) {
basic_memory_buffer<Char> buffer;
printf(buffer, format, args);
printf(buffer, to_string_view(format), args);
std::size_t size = buffer.size();
return std::fwrite(
buffer.data(), sizeof(Char), size, f) < size ? -1 : static_cast<int>(size);
@ -638,26 +781,22 @@ inline int vfprintf(std::FILE *f, basic_string_view<Char> format,
fmt::fprintf(stderr, "Don't %s!", "panic");
\endrst
*/
template <typename... Args>
inline int fprintf(std::FILE *f, string_view format_str, const Args & ... args) {
auto vargs = make_format_args<
typename printf_context<internal::buffer>::type>(args...);
return vfprintf<char>(f, format_str, vargs);
}
template <typename... Args>
inline int fprintf(std::FILE *f, wstring_view format_str,
const Args & ... args) {
return vfprintf(f, format_str,
make_format_args<typename printf_context<internal::wbuffer>::type>(args...));
}
inline int vprintf(string_view format, printf_args args) {
return vfprintf(stdout, format, args);
template <typename S, typename... Args>
inline FMT_ENABLE_IF_T(internal::is_string<S>::value, int)
fprintf(std::FILE *f, const S &format, const Args & ... args) {
internal::check_format_string<Args...>(format);
typedef internal::basic_buffer<FMT_CHAR(S)> buffer;
typedef typename basic_printf_context_t<buffer>::type context;
format_arg_store<context, Args...> as{ args... };
return vfprintf(f, to_string_view(format),
basic_format_args<context>(as));
}
inline int vprintf(wstring_view format, wprintf_args args) {
return vfprintf(stdout, format, args);
template <typename S, typename Char = FMT_CHAR(S)>
inline int vprintf(const S &format,
basic_format_args<typename basic_printf_context_t<
internal::basic_buffer<Char>>::type> args) {
return vfprintf(stdout, to_string_view(format), args);
}
/**
@ -669,30 +808,24 @@ inline int vprintf(wstring_view format, wprintf_args args) {
fmt::printf("Elapsed time: %.2f seconds", 1.23);
\endrst
*/
template <typename... Args>
inline int printf(string_view format_str, const Args & ... args) {
return vprintf(format_str,
make_format_args<typename printf_context<internal::buffer>::type>(args...));
}
template <typename... Args>
inline int printf(wstring_view format_str, const Args & ... args) {
return vprintf(format_str,
make_format_args<typename printf_context<internal::wbuffer>::type>(args...));
template <typename S, typename... Args>
inline FMT_ENABLE_IF_T(internal::is_string<S>::value, int)
printf(const S &format_str, const Args & ... args) {
internal::check_format_string<Args...>(format_str);
typedef internal::basic_buffer<FMT_CHAR(S)> buffer;
typedef typename basic_printf_context_t<buffer>::type context;
format_arg_store<context, Args...> as{ args... };
return vprintf(to_string_view(format_str),
basic_format_args<context>(as));
}
inline int vfprintf(std::ostream &os, string_view format_str,
printf_args args) {
memory_buffer buffer;
printf(buffer, format_str, args);
internal::write(os, buffer);
return static_cast<int>(buffer.size());
}
inline int vfprintf(std::wostream &os, wstring_view format_str,
wprintf_args args) {
wmemory_buffer buffer;
printf(buffer, format_str, args);
template <typename S, typename Char = FMT_CHAR(S)>
inline int vfprintf(std::basic_ostream<Char> &os,
const S &format,
basic_format_args<typename basic_printf_context_t<
internal::basic_buffer<Char>>::type> args) {
basic_memory_buffer<Char> buffer;
printf(buffer, to_string_view(format), args);
internal::write(os, buffer);
return static_cast<int>(buffer.size());
}
@ -706,20 +839,16 @@ inline int vfprintf(std::wostream &os, wstring_view format_str,
fmt::fprintf(cerr, "Don't %s!", "panic");
\endrst
*/
template <typename... Args>
inline int fprintf(std::ostream &os, string_view format_str,
const Args & ... args) {
auto vargs = make_format_args<
typename printf_context<internal::buffer>::type>(args...);
return vfprintf(os, format_str, vargs);
}
template <typename... Args>
inline int fprintf(std::wostream &os, wstring_view format_str,
const Args & ... args) {
auto vargs = make_format_args<
typename printf_context<internal::buffer>::type>(args...);
return vfprintf(os, format_str, vargs);
template <typename S, typename... Args>
inline FMT_ENABLE_IF_T(internal::is_string<S>::value, int)
fprintf(std::basic_ostream<FMT_CHAR(S)> &os,
const S &format_str, const Args & ... args) {
internal::check_format_string<Args...>(format_str);
typedef internal::basic_buffer<FMT_CHAR(S)> buffer;
typedef typename basic_printf_context_t<buffer>::type context;
format_arg_store<context, Args...> as{ args... };
return vfprintf(os, to_string_view(format_str),
basic_format_args<context>(as));
}
FMT_END_NAMESPACE

@ -1,6 +1,6 @@
// Formatting library for C++ - time formatting
//
// Copyright (c) 2012 - 2016, Victor Zverovich
// Copyright (c) 2012 - present, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
@ -10,6 +10,7 @@
#include "format.h"
#include <ctime>
#include <locale>
FMT_BEGIN_NAMESPACE
@ -22,7 +23,7 @@ inline null<> localtime_r FMT_NOMACRO(...) { return null<>(); }
inline null<> localtime_s(...) { return null<>(); }
inline null<> gmtime_r(...) { return null<>(); }
inline null<> gmtime_s(...) { return null<>(); }
}
} // namespace internal
// Thread-safe replacement for std::localtime
inline std::tm localtime(std::time_t time) {
@ -46,18 +47,20 @@ inline std::tm localtime(std::time_t time) {
bool fallback(int res) { return res == 0; }
#if !FMT_MSC_VER
bool fallback(internal::null<>) {
using namespace fmt::internal;
std::tm *tm = std::localtime(&time_);
if (tm) tm_ = *tm;
return tm != FMT_NULL;
}
#endif
};
dispatcher lt(time);
if (lt.run())
return lt.tm_;
// Too big time values may be unsupported.
if (!lt.run())
FMT_THROW(format_error("time_t value out of range"));
return lt.tm_;
}
// Thread-safe replacement for std::gmtime
@ -82,17 +85,19 @@ inline std::tm gmtime(std::time_t time) {
bool fallback(int res) { return res == 0; }
#if !FMT_MSC_VER
bool fallback(internal::null<>) {
std::tm *tm = std::gmtime(&time_);
if (tm) tm_ = *tm;
return tm != FMT_NULL;
}
#endif
};
dispatcher gt(time);
if (gt.run())
return gt.tm_;
// Too big time values may be unsupported.
if (!gt.run())
FMT_THROW(format_error("time_t value out of range"));
return gt.tm_;
}
namespace internal {
@ -111,22 +116,21 @@ template <typename Char>
struct formatter<std::tm, Char> {
template <typename ParseContext>
auto parse(ParseContext &ctx) -> decltype(ctx.begin()) {
auto it = internal::null_terminating_iterator<Char>(ctx);
if (*it == ':')
auto it = ctx.begin();
if (it != ctx.end() && *it == ':')
++it;
auto end = it;
while (*end && *end != '}')
while (end != ctx.end() && *end != '}')
++end;
tm_format.reserve(end - it + 1);
using internal::pointer_from;
tm_format.append(pointer_from(it), pointer_from(end));
tm_format.reserve(internal::to_unsigned(end - it + 1));
tm_format.append(it, end);
tm_format.push_back('\0');
return pointer_from(end);
return end;
}
template <typename FormatContext>
auto format(const std::tm &tm, FormatContext &ctx) -> decltype(ctx.out()) {
internal::basic_buffer<Char> &buf = internal::get_container(ctx.out());
basic_memory_buffer<Char> buf;
std::size_t start = buf.size();
for (;;) {
std::size_t size = buf.capacity() - start;
@ -146,7 +150,7 @@ struct formatter<std::tm, Char> {
const std::size_t MIN_GROWTH = 10;
buf.reserve(buf.capacity() + (size > MIN_GROWTH ? size : MIN_GROWTH));
}
return ctx.out();
return std::copy(buf.begin(), buf.end(), ctx.out());
}
basic_memory_buffer<Char> tm_format;

@ -22,7 +22,6 @@
#include "spdlog/formatter.h"
#include "spdlog/sinks/sink.h"
#include <locale>
#include <memory>
#include <string>
#include <vector>
@ -46,8 +45,13 @@ public:
template<typename... Args>
void log(level::level_enum lvl, const char *fmt, const Args &... args);
template<typename... Args>
void log(source_loc loc, level::level_enum lvl, const char *fmt, const Args &... args);
void log(level::level_enum lvl, const char *msg);
void log(source_loc loc, level::level_enum lvl, const char *msg);
template<typename... Args>
void trace(const char *fmt, const Args &... args);
@ -73,6 +77,9 @@ public:
template<typename... Args>
void log(level::level_enum lvl, const wchar_t *fmt, const Args &... args);
template<typename... Args>
void log(source_loc source, level::level_enum lvl, const wchar_t *fmt, const Args &... args);
template<typename... Args>
void trace(const wchar_t *fmt, const Args &... args);
@ -97,10 +104,18 @@ public:
template<class T, typename std::enable_if<std::is_convertible<T, spdlog::string_view_t>::value, T>::type * = nullptr>
void log(level::level_enum lvl, const T &);
// T can be statically converted to string_view
template<class T, typename std::enable_if<std::is_convertible<T, spdlog::string_view_t>::value, T>::type * = nullptr>
void log(source_loc loc, level::level_enum lvl, const T &);
// T cannot be statically converted to string_view
template<class T, typename std::enable_if<!std::is_convertible<T, spdlog::string_view_t>::value, T>::type * = nullptr>
void log(level::level_enum lvl, const T &);
// T cannot be statically converted to string_view
template<class T, typename std::enable_if<!std::is_convertible<T, spdlog::string_view_t>::value, T>::type * = nullptr>
void log(source_loc loc, level::level_enum lvl, const T &);
template<typename T>
void trace(const T &msg);

@ -6,7 +6,7 @@
#pragma once
#ifndef SPDLOG_H
#error "spdlog.h must be included before this file."
#include "spdlog/spdlog.h"
#endif
#include "spdlog/details/fmt_helper.h"

@ -6,7 +6,7 @@
#pragma once
#ifndef SPDLOG_H
#error "spdlog.h must be included before this file."
#include "spdlog/spdlog.h"
#endif
#include "spdlog/details/console_globals.h"

@ -6,7 +6,7 @@
#pragma once
#ifndef SPDLOG_H
#error "spdlog.h must be included before this file."
#include "spdlog/spdlog.h"
#endif
#include "spdlog/details/file_helper.h"

@ -6,7 +6,7 @@
#pragma once
#ifndef SPDLOG_H
#error "spdlog.h must be included before this file."
#include "spdlog/spdlog.h"
#endif
#include "spdlog/details/file_helper.h"
@ -32,7 +32,7 @@ struct daily_filename_calculator
static filename_t calc_filename(const filename_t &filename, const tm &now_tm)
{
filename_t basename, ext;
std::tie(basename, ext) = details::file_helper::split_by_extenstion(filename);
std::tie(basename, ext) = details::file_helper::split_by_extension(filename);
std::conditional<std::is_same<filename_t::value_type, char>::value, fmt::memory_buffer, fmt::wmemory_buffer>::type w;
fmt::format_to(
w, SPDLOG_FILENAME_T("{}_{:04d}-{:02d}-{:02d}{}"), basename, now_tm.tm_year + 1900, now_tm.tm_mon + 1, now_tm.tm_mday, ext);

@ -6,7 +6,7 @@
#pragma once
#ifndef SPDLOG_H
#error "spdlog.h must be included before this file."
#include "spdlog/spdlog.h"
#endif
#include "base_sink.h"

@ -6,7 +6,7 @@
#pragma once
#ifndef SPDLOG_H
#error "spdlog.h must be included before this file."
#include "spdlog/spdlog.h"
#endif
#if defined(_WIN32)

@ -6,7 +6,7 @@
#pragma once
#ifndef SPDLOG_H
#error "spdlog.h must be included before this file."
#include "spdlog/spdlog.h"
#endif
#include "spdlog/details/null_mutex.h"

@ -6,7 +6,7 @@
#pragma once
#ifndef SPDLOG_H
#error "spdlog.h must be included before this file."
#include "spdlog/spdlog.h"
#endif
#include "spdlog/details/null_mutex.h"

@ -6,7 +6,7 @@
#pragma once
#ifndef SPDLOG_H
#error "spdlog.h must be included before this file."
#include "spdlog/spdlog.h"
#endif
#include "spdlog/details/file_helper.h"
@ -48,7 +48,7 @@ public:
if (index != 0u)
{
filename_t basename, ext;
std::tie(basename, ext) = details::file_helper::split_by_extenstion(filename);
std::tie(basename, ext) = details::file_helper::split_by_extension(filename);
fmt::format_to(w, SPDLOG_FILENAME_T("{}.{}{}"), basename, index, ext);
}
else
@ -105,6 +105,7 @@ private:
if (!rename_file(src, target))
{
file_helper_.reopen(true); // truncate the log file anyway to prevent it to grow beyond its limit!
current_size_ = 0;
throw spdlog_ex(
"rotating_file_sink: failed renaming " + filename_to_str(src) + " to " + filename_to_str(target), errno);
}

@ -6,7 +6,7 @@
#pragma once
#ifndef SPDLOG_H
#error "spdlog.h must be included before this file."
#include "spdlog/spdlog.h"
#endif
#ifdef _WIN32

@ -6,7 +6,7 @@
#pragma once
#ifndef SPDLOG_H
#error "spdlog.h must be included before this file."
#include "spdlog/spdlog.h"
#endif
#include "spdlog/details/console_globals.h"

@ -6,7 +6,7 @@
#pragma once
#ifndef SPDLOG_H
#error "spdlog.h must be included before this file."
#include "spdlog/spdlog.h"
#endif
#include "spdlog/sinks/base_sink.h"

@ -6,7 +6,7 @@
#pragma once
#ifndef SPDLOG_H
#error "spdlog.h must be included before this file."
#include "spdlog/spdlog.h"
#endif
#include "spdlog/common.h"

@ -161,10 +161,16 @@ inline void set_default_logger(std::shared_ptr<spdlog::logger> default_logger)
details::registry::instance().set_default_logger(std::move(default_logger));
}
template<typename... Args>
inline void log(source_loc source, level::level_enum lvl, const char *fmt, const Args &... args)
{
default_logger_raw()->log(source, lvl, fmt, args...);
}
template<typename... Args>
inline void log(level::level_enum lvl, const char *fmt, const Args &... args)
{
default_logger_raw()->log(lvl, fmt, args...);
default_logger_raw()->log(source_loc{}, lvl, fmt, args...);
}
template<typename... Args>
@ -290,58 +296,71 @@ inline void critical(const wchar_t *fmt, const Args &... args)
#endif // SPDLOG_WCHAR_TO_UTF8_SUPPORT
} // namespace spdlog
//
// enable/disable log calls at compile time according to global level.
//
// compile time macros.
// can be enabled/disabled using SPDLOG_ACTIVE_LEVEL (info by default).
// define SPDLOG_ACTIVE_LEVEL to one of those (before including spdlog.h):
// SPDLOG_LEVEL_TRACE,
// SPDLOG_LEVEL_DEBUG,
// SPDLOG_LEVEL_INFO,
// SPDLOG_LEVEL_WARN,
// SPDLOG_LEVEL_ERROR,
// SPDLOG_LEVEL_CRITICAL,
// SPDLOG_LEVEL_OFF
//
#define SPDLOG_LOGGER_CALL(logger, level, ...) \
if (logger->should_log(level)) \
logger->log(spdlog::source_loc{SPDLOG_FILE_BASENAME(__FILE__), __LINE__, SPDLOG_FUNCTION}, level, __VA_ARGS__)
#if SPDLOG_ACTIVE_LEVEL <= SPDLOG_LEVEL_TRACE
#define SPDLOG_LOGGER_TRACE(logger, ...) logger->trace(__VA_ARGS__)
#define SPDLOG_TRACE(...) spdlog::trace(__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
#endif
#if SPDLOG_ACTIVE_LEVEL <= SPDLOG_LEVEL_DEBUG
#define SPDLOG_LOGGER_DEBUG(logger, ...) logger->debug(__VA_ARGS__)
#define SPDLOG_DEBUG(...) spdlog::debug(__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
#endif
#if SPDLOG_ACTIVE_LEVEL <= SPDLOG_LEVEL_INFO
#define SPDLOG_LOGGER_INFO(logger, ...) logger->info(__VA_ARGS__)
#define SPDLOG_INFO(...) spdlog::info(__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
#endif
#if SPDLOG_ACTIVE_LEVEL <= SPDLOG_LEVEL_WARN
#define SPDLOG_LOGGER_WARN(logger, ...) logger->warn(__VA_ARGS__)
#define SPDLOG_WARN(...) spdlog::warn(__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
#endif
#if SPDLOG_ACTIVE_LEVEL <= SPDLOG_LEVEL_ERROR
#define SPDLOG_LOGGER_ERROR(logger, ...) logger->error(__VA_ARGS__)
#define SPDLOG_ERROR(...) spdlog::error(__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
#endif
#if SPDLOG_ACTIVE_LEVEL <= SPDLOG_LEVEL_CRITICAL
#define SPDLOG_LOGGER_CRITICAL(logger, ...) logger->critical(__VA_ARGS__)
#define SPDLOG_CRITICAL(...) spdlog::critical(__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
#endif
} // namespace spdlog
#endif // SPDLOG_H

@ -45,13 +45,12 @@
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// Uncomment to prevent spdlog from caching thread ids in thread local storage.
// By default spdlog saves thread ids in tls to gain a few micros for each call.
// Uncomment to prevent spdlog from using thread local storage.
//
// WARNING: if your program forks, UNCOMMENT this flag to prevent undefined
// thread ids in the children logs.
//
// #define SPDLOG_DISABLE_TID_CACHING
// #define SPDLOG_NO_TLS
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
@ -135,3 +134,12 @@
//
// #define SPDLOG_ACTIVE_LEVEL SPDLOG_LEVEL_INFO
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// Uncomment (and change if desired) macro to use for function names.
// This is compiler dependent.
// __PRETTY_FUNCTION__ might be nicer in clang/gcc, and __FUNCTION__ in msvc.
// Defaults to __FUNCTION__ (should work on all compilers) if not defined.
//
// #define SPDLOG_FUNCTION __PRETTY_FUNCTION__
///////////////////////////////////////////////////////////////////////////////

@ -3,9 +3,9 @@ project(spdlog-utests CXX)
find_package(Threads REQUIRED)
set(SPDLOG_UTESTS_SOURCES
errors.cpp
file_helper.cpp
file_log.cpp
test_errors.cpp
test_file_helper.cpp
test_file_logging.cpp
test_misc.cpp
test_pattern_formatter.cpp
test_async.cpp

@ -81,12 +81,12 @@ static void test_split_ext(const char *fname, const char *expect_base, const cha
std::replace(expected_base.begin(), expected_base.end(), '/', '\\');
#endif
spdlog::filename_t basename, ext;
std::tie(basename, ext) = file_helper::split_by_extenstion(filename);
std::tie(basename, ext) = file_helper::split_by_extension(filename);
REQUIRE(basename == expected_base);
REQUIRE(ext == expected_ext);
}
TEST_CASE("file_helper_split_by_extenstion", "[file_helper::split_by_extenstion()]]")
TEST_CASE("file_helper_split_by_extension", "[file_helper::split_by_extension()]]")
{
test_split_ext("mylog.txt", "mylog", ".txt");
test_split_ext(".mylog.txt", ".mylog", ".txt");

@ -8,7 +8,7 @@ void test_pad2(int n, const char *expected)
REQUIRE(fmt::to_string(buf) == expected);
}
void test_pad3(int n, const char *expected)
void test_pad3(uint32_t n, const char *expected)
{
fmt::memory_buffer buf;
spdlog::details::fmt_helper::pad3(n, buf);
@ -22,6 +22,13 @@ void test_pad6(std::size_t n, const char *expected)
REQUIRE(fmt::to_string(buf) == expected);
}
void test_pad9(std::size_t n, const char *expected)
{
fmt::memory_buffer buf;
spdlog::details::fmt_helper::pad9(n, buf);
REQUIRE(fmt::to_string(buf) == expected);
}
TEST_CASE("pad2", "[fmt_helper]")
{
test_pad2(0, "00");
@ -39,7 +46,6 @@ TEST_CASE("pad3", "[fmt_helper]")
test_pad3(23, "023");
test_pad3(123, "123");
test_pad3(1234, "1234");
test_pad3(-5, "-05");
}
TEST_CASE("pad6", "[fmt_helper]")
@ -52,3 +58,18 @@ TEST_CASE("pad6", "[fmt_helper]")
test_pad6(12345, "012345");
test_pad6(123456, "123456");
}
TEST_CASE("pad9", "[fmt_helper]")
{
test_pad9(0, "000000000");
test_pad9(3, "000000003");
test_pad9(23, "000000023");
test_pad9(123, "000000123");
test_pad9(1234, "000001234");
test_pad9(12345, "000012345");
test_pad9(123456, "000123456");
test_pad9(1234567, "001234567");
test_pad9(12345678, "012345678");
test_pad9(123456789, "123456789");
test_pad9(1234567891, "1234567891");
}

@ -24,6 +24,15 @@ TEST_CASE("debug and trace w/o format string", "[macros]]")
REQUIRE(ends_with(file_contents(filename), "Test message 2\n"));
REQUIRE(count_lines(filename) == 1);
spdlog::set_default_logger(logger);
SPDLOG_TRACE("Test message 3");
SPDLOG_DEBUG("Test message {}", 4);
logger->flush();
REQUIRE(ends_with(file_contents(filename), "Test message 4\n"));
REQUIRE(count_lines(filename) == 2);
}
TEST_CASE("disable param evaluation", "[macros]")

@ -43,15 +43,15 @@ TEST_CASE("log_levels", "[log_levels]")
REQUIRE(log_info("Hello", spdlog::level::trace) == "Hello");
}
TEST_CASE("to_c_str", "[convert_to_c_str]")
TEST_CASE("level_to_string_view", "[convert_to_string_view")
{
REQUIRE(std::string(spdlog::level::to_c_str(spdlog::level::trace)) == "trace");
REQUIRE(std::string(spdlog::level::to_c_str(spdlog::level::debug)) == "debug");
REQUIRE(std::string(spdlog::level::to_c_str(spdlog::level::info)) == "info");
REQUIRE(std::string(spdlog::level::to_c_str(spdlog::level::warn)) == "warning");
REQUIRE(std::string(spdlog::level::to_c_str(spdlog::level::err)) == "error");
REQUIRE(std::string(spdlog::level::to_c_str(spdlog::level::critical)) == "critical");
REQUIRE(std::string(spdlog::level::to_c_str(spdlog::level::off)) == "off");
REQUIRE(spdlog::level::to_string_view(spdlog::level::trace) == "trace");
REQUIRE(spdlog::level::to_string_view(spdlog::level::debug) == "debug");
REQUIRE(spdlog::level::to_string_view(spdlog::level::info) == "info");
REQUIRE(spdlog::level::to_string_view(spdlog::level::warn) == "warning");
REQUIRE(spdlog::level::to_string_view(spdlog::level::err) == "error");
REQUIRE(spdlog::level::to_string_view(spdlog::level::critical) == "critical");
REQUIRE(spdlog::level::to_string_view(spdlog::level::off) == "off");
}
TEST_CASE("to_short_c_str", "[convert_to_short_c_str]")
@ -86,7 +86,7 @@ TEST_CASE("periodic flush", "[periodic_flush]")
auto test_sink = std::static_pointer_cast<sinks::test_sink_mt>(logger->sinks()[0]);
spdlog::flush_every(std::chrono::seconds(1));
std::this_thread::sleep_for(std::chrono::milliseconds(1100));
std::this_thread::sleep_for(std::chrono::milliseconds(1250));
REQUIRE(test_sink->flush_counter() == 1);
spdlog::flush_every(std::chrono::seconds(0));
spdlog::drop_all();

@ -16,7 +16,6 @@ static std::string log_to_str(const std::string &msg, const Args &... args)
return oss.str();
}
TEST_CASE("custom eol", "[pattern_formatter]")
{
std::string msg = "Hello custom eol test";
@ -208,7 +207,7 @@ TEST_CASE("clone-default-formatter", "[pattern_formatter]")
formatter_1->format(msg, formatted_1);
formatter_2->format(msg, formatted_2);
REQUIRE( fmt::to_string(formatted_1) == fmt::to_string(formatted_2));
REQUIRE(fmt::to_string(formatted_1) == fmt::to_string(formatted_2));
}
TEST_CASE("clone-default-formatter2", "[pattern_formatter]")
@ -223,7 +222,7 @@ TEST_CASE("clone-default-formatter2", "[pattern_formatter]")
formatter_1->format(msg, formatted_1);
formatter_2->format(msg, formatted_2);
REQUIRE( fmt::to_string(formatted_1) == fmt::to_string(formatted_2));
REQUIRE(fmt::to_string(formatted_1) == fmt::to_string(formatted_2));
}
TEST_CASE("clone-formatter", "[pattern_formatter]")
@ -240,7 +239,6 @@ TEST_CASE("clone-formatter", "[pattern_formatter]")
REQUIRE(fmt::to_string(formatted_1) == fmt::to_string(formatted_2));
}
TEST_CASE("clone-formatter-2", "[pattern_formatter]")
{
using spdlog::pattern_time_type;

@ -83,7 +83,7 @@ TEST_CASE("drop non existing", "[registry]")
TEST_CASE("default logger", "[registry]")
{
spdlog::drop_all();
spdlog::set_default_logger(std::move(spdlog::null_logger_st(tested_logger_name)));
spdlog::set_default_logger(spdlog::null_logger_st(tested_logger_name));
REQUIRE(spdlog::get(tested_logger_name) == spdlog::default_logger());
spdlog::drop_all();
}
@ -110,4 +110,5 @@ TEST_CASE("disable automatic registration", "[registry]")
REQUIRE(logger1->level() == log_level);
REQUIRE(logger2->level() == log_level);
spdlog::set_level(spdlog::level::info);
spdlog::set_automatic_registration(true);
}

Loading…
Cancel
Save