4
.github/workflows/build.yml
vendored
4
.github/workflows/build.yml
vendored
@@ -13,14 +13,14 @@ jobs:
|
|||||||
- name: Update package database
|
- name: Update package database
|
||||||
run: sudo apt -y update
|
run: sudo apt -y update
|
||||||
- name: Install deps
|
- name: Install deps
|
||||||
run: sudo apt -y install git make gcc-10 g++-10 ccache cmake libyaml-cpp-dev libfmt-dev libspdlog-dev clang-12 libclang-12-dev libclang-cpp12-dev lcov
|
run: sudo apt -y install git make gcc-10 g++-10 ccache cmake libyaml-cpp-dev clang-12 libclang-12-dev libclang-cpp12-dev lcov
|
||||||
- name: Select g++ version
|
- name: Select g++ version
|
||||||
run: |
|
run: |
|
||||||
sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-10 10
|
sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-10 10
|
||||||
sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-10 10
|
sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-10 10
|
||||||
- name: Build and unit test
|
- name: Build and unit test
|
||||||
run: |
|
run: |
|
||||||
NUMPROC=2 CMAKE_CXX_FLAGS="--coverage -fno-inline" make test
|
NUMPROC=2 CMAKE_CXX_FLAGS="--coverage -fno-inline" CMAKE_EXE_LINKER_FLAGS="-lgcov --coverage" make test
|
||||||
- name: Run coverage
|
- name: Run coverage
|
||||||
run: |
|
run: |
|
||||||
lcov -c -d debug -o coverage.info
|
lcov -c -d debug -o coverage.info
|
||||||
|
|||||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -26,4 +26,5 @@ coverage*.info
|
|||||||
# CLion
|
# CLion
|
||||||
|
|
||||||
.idea/
|
.idea/
|
||||||
cmake-build-debug/
|
cmake-build-
|
||||||
|
cmake-build-*
|
||||||
|
|||||||
@@ -23,19 +23,6 @@ if(LLVM_CONFIG_PATH)
|
|||||||
set(LLVM_CONFIG_BINARY ${LLVM_CONFIG_PATH})
|
set(LLVM_CONFIG_BINARY ${LLVM_CONFIG_PATH})
|
||||||
endif(LLVM_CONFIG_PATH)
|
endif(LLVM_CONFIG_PATH)
|
||||||
|
|
||||||
message(STATUS "Checking for fmt...")
|
|
||||||
find_package(fmt REQUIRED)
|
|
||||||
|
|
||||||
message(STATUS "Checking for spdlog...")
|
|
||||||
find_package(spdlog REQUIRED)
|
|
||||||
if(APPLE)
|
|
||||||
get_target_property(SPDLOG_INCLUDE_DIRS spdlog::spdlog_header_only INTERFACE_INCLUDE_DIRECTORIES)
|
|
||||||
else(APPLE)
|
|
||||||
get_target_property(SPDLOG_INCLUDE_DIRS spdlog::spdlog INTERFACE_INCLUDE_DIRECTORIES)
|
|
||||||
add_definitions(-DSPDLOG_FMT_EXTERNAL)
|
|
||||||
endif(APPLE)
|
|
||||||
|
|
||||||
|
|
||||||
message(STATUS "Checking for yaml-cpp...")
|
message(STATUS "Checking for yaml-cpp...")
|
||||||
find_package(yaml-cpp REQUIRED)
|
find_package(yaml-cpp REQUIRED)
|
||||||
|
|
||||||
@@ -46,7 +33,8 @@ set(LLVM_PREFERRED_VERSION 12.0.0)
|
|||||||
# to use custom LLVM version
|
# to use custom LLVM version
|
||||||
find_package(LibClang REQUIRED)
|
find_package(LibClang REQUIRED)
|
||||||
|
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17 ${LIBCLANG_CXXFLAGS}")
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror -Wall -Wextra -std=c++17 ${LIBCLANG_CXXFLAGS}")
|
||||||
|
|
||||||
message(STATUS "Using CMAKE_CXX_FLAGS: ${CMAKE_CXX_FLAGS}")
|
message(STATUS "Using CMAKE_CXX_FLAGS: ${CMAKE_CXX_FLAGS}")
|
||||||
|
|
||||||
# Thirdparty sources
|
# Thirdparty sources
|
||||||
@@ -67,7 +55,6 @@ if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
|||||||
endif()
|
endif()
|
||||||
include_directories(${CLANG_UML_INSTALL_INCLUDE_DIR})
|
include_directories(${CLANG_UML_INSTALL_INCLUDE_DIR})
|
||||||
include_directories(${YAML_CPP_INCLUDE_DIR})
|
include_directories(${YAML_CPP_INCLUDE_DIR})
|
||||||
include_directories(${SPDLOG_INCLUDE_DIRS})
|
|
||||||
include_directories(${UML_HEADERS_DIR})
|
include_directories(${UML_HEADERS_DIR})
|
||||||
include_directories(${THIRDPARTY_HEADERS_DIR})
|
include_directories(${THIRDPARTY_HEADERS_DIR})
|
||||||
include_directories(${THIRDPARTY_HEADERS_DIR}/cppast/include)
|
include_directories(${THIRDPARTY_HEADERS_DIR}/cppast/include)
|
||||||
@@ -83,12 +70,7 @@ add_library(clang-umllib OBJECT ${SOURCES})
|
|||||||
|
|
||||||
add_executable(clang-uml ${MAIN_SOURCE_FILE})
|
add_executable(clang-uml ${MAIN_SOURCE_FILE})
|
||||||
install(TARGETS clang-uml DESTINATION ${CLANG_UML_INSTALL_BIN_DIR})
|
install(TARGETS clang-uml DESTINATION ${CLANG_UML_INSTALL_BIN_DIR})
|
||||||
target_link_libraries(clang-uml ${LIBCLANG_LIBRARIES} ${YAML_CPP_LIBRARIES} fmt::fmt cppast clang-umllib)
|
target_link_libraries(clang-uml ${LIBCLANG_LIBRARIES} ${YAML_CPP_LIBRARIES} cppast clang-umllib)
|
||||||
if(APPLE)
|
|
||||||
target_link_libraries(clang-uml spdlog::spdlog_header_only)
|
|
||||||
else(APPLE)
|
|
||||||
target_link_libraries(clang-uml spdlog::spdlog)
|
|
||||||
endif(APPLE)
|
|
||||||
|
|
||||||
target_compile_features(clang-uml PRIVATE cxx_std_17)
|
target_compile_features(clang-uml PRIVATE cxx_std_17)
|
||||||
|
|
||||||
|
|||||||
7
Makefile
7
Makefile
@@ -24,6 +24,7 @@ NUMPROC ?= $(shell nproc)
|
|||||||
|
|
||||||
LLVM_CONFIG_PATH ?=
|
LLVM_CONFIG_PATH ?=
|
||||||
CMAKE_CXX_FLAGS ?=
|
CMAKE_CXX_FLAGS ?=
|
||||||
|
CMAKE_EXE_LINKER_FLAGS ?=
|
||||||
|
|
||||||
.PHONY: clean
|
.PHONY: clean
|
||||||
clean:
|
clean:
|
||||||
@@ -34,12 +35,15 @@ debug/CMakeLists.txt:
|
|||||||
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
||||||
-DCMAKE_BUILD_TYPE=Debug \
|
-DCMAKE_BUILD_TYPE=Debug \
|
||||||
-DCMAKE_CXX_FLAGS="$(CMAKE_CXX_FLAGS)" \
|
-DCMAKE_CXX_FLAGS="$(CMAKE_CXX_FLAGS)" \
|
||||||
|
-DCMAKE_EXE_LINKER_FLAGS="$(CMAKE_EXE_LINKER_FLAGS)" \
|
||||||
-DLLVM_CONFIG_PATH=$(LLVM_CONFIG_PATH)
|
-DLLVM_CONFIG_PATH=$(LLVM_CONFIG_PATH)
|
||||||
|
|
||||||
release/CMakeLists.txt:
|
release/CMakeLists.txt:
|
||||||
cmake -S . -B release \
|
cmake -S . -B release \
|
||||||
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
||||||
-DCMAKE_BUILD_TYPE=Release \
|
-DCMAKE_BUILD_TYPE=Release \
|
||||||
|
-DCMAKE_CXX_FLAGS="$(CMAKE_CXX_FLAGS)" \
|
||||||
|
-DCMAKE_EXE_LINKER_FLAGS="$(CMAKE_EXE_LINKER_FLAGS)" \
|
||||||
-DLLVM_CONFIG_PATH=$(LLVM_CONFIG_PATH)
|
-DLLVM_CONFIG_PATH=$(LLVM_CONFIG_PATH)
|
||||||
|
|
||||||
debug: debug/CMakeLists.txt
|
debug: debug/CMakeLists.txt
|
||||||
@@ -52,6 +56,9 @@ release: release/CMakeLists.txt
|
|||||||
test: debug
|
test: debug
|
||||||
CTEST_OUTPUT_ON_FAILURE=1 make -C debug test
|
CTEST_OUTPUT_ON_FAILURE=1 make -C debug test
|
||||||
|
|
||||||
|
test_release: release
|
||||||
|
CTEST_OUTPUT_ON_FAILURE=1 make -C release test
|
||||||
|
|
||||||
test_plantuml: test
|
test_plantuml: test
|
||||||
plantuml -tsvg debug/tests/puml/*.puml
|
plantuml -tsvg debug/tests/puml/*.puml
|
||||||
|
|
||||||
|
|||||||
@@ -40,10 +40,10 @@ that you have the following dependencies installed:
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Ubuntu
|
# Ubuntu
|
||||||
apt install ccache cmake libyaml-cpp-dev libfmt-dev libspdlog-dev clang-12 libclang-12-dev libclang-cpp12-dev
|
apt install ccache cmake libyaml-cpp-dev clang-12 libclang-12-dev libclang-cpp12-dev
|
||||||
|
|
||||||
# macos
|
# macos
|
||||||
brew install ccache cmake llvm fmt spdlog yaml-cpp
|
brew install ccache cmake llvm yaml-cpp
|
||||||
```
|
```
|
||||||
|
|
||||||
Then proceed with building the sources:
|
Then proceed with building the sources:
|
||||||
|
|||||||
@@ -250,6 +250,7 @@ void generator::generate_relationships(
|
|||||||
|
|
||||||
std::stringstream all_relations_str;
|
std::stringstream all_relations_str;
|
||||||
std::set<std::string> unique_relations;
|
std::set<std::string> unique_relations;
|
||||||
|
|
||||||
for (const auto &r : c.relationships()) {
|
for (const auto &r : c.relationships()) {
|
||||||
if (!m_model.should_include(r.type()))
|
if (!m_model.should_include(r.type()))
|
||||||
continue;
|
continue;
|
||||||
@@ -450,8 +451,6 @@ void generator::generate(const package &p, std::ostream &ostr) const
|
|||||||
void generator::generate_relationships(
|
void generator::generate_relationships(
|
||||||
const package &p, std::ostream &ostr) const
|
const package &p, std::ostream &ostr) const
|
||||||
{
|
{
|
||||||
const auto &uns = m_config.using_namespace();
|
|
||||||
|
|
||||||
for (const auto &subpackage : p) {
|
for (const auto &subpackage : p) {
|
||||||
if (dynamic_cast<package *>(subpackage.get())) {
|
if (dynamic_cast<package *>(subpackage.get())) {
|
||||||
// TODO: add option - generate_empty_packages
|
// TODO: add option - generate_empty_packages
|
||||||
|
|||||||
@@ -174,7 +174,7 @@ int class_::calculate_template_specialization_match(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Iterate over all template arguments
|
// Iterate over all template arguments
|
||||||
for (int i = 0; i < other.templates().size(); i++) {
|
for (auto i = 0U; i < other.templates().size(); i++) {
|
||||||
const auto &template_arg = templates().at(i);
|
const auto &template_arg = templates().at(i);
|
||||||
const auto &other_template_arg = other.templates().at(i);
|
const auto &other_template_arg = other.templates().at(i);
|
||||||
|
|
||||||
|
|||||||
@@ -28,6 +28,8 @@ public:
|
|||||||
class_member(common::model::access_t access, const std::string &name,
|
class_member(common::model::access_t access, const std::string &name,
|
||||||
const std::string &type);
|
const std::string &type);
|
||||||
|
|
||||||
|
virtual ~class_member() = default;
|
||||||
|
|
||||||
bool is_relationship() const;
|
bool is_relationship() const;
|
||||||
void is_relationship(bool is_relationship);
|
void is_relationship(bool is_relationship);
|
||||||
|
|
||||||
|
|||||||
@@ -139,8 +139,9 @@ bool diagram::add_class(std::unique_ptr<class_> &&c)
|
|||||||
|
|
||||||
const auto &el = get_element<class_>(name_and_ns).value();
|
const auto &el = get_element<class_>(name_and_ns).value();
|
||||||
|
|
||||||
assert(el.name() == name);
|
if ((el.name() != name) || !(el.get_relative_namespace() == ns))
|
||||||
assert(el.get_relative_namespace() == ns);
|
throw std::runtime_error(
|
||||||
|
"Invalid element stored in the diagram tree");
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,7 +19,6 @@
|
|||||||
#include "template_parameter.h"
|
#include "template_parameter.h"
|
||||||
#include "common/model/enums.h"
|
#include "common/model/enums.h"
|
||||||
#include <common/model/namespace.h>
|
#include <common/model/namespace.h>
|
||||||
#include <fmt/format.h>
|
|
||||||
|
|
||||||
namespace clanguml::class_diagram::model {
|
namespace clanguml::class_diagram::model {
|
||||||
|
|
||||||
|
|||||||
@@ -139,7 +139,7 @@ void translation_unit_visitor::operator()(const cppast::cpp_entity &file)
|
|||||||
|
|
||||||
auto &cls = static_cast<const cppast::cpp_class &>(e);
|
auto &cls = static_cast<const cppast::cpp_class &>(e);
|
||||||
if (cppast::get_definition(ctx.entity_index(), cls)) {
|
if (cppast::get_definition(ctx.entity_index(), cls)) {
|
||||||
auto &clsdef = static_cast<const cppast::cpp_class &>(
|
const auto &clsdef = static_cast<const cppast::cpp_class &>(
|
||||||
cppast::get_definition(ctx.entity_index(), cls)
|
cppast::get_definition(ctx.entity_index(), cls)
|
||||||
.value());
|
.value());
|
||||||
if (&cls != &clsdef) {
|
if (&cls != &clsdef) {
|
||||||
@@ -862,7 +862,7 @@ void translation_unit_visitor::process_field(
|
|||||||
if (m.skip())
|
if (m.skip())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
auto &tr = cx::util::unreferenced(cppast::remove_cv(mv.type()));
|
const auto &tr = cx::util::unreferenced(cppast::remove_cv(mv.type()));
|
||||||
|
|
||||||
auto tr_declaration = cppast::to_string(tr);
|
auto tr_declaration = cppast::to_string(tr);
|
||||||
|
|
||||||
@@ -901,10 +901,10 @@ void translation_unit_visitor::process_field(
|
|||||||
!template_instantiation_added_as_aggregation &&
|
!template_instantiation_added_as_aggregation &&
|
||||||
(tr.kind() != cppast::cpp_type_kind::builtin_t) &&
|
(tr.kind() != cppast::cpp_type_kind::builtin_t) &&
|
||||||
(tr.kind() != cppast::cpp_type_kind::template_parameter_t)) {
|
(tr.kind() != cppast::cpp_type_kind::template_parameter_t)) {
|
||||||
const auto &ttt = resolve_alias(mv.type());
|
|
||||||
|
|
||||||
found_relationships_t relationships;
|
found_relationships_t relationships;
|
||||||
auto found = find_relationships(ttt, relationships);
|
|
||||||
|
const auto &unaliased_type = resolve_alias(mv.type());
|
||||||
|
find_relationships(unaliased_type, relationships);
|
||||||
|
|
||||||
for (const auto &[type, relationship_type] : relationships) {
|
for (const auto &[type, relationship_type] : relationships) {
|
||||||
if (relationship_type != relationship_t::kNone) {
|
if (relationship_type != relationship_t::kNone) {
|
||||||
@@ -995,7 +995,8 @@ void translation_unit_visitor::process_method(
|
|||||||
if (m.skip())
|
if (m.skip())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for (auto ¶m : mf.parameters())
|
const auto params = mf.parameters();
|
||||||
|
for (auto ¶m : params)
|
||||||
process_function_parameter(param, m, c);
|
process_function_parameter(param, m, c);
|
||||||
|
|
||||||
LOG_DBG("Adding method: {}", m.name());
|
LOG_DBG("Adding method: {}", m.name());
|
||||||
@@ -1040,11 +1041,13 @@ void translation_unit_visitor::process_template_method(
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
std::set<std::string> template_parameter_names;
|
std::set<std::string> template_parameter_names;
|
||||||
for (const auto &template_parameter : mf.parameters()) {
|
const auto template_params = mf.parameters();
|
||||||
|
for (const auto &template_parameter : template_params) {
|
||||||
template_parameter_names.emplace(template_parameter.name());
|
template_parameter_names.emplace(template_parameter.name());
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto ¶m : mf.function().parameters())
|
const auto params = mf.function().parameters();
|
||||||
|
for (auto ¶m : params)
|
||||||
process_function_parameter(param, m, c, template_parameter_names);
|
process_function_parameter(param, m, c, template_parameter_names);
|
||||||
|
|
||||||
LOG_DBG("Adding template method: {}", m.name());
|
LOG_DBG("Adding template method: {}", m.name());
|
||||||
@@ -1229,6 +1232,9 @@ void translation_unit_visitor::
|
|||||||
auto &template_instantiation_type =
|
auto &template_instantiation_type =
|
||||||
static_cast<const cppast::cpp_template_instantiation_type &>(t);
|
static_cast<const cppast::cpp_template_instantiation_type &>(t);
|
||||||
|
|
||||||
|
const auto &full_name =
|
||||||
|
cx::util::full_name(cppast::remove_cv(t), ctx.entity_index(), false);
|
||||||
|
|
||||||
if (template_instantiation_type.primary_template()
|
if (template_instantiation_type.primary_template()
|
||||||
.get(ctx.entity_index())
|
.get(ctx.entity_index())
|
||||||
.size()) {
|
.size()) {
|
||||||
@@ -1241,8 +1247,8 @@ void translation_unit_visitor::
|
|||||||
LOG_DBG("Processing template method argument exposed "
|
LOG_DBG("Processing template method argument exposed "
|
||||||
"parameters...");
|
"parameters...");
|
||||||
|
|
||||||
for (const auto &template_argument :
|
const auto targs = template_instantiation_type.arguments();
|
||||||
template_instantiation_type.arguments().value()) {
|
for (const auto &template_argument : targs.value()) {
|
||||||
if (!template_argument.type().has_value())
|
if (!template_argument.type().has_value())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@@ -1272,18 +1278,18 @@ void translation_unit_visitor::
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (template_is_not_instantiation) {
|
if (template_is_not_instantiation) {
|
||||||
|
relationship rr{relationship_t::kDependency, full_name};
|
||||||
|
|
||||||
LOG_DBG("Template is not an instantiation - "
|
LOG_DBG("Template is not an instantiation - "
|
||||||
"only adding reference to template {}",
|
"only adding reference to template {}",
|
||||||
cx::util::full_name(
|
full_name);
|
||||||
cppast::remove_cv(t), ctx.entity_index(), false));
|
|
||||||
relationship rr{relationship_t::kDependency,
|
|
||||||
cx::util::full_name(
|
|
||||||
cppast::remove_cv(t), ctx.entity_index(), false)};
|
|
||||||
LOG_DBG("Adding field template dependency relationship "
|
LOG_DBG("Adding field template dependency relationship "
|
||||||
"{} {} {} "
|
"{} {} {} "
|
||||||
": {}",
|
": {}",
|
||||||
rr.destination(), common::model::to_string(rr.type()),
|
rr.destination(), common::model::to_string(rr.type()),
|
||||||
c.full_name(), rr.label());
|
c.full_name(), rr.label());
|
||||||
|
|
||||||
c.add_relationship(std::move(rr));
|
c.add_relationship(std::move(rr));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -1350,9 +1356,9 @@ void translation_unit_visitor::process_friend(const cppast::cpp_friend &f,
|
|||||||
{
|
{
|
||||||
// Only process friends to other classes or class templates
|
// Only process friends to other classes or class templates
|
||||||
if (!f.entity() ||
|
if (!f.entity() ||
|
||||||
(f.entity().value().kind() != cppast::cpp_entity_kind::class_t) &&
|
((f.entity().value().kind() != cppast::cpp_entity_kind::class_t) &&
|
||||||
(f.entity().value().kind() !=
|
(f.entity().value().kind() !=
|
||||||
cppast::cpp_entity_kind::class_template_t))
|
cppast::cpp_entity_kind::class_template_t)))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
relationship r{relationship_t::kFriendship, "",
|
relationship r{relationship_t::kFriendship, "",
|
||||||
@@ -1384,11 +1390,11 @@ void translation_unit_visitor::process_friend(const cppast::cpp_friend &f,
|
|||||||
f.entity().value());
|
f.entity().value());
|
||||||
const auto &class_ = ft.class_();
|
const auto &class_ = ft.class_();
|
||||||
auto scope = cppast::cpp_scope_name(type_safe::ref(ft));
|
auto scope = cppast::cpp_scope_name(type_safe::ref(ft));
|
||||||
if (ft.class_().user_data() == nullptr) {
|
if (class_.user_data() == nullptr) {
|
||||||
spdlog::warn(
|
spdlog::warn(
|
||||||
"Empty user data in friend class template: {}, {}, {}",
|
"Empty user data in friend class template: {}, {}, {}",
|
||||||
ft.name(),
|
ft.name(),
|
||||||
fmt::ptr(reinterpret_cast<const void *>(&ft.class_())),
|
fmt::ptr(reinterpret_cast<const void *>(&class_)),
|
||||||
scope.name());
|
scope.name());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1483,8 +1489,6 @@ bool translation_unit_visitor::find_relationships_in_template_instantiation(
|
|||||||
assert(tinst.arguments().has_value());
|
assert(tinst.arguments().has_value());
|
||||||
assert(tinst.arguments().value().size() > 0u);
|
assert(tinst.arguments().value().size() > 0u);
|
||||||
|
|
||||||
[[maybe_unused]] const auto args_count = tinst.arguments().value().size();
|
|
||||||
|
|
||||||
const auto args = tinst.arguments().value();
|
const auto args = tinst.arguments().value();
|
||||||
|
|
||||||
const auto [ns, base_name] = cx::util::split_ns(fn);
|
const auto [ns, base_name] = cx::util::split_ns(fn);
|
||||||
@@ -1542,7 +1546,8 @@ bool translation_unit_visitor::find_relationships_in_user_defined_type(
|
|||||||
const std::string &fn, relationship_t &relationship_type,
|
const std::string &fn, relationship_t &relationship_type,
|
||||||
const cppast::cpp_type &t) const
|
const cppast::cpp_type &t) const
|
||||||
{
|
{
|
||||||
bool found;
|
bool found{false};
|
||||||
|
|
||||||
LOG_DBG("Finding relationships in user defined type: {} | {}",
|
LOG_DBG("Finding relationships in user defined type: {} | {}",
|
||||||
cppast::to_string(t_), cppast::to_string(t_.canonical()));
|
cppast::to_string(t_), cppast::to_string(t_.canonical()));
|
||||||
|
|
||||||
@@ -1715,7 +1720,8 @@ std::unique_ptr<class_> translation_unit_visitor::build_template_instantiation(
|
|||||||
// to the variadic tuple
|
// to the variadic tuple
|
||||||
auto has_variadic_params = false;
|
auto has_variadic_params = false;
|
||||||
|
|
||||||
for (const auto &targ : t.arguments().value()) {
|
const auto targs = t.arguments().value();
|
||||||
|
for (const auto &targ : targs) {
|
||||||
template_parameter ct;
|
template_parameter ct;
|
||||||
if (targ.type()) {
|
if (targ.type()) {
|
||||||
build_template_instantiation_process_type_argument(
|
build_template_instantiation_process_type_argument(
|
||||||
@@ -1821,12 +1827,14 @@ void translation_unit_visitor::
|
|||||||
build_template_instantiation_process_expression_argument(
|
build_template_instantiation_process_expression_argument(
|
||||||
const cppast::cpp_template_argument &targ, template_parameter &ct) const
|
const cppast::cpp_template_argument &targ, template_parameter &ct) const
|
||||||
{
|
{
|
||||||
const auto &exp = targ.expression().value();
|
const auto exp = targ.expression();
|
||||||
if (exp.kind() == cppast::cpp_expression_kind::literal_t)
|
if (exp.value().kind() == cppast::cpp_expression_kind::literal_t)
|
||||||
ct.set_type(
|
ct.set_type(
|
||||||
static_cast<const cppast::cpp_literal_expression &>(exp).value());
|
static_cast<const cppast::cpp_literal_expression &>(exp.value())
|
||||||
else if (exp.kind() == cppast::cpp_expression_kind::unexposed_t)
|
.value());
|
||||||
ct.set_type(static_cast<const cppast::cpp_unexposed_expression &>(exp)
|
else if (exp.value().kind() == cppast::cpp_expression_kind::unexposed_t)
|
||||||
|
ct.set_type(
|
||||||
|
static_cast<const cppast::cpp_unexposed_expression &>(exp.value())
|
||||||
.expression()
|
.expression()
|
||||||
.as_string());
|
.as_string());
|
||||||
|
|
||||||
@@ -1940,8 +1948,6 @@ void translation_unit_visitor::
|
|||||||
const auto &function_argument =
|
const auto &function_argument =
|
||||||
static_cast<const cppast::cpp_function_type &>(targ_type);
|
static_cast<const cppast::cpp_function_type &>(targ_type);
|
||||||
|
|
||||||
const auto &rt = function_argument.return_type();
|
|
||||||
|
|
||||||
// Search for relationships in argument return type
|
// Search for relationships in argument return type
|
||||||
// TODO...
|
// TODO...
|
||||||
|
|
||||||
|
|||||||
@@ -261,7 +261,7 @@ std::unique_ptr<DiagramModel> generate(
|
|||||||
|
|
||||||
diagram->set_complete(true);
|
diagram->set_complete(true);
|
||||||
|
|
||||||
return std::move(diagram);
|
return diagram;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename C, typename D> void generator<C, D>::init_context()
|
template <typename C, typename D> void generator<C, D>::init_context()
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ public:
|
|||||||
|
|
||||||
std::string name() const { return name_; }
|
std::string name() const { return name_; }
|
||||||
|
|
||||||
virtual std::string full_name(bool relative) const { return name(); }
|
virtual std::string full_name(bool /*relative*/) const { return name(); }
|
||||||
|
|
||||||
std::vector<relationship> &relationships();
|
std::vector<relationship> &relationships();
|
||||||
|
|
||||||
|
|||||||
@@ -90,31 +90,31 @@ filter_visitor::filter_visitor(filter_t type)
|
|||||||
}
|
}
|
||||||
|
|
||||||
tvl::value_t filter_visitor::match(
|
tvl::value_t filter_visitor::match(
|
||||||
const diagram &d, const common::model::element &e) const
|
const diagram & /*d*/, const common::model::element & /*e*/) const
|
||||||
{
|
{
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
tvl::value_t filter_visitor::match(
|
tvl::value_t filter_visitor::match(
|
||||||
const diagram &d, const common::model::relationship_t &r) const
|
const diagram & /*d*/, const common::model::relationship_t & /*r*/) const
|
||||||
{
|
{
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
tvl::value_t filter_visitor::match(
|
tvl::value_t filter_visitor::match(
|
||||||
const diagram &d, const common::model::access_t &a) const
|
const diagram & /*d*/, const common::model::access_t & /*a*/) const
|
||||||
{
|
{
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
tvl::value_t filter_visitor::match(
|
tvl::value_t filter_visitor::match(
|
||||||
const diagram &d, const common::model::namespace_ &ns) const
|
const diagram & /*d*/, const common::model::namespace_ & /*ns*/) const
|
||||||
{
|
{
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
tvl::value_t filter_visitor::match(
|
tvl::value_t filter_visitor::match(
|
||||||
const diagram &d, const common::model::source_file &f) const
|
const diagram & /*d*/, const common::model::source_file & /*f*/) const
|
||||||
{
|
{
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
@@ -160,7 +160,7 @@ namespace_filter::namespace_filter(
|
|||||||
}
|
}
|
||||||
|
|
||||||
tvl::value_t namespace_filter::match(
|
tvl::value_t namespace_filter::match(
|
||||||
const diagram &d, const namespace_ &ns) const
|
const diagram & /*d*/, const namespace_ &ns) const
|
||||||
{
|
{
|
||||||
if (ns.is_empty())
|
if (ns.is_empty())
|
||||||
return {};
|
return {};
|
||||||
@@ -169,7 +169,8 @@ tvl::value_t namespace_filter::match(
|
|||||||
[&ns](const auto &nsit) { return ns.starts_with(nsit) || ns == nsit; });
|
[&ns](const auto &nsit) { return ns.starts_with(nsit) || ns == nsit; });
|
||||||
}
|
}
|
||||||
|
|
||||||
tvl::value_t namespace_filter::match(const diagram &d, const element &e) const
|
tvl::value_t namespace_filter::match(
|
||||||
|
const diagram & /*d*/, const element &e) const
|
||||||
{
|
{
|
||||||
if (dynamic_cast<const package *>(&e) != nullptr) {
|
if (dynamic_cast<const package *>(&e) != nullptr) {
|
||||||
return tvl::any_of(
|
return tvl::any_of(
|
||||||
@@ -193,7 +194,8 @@ element_filter::element_filter(filter_t type, std::vector<std::string> elements)
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
tvl::value_t element_filter::match(const diagram &d, const element &e) const
|
tvl::value_t element_filter::match(
|
||||||
|
const diagram & /*d*/, const element &e) const
|
||||||
{
|
{
|
||||||
return tvl::any_of(elements_.begin(), elements_.end(),
|
return tvl::any_of(elements_.begin(), elements_.end(),
|
||||||
[&e](const auto &el) { return e.full_name(false) == el; });
|
[&e](const auto &el) { return e.full_name(false) == el; });
|
||||||
@@ -253,7 +255,7 @@ relationship_filter::relationship_filter(
|
|||||||
}
|
}
|
||||||
|
|
||||||
tvl::value_t relationship_filter::match(
|
tvl::value_t relationship_filter::match(
|
||||||
const diagram &d, const relationship_t &r) const
|
const diagram & /*d*/, const relationship_t &r) const
|
||||||
{
|
{
|
||||||
return tvl::any_of(relationships_.begin(), relationships_.end(),
|
return tvl::any_of(relationships_.begin(), relationships_.end(),
|
||||||
[&r](const auto &rel) { return r == rel; });
|
[&r](const auto &rel) { return r == rel; });
|
||||||
@@ -265,7 +267,8 @@ access_filter::access_filter(filter_t type, std::vector<access_t> access)
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
tvl::value_t access_filter::match(const diagram &d, const access_t &a) const
|
tvl::value_t access_filter::match(
|
||||||
|
const diagram & /*d*/, const access_t &a) const
|
||||||
{
|
{
|
||||||
return tvl::any_of(access_.begin(), access_.end(),
|
return tvl::any_of(access_.begin(), access_.end(),
|
||||||
[&a](const auto &access) { return a == access; });
|
[&a](const auto &access) { return a == access; });
|
||||||
@@ -349,7 +352,7 @@ paths_filter::paths_filter(filter_t type, const std::filesystem::path &root,
|
|||||||
}
|
}
|
||||||
|
|
||||||
tvl::value_t paths_filter::match(
|
tvl::value_t paths_filter::match(
|
||||||
const diagram &d, const common::model::source_file &p) const
|
const diagram & /*d*/, const common::model::source_file &p) const
|
||||||
{
|
{
|
||||||
if (paths_.empty()) {
|
if (paths_.empty()) {
|
||||||
return {};
|
return {};
|
||||||
|
|||||||
@@ -131,8 +131,8 @@ struct edge_traversal_filter : public filter_visitor {
|
|||||||
edge_traversal_filter(filter_t type, relationship_t relationship,
|
edge_traversal_filter(filter_t type, relationship_t relationship,
|
||||||
std::vector<std::string> roots, bool forward = false)
|
std::vector<std::string> roots, bool forward = false)
|
||||||
: filter_visitor{type}
|
: filter_visitor{type}
|
||||||
, relationship_{relationship}
|
|
||||||
, roots_{roots}
|
, roots_{roots}
|
||||||
|
, relationship_{relationship}
|
||||||
, forward_{forward}
|
, forward_{forward}
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ public:
|
|||||||
|
|
||||||
const namespace_ &path() const { return ns_; }
|
const namespace_ &path() const { return ns_; }
|
||||||
|
|
||||||
std::string full_name(bool relative) const override
|
std::string full_name(bool /*relative*/) const override
|
||||||
{
|
{
|
||||||
return name_and_ns();
|
return name_and_ns();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ std::string to_string(relationship_t r)
|
|||||||
return "alias";
|
return "alias";
|
||||||
default:
|
default:
|
||||||
assert(false);
|
assert(false);
|
||||||
|
return "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -62,6 +63,7 @@ std::string to_string(access_t a)
|
|||||||
return "private";
|
return "private";
|
||||||
default:
|
default:
|
||||||
assert(false);
|
assert(false);
|
||||||
|
return "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -74,6 +76,7 @@ std::string to_string(message_t r)
|
|||||||
return "return";
|
return "return";
|
||||||
default:
|
default:
|
||||||
assert(false);
|
assert(false);
|
||||||
|
return "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -90,6 +93,7 @@ std::string to_string(const diagram_t t)
|
|||||||
return "include";
|
return "include";
|
||||||
default:
|
default:
|
||||||
assert(false);
|
assert(false);
|
||||||
|
return "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -26,10 +26,10 @@ relationship::relationship(relationship_t type, const std::string &destination,
|
|||||||
const std::string &multiplicity_destination)
|
const std::string &multiplicity_destination)
|
||||||
: type_{type}
|
: type_{type}
|
||||||
, destination_{destination}
|
, destination_{destination}
|
||||||
, access_{access}
|
|
||||||
, label_{label}
|
|
||||||
, multiplicity_source_{multiplicity_source}
|
, multiplicity_source_{multiplicity_source}
|
||||||
, multiplicity_destination_{multiplicity_destination}
|
, multiplicity_destination_{multiplicity_destination}
|
||||||
|
, label_{label}
|
||||||
|
, access_{access}
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -56,11 +56,11 @@ public:
|
|||||||
friend bool operator==(const relationship &l, const relationship &r);
|
friend bool operator==(const relationship &l, const relationship &r);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
relationship_t type_{relationship_t::kAssociation};
|
relationship_t type_;
|
||||||
std::string destination_;
|
std::string destination_;
|
||||||
std::string multiplicity_source_;
|
std::string multiplicity_source_;
|
||||||
std::string multiplicity_destination_;
|
std::string multiplicity_destination_;
|
||||||
std::string label_;
|
std::string label_;
|
||||||
access_t access_{access_t::kPublic};
|
access_t access_;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ public:
|
|||||||
|
|
||||||
const filesystem_path &path() const { return path_; }
|
const filesystem_path &path() const { return path_; }
|
||||||
|
|
||||||
std::string full_name(bool relative) const override
|
std::string full_name(bool /*relative*/) const override
|
||||||
{
|
{
|
||||||
return (path_ | name()).to_string();
|
return (path_ | name()).to_string();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -73,6 +73,7 @@ std::string to_string(const hint_t t)
|
|||||||
return "right";
|
return "right";
|
||||||
default:
|
default:
|
||||||
assert(false);
|
assert(false);
|
||||||
|
return "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -262,7 +262,6 @@ parse_unexposed_template_params(const std::string ¶ms,
|
|||||||
|
|
||||||
std::vector<template_parameter> res;
|
std::vector<template_parameter> res;
|
||||||
|
|
||||||
int nested_template_level{0};
|
|
||||||
auto it = params.begin();
|
auto it = params.begin();
|
||||||
|
|
||||||
std::string type{};
|
std::string type{};
|
||||||
|
|||||||
@@ -119,12 +119,13 @@ std::shared_ptr<decorator> note::from_string(std::string_view c)
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<decorator> skip::from_string(std::string_view c)
|
std::shared_ptr<decorator> skip::from_string(std::string_view /*c*/)
|
||||||
{
|
{
|
||||||
return std::make_shared<skip>();
|
return std::make_shared<skip>();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<decorator> skip_relationship::from_string(std::string_view c)
|
std::shared_ptr<decorator> skip_relationship::from_string(
|
||||||
|
std::string_view /*c*/)
|
||||||
{
|
{
|
||||||
return std::make_shared<skip_relationship>();
|
return std::make_shared<skip_relationship>();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ void translation_unit_visitor::operator()(const cppast::cpp_entity &file)
|
|||||||
process_source_file(static_cast<const cppast::cpp_file &>(file));
|
process_source_file(static_cast<const cppast::cpp_file &>(file));
|
||||||
|
|
||||||
cppast::visit(file,
|
cppast::visit(file,
|
||||||
[&, this](const cppast::cpp_entity &e, cppast::visitor_info info) {
|
[&, this](const cppast::cpp_entity &e, cppast::visitor_info /*info*/) {
|
||||||
if (e.kind() == cppast::cpp_entity_kind::include_directive_t) {
|
if (e.kind() == cppast::cpp_entity_kind::include_directive_t) {
|
||||||
const auto &inc =
|
const auto &inc =
|
||||||
static_cast<const cppast::cpp_include_directive &>(e);
|
static_cast<const cppast::cpp_include_directive &>(e);
|
||||||
|
|||||||
@@ -215,34 +215,26 @@ void translation_unit_visitor::operator()(const cppast::cpp_entity &file)
|
|||||||
LOG_DBG("========== Visiting '{}' - {}",
|
LOG_DBG("========== Visiting '{}' - {}",
|
||||||
cx::util::full_name(ctx.get_namespace(), e),
|
cx::util::full_name(ctx.get_namespace(), e),
|
||||||
cppast::to_string(e.kind()));
|
cppast::to_string(e.kind()));
|
||||||
|
|
||||||
auto &at = static_cast<const cppast::cpp_alias_template &>(e);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void translation_unit_visitor::process_class_declaration(
|
void translation_unit_visitor::process_class_declaration(
|
||||||
const cppast::cpp_class &cls,
|
const cppast::cpp_class &cls,
|
||||||
type_safe::optional_ref<const cppast::cpp_template_specialization> tspec)
|
type_safe::optional_ref<
|
||||||
|
const cppast::cpp_template_specialization> /*tspec*/)
|
||||||
{
|
{
|
||||||
auto current_package = ctx.get_current_package();
|
auto current_package = ctx.get_current_package();
|
||||||
|
|
||||||
if (!current_package)
|
if (!current_package)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
cppast::cpp_access_specifier_kind last_access_specifier =
|
|
||||||
cppast::cpp_access_specifier_kind::cpp_private;
|
|
||||||
|
|
||||||
std::vector<std::pair<std::string, relationship_t>> relationships;
|
std::vector<std::pair<std::string, relationship_t>> relationships;
|
||||||
|
|
||||||
// Process class elements
|
// Process class elements
|
||||||
for (auto &child : cls) {
|
for (auto &child : cls) {
|
||||||
auto name = child.name();
|
auto name = child.name();
|
||||||
if (child.kind() == cppast::cpp_entity_kind::access_specifier_t) {
|
if (child.kind() == cppast::cpp_entity_kind::member_variable_t) {
|
||||||
auto &as = static_cast<const cppast::cpp_access_specifier &>(child);
|
|
||||||
last_access_specifier = as.access_specifier();
|
|
||||||
}
|
|
||||||
else if (child.kind() == cppast::cpp_entity_kind::member_variable_t) {
|
|
||||||
auto &mv = static_cast<const cppast::cpp_member_variable &>(child);
|
auto &mv = static_cast<const cppast::cpp_member_variable &>(child);
|
||||||
find_relationships(
|
find_relationships(
|
||||||
mv.type(), relationships, relationship_t::kDependency);
|
mv.type(), relationships, relationship_t::kDependency);
|
||||||
@@ -442,7 +434,7 @@ bool translation_unit_visitor::find_relationships(const cppast::cpp_type &t_,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (t.kind() == cppast::cpp_type_kind::template_instantiation_t) {
|
else if (t.kind() == cppast::cpp_type_kind::template_instantiation_t) {
|
||||||
auto &tinst =
|
const auto &tinst =
|
||||||
static_cast<const cppast::cpp_template_instantiation_type &>(t);
|
static_cast<const cppast::cpp_template_instantiation_type &>(t);
|
||||||
|
|
||||||
if (!tinst.arguments_exposed()) {
|
if (!tinst.arguments_exposed()) {
|
||||||
@@ -451,7 +443,7 @@ bool translation_unit_visitor::find_relationships(const cppast::cpp_type &t_,
|
|||||||
return found;
|
return found;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto &args = tinst.arguments().value();
|
const auto args = tinst.arguments().value();
|
||||||
|
|
||||||
// Try to match common containers
|
// Try to match common containers
|
||||||
// TODO: Refactor to a separate class with configurable
|
// TODO: Refactor to a separate class with configurable
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ common::model::diagram_t diagram::type() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
type_safe::optional_ref<const common::model::diagram_element> diagram::get(
|
type_safe::optional_ref<const common::model::diagram_element> diagram::get(
|
||||||
const std::string &full_name) const
|
const std::string & /*full_name*/) const
|
||||||
{
|
{
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -138,7 +138,7 @@ void translation_unit_visitor::operator()(const cppast::cpp_entity &file)
|
|||||||
using cppast::cpp_member_function_call;
|
using cppast::cpp_member_function_call;
|
||||||
using cppast::visitor_info;
|
using cppast::visitor_info;
|
||||||
|
|
||||||
cppast::visit(file, [&, this](const cpp_entity &e, visitor_info info) {
|
cppast::visit(file, [&, this](const cpp_entity &e, visitor_info /*info*/) {
|
||||||
if (e.kind() == cpp_entity_kind::function_t) {
|
if (e.kind() == cpp_entity_kind::function_t) {
|
||||||
const auto &function = static_cast<const cpp_function &>(e);
|
const auto &function = static_cast<const cpp_function &>(e);
|
||||||
process_activities(function);
|
process_activities(function);
|
||||||
|
|||||||
@@ -109,7 +109,7 @@ std::vector<std::string> split(std::string str, std::string_view delimiter)
|
|||||||
result.push_back(str);
|
result.push_back(str);
|
||||||
else
|
else
|
||||||
while (str.size()) {
|
while (str.size()) {
|
||||||
int index = str.find(delimiter);
|
auto index = str.find(delimiter);
|
||||||
if (index != std::string::npos) {
|
if (index != std::string::npos) {
|
||||||
result.push_back(str.substr(0, index));
|
result.push_back(str.substr(0, index));
|
||||||
str = str.substr(index + delimiter.size());
|
str = str.substr(index + delimiter.size());
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
|||||||
|
|
||||||
set(CMAKE_CXX_STANDARD 17)
|
set(CMAKE_CXX_STANDARD 17)
|
||||||
|
|
||||||
|
set(CMAKE_CXX_FLAGS "-std=c++17 ${LIBCLANG_CXXFLAGS}")
|
||||||
|
|
||||||
file(GLOB_RECURSE TEST_CASE_SOURCES t*/*.cc)
|
file(GLOB_RECURSE TEST_CASE_SOURCES t*/*.cc)
|
||||||
file(GLOB_RECURSE TEST_CASE_CONFIGS t*/.clang-uml)
|
file(GLOB_RECURSE TEST_CASE_CONFIGS t*/.clang-uml)
|
||||||
file(GLOB_RECURSE TEST_CONFIG_YMLS test_config_data/*.yml)
|
file(GLOB_RECURSE TEST_CONFIG_YMLS test_config_data/*.yml)
|
||||||
@@ -71,7 +73,7 @@ target_link_libraries(test_util
|
|||||||
PRIVATE
|
PRIVATE
|
||||||
${LIBCLANG_LIBRARIES}
|
${LIBCLANG_LIBRARIES}
|
||||||
${YAML_CPP_LIBRARIES}
|
${YAML_CPP_LIBRARIES}
|
||||||
spdlog::spdlog clang-umllib cppast)
|
clang-umllib cppast)
|
||||||
|
|
||||||
add_executable(test_model
|
add_executable(test_model
|
||||||
${CLANG_UML_TEST_MODEL_SRC}
|
${CLANG_UML_TEST_MODEL_SRC}
|
||||||
@@ -81,7 +83,7 @@ target_link_libraries(test_model
|
|||||||
PRIVATE
|
PRIVATE
|
||||||
${LIBCLANG_LIBRARIES}
|
${LIBCLANG_LIBRARIES}
|
||||||
${YAML_CPP_LIBRARIES}
|
${YAML_CPP_LIBRARIES}
|
||||||
spdlog::spdlog clang-umllib cppast)
|
clang-umllib cppast)
|
||||||
|
|
||||||
add_executable(test_decorator_parser
|
add_executable(test_decorator_parser
|
||||||
${CLANG_UML_TEST_DECORATOR_PARSER_SRC}
|
${CLANG_UML_TEST_DECORATOR_PARSER_SRC}
|
||||||
@@ -91,7 +93,7 @@ target_link_libraries(test_decorator_parser
|
|||||||
PRIVATE
|
PRIVATE
|
||||||
${LIBCLANG_LIBRARIES}
|
${LIBCLANG_LIBRARIES}
|
||||||
${YAML_CPP_LIBRARIES}
|
${YAML_CPP_LIBRARIES}
|
||||||
spdlog::spdlog clang-umllib cppast)
|
clang-umllib cppast)
|
||||||
|
|
||||||
add_executable(test_config
|
add_executable(test_config
|
||||||
${CLANG_UML_TEST_CONFIG_SRC}
|
${CLANG_UML_TEST_CONFIG_SRC}
|
||||||
@@ -101,7 +103,7 @@ target_link_libraries(test_config
|
|||||||
PRIVATE
|
PRIVATE
|
||||||
${LIBCLANG_LIBRARIES}
|
${LIBCLANG_LIBRARIES}
|
||||||
${YAML_CPP_LIBRARIES}
|
${YAML_CPP_LIBRARIES}
|
||||||
spdlog::spdlog clang-umllib cppast)
|
clang-umllib cppast)
|
||||||
|
|
||||||
add_executable(test_filters
|
add_executable(test_filters
|
||||||
${CLANG_UML_TEST_FILTERS_SRC}
|
${CLANG_UML_TEST_FILTERS_SRC}
|
||||||
@@ -111,7 +113,7 @@ target_link_libraries(test_filters
|
|||||||
PRIVATE
|
PRIVATE
|
||||||
${LIBCLANG_LIBRARIES}
|
${LIBCLANG_LIBRARIES}
|
||||||
${YAML_CPP_LIBRARIES}
|
${YAML_CPP_LIBRARIES}
|
||||||
spdlog::spdlog clang-umllib cppast)
|
clang-umllib cppast)
|
||||||
|
|
||||||
add_executable(test_thread_pool_executor
|
add_executable(test_thread_pool_executor
|
||||||
${CLANG_UML_TEST_THREAD_POOL_EXECUTOR_SRC}
|
${CLANG_UML_TEST_THREAD_POOL_EXECUTOR_SRC}
|
||||||
@@ -121,7 +123,7 @@ target_link_libraries(test_thread_pool_executor
|
|||||||
PRIVATE
|
PRIVATE
|
||||||
${LIBCLANG_LIBRARIES}
|
${LIBCLANG_LIBRARIES}
|
||||||
${YAML_CPP_LIBRARIES}
|
${YAML_CPP_LIBRARIES}
|
||||||
spdlog::spdlog clang-umllib cppast)
|
clang-umllib cppast)
|
||||||
|
|
||||||
add_executable(test_cases
|
add_executable(test_cases
|
||||||
${CLANG_UML_TEST_CASES_SRC}
|
${CLANG_UML_TEST_CASES_SRC}
|
||||||
@@ -131,7 +133,7 @@ target_link_libraries(test_cases
|
|||||||
PRIVATE
|
PRIVATE
|
||||||
${LIBCLANG_LIBRARIES}
|
${LIBCLANG_LIBRARIES}
|
||||||
${YAML_CPP_LIBRARIES}
|
${YAML_CPP_LIBRARIES}
|
||||||
spdlog::spdlog clang-umllib cppast)
|
clang-umllib cppast)
|
||||||
|
|
||||||
foreach(TEST_CASE_CONFIG ${TEST_CASE_CONFIGS})
|
foreach(TEST_CASE_CONFIG ${TEST_CASE_CONFIGS})
|
||||||
file(RELATIVE_PATH
|
file(RELATIVE_PATH
|
||||||
|
|||||||
2
thirdparty/glob/glob.hpp
vendored
2
thirdparty/glob/glob.hpp
vendored
@@ -267,7 +267,7 @@ static inline std::vector<fs::path> rlistdir(
|
|||||||
// This helper function recursively yields relative pathnames inside a literal
|
// This helper function recursively yields relative pathnames inside a literal
|
||||||
// directory.
|
// directory.
|
||||||
static inline std::vector<fs::path> glob2(
|
static inline std::vector<fs::path> glob2(
|
||||||
const fs::path &dirname, const std::string &pattern, bool dironly)
|
const fs::path &dirname, [[maybe_unused]] const std::string &pattern, bool dironly)
|
||||||
{
|
{
|
||||||
// std::cout << "In glob2\n";
|
// std::cout << "In glob2\n";
|
||||||
std::vector<fs::path> result;
|
std::vector<fs::path> result;
|
||||||
|
|||||||
26
thirdparty/spdlog/LICENSE
vendored
Normal file
26
thirdparty/spdlog/LICENSE
vendored
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2016 Gabi Melman.
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
|
|
||||||
|
-- NOTE: Third party dependency used by this software --
|
||||||
|
This software depends on the fmt lib (MIT License),
|
||||||
|
and users must comply to its license: https://github.com/fmtlib/fmt/blob/master/LICENSE.rst
|
||||||
|
|
||||||
93
thirdparty/spdlog/async.h
vendored
Normal file
93
thirdparty/spdlog/async.h
vendored
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
|
||||||
|
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
//
|
||||||
|
// Async logging using global thread pool
|
||||||
|
// All loggers created here share same global thread pool.
|
||||||
|
// Each log message is pushed to a queue along with a shared pointer to the
|
||||||
|
// logger.
|
||||||
|
// If a logger deleted while having pending messages in the queue, it's actual
|
||||||
|
// destruction will defer
|
||||||
|
// until all its messages are processed by the thread pool.
|
||||||
|
// This is because each message in the queue holds a shared_ptr to the
|
||||||
|
// originating logger.
|
||||||
|
|
||||||
|
#include <spdlog/async_logger.h>
|
||||||
|
#include <spdlog/details/registry.h>
|
||||||
|
#include <spdlog/details/thread_pool.h>
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <mutex>
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
namespace spdlog {
|
||||||
|
|
||||||
|
namespace details {
|
||||||
|
static const size_t default_async_q_size = 8192;
|
||||||
|
}
|
||||||
|
|
||||||
|
// async logger factory - creates async loggers backed with thread pool.
|
||||||
|
// if a global thread pool doesn't already exist, create it with default queue
|
||||||
|
// size of 8192 items and single thread.
|
||||||
|
template<async_overflow_policy OverflowPolicy = async_overflow_policy::block>
|
||||||
|
struct async_factory_impl
|
||||||
|
{
|
||||||
|
template<typename Sink, typename... SinkArgs>
|
||||||
|
static std::shared_ptr<async_logger> create(std::string logger_name, SinkArgs &&...args)
|
||||||
|
{
|
||||||
|
auto ®istry_inst = details::registry::instance();
|
||||||
|
|
||||||
|
// create global thread pool if not already exists..
|
||||||
|
|
||||||
|
auto &mutex = registry_inst.tp_mutex();
|
||||||
|
std::lock_guard<std::recursive_mutex> tp_lock(mutex);
|
||||||
|
auto tp = registry_inst.get_tp();
|
||||||
|
if (tp == nullptr)
|
||||||
|
{
|
||||||
|
tp = std::make_shared<details::thread_pool>(details::default_async_q_size, 1U);
|
||||||
|
registry_inst.set_tp(tp);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto sink = std::make_shared<Sink>(std::forward<SinkArgs>(args)...);
|
||||||
|
auto new_logger = std::make_shared<async_logger>(std::move(logger_name), std::move(sink), std::move(tp), OverflowPolicy);
|
||||||
|
registry_inst.initialize_logger(new_logger);
|
||||||
|
return new_logger;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
using async_factory = async_factory_impl<async_overflow_policy::block>;
|
||||||
|
using async_factory_nonblock = async_factory_impl<async_overflow_policy::overrun_oldest>;
|
||||||
|
|
||||||
|
template<typename Sink, typename... SinkArgs>
|
||||||
|
inline std::shared_ptr<spdlog::logger> create_async(std::string logger_name, SinkArgs &&...sink_args)
|
||||||
|
{
|
||||||
|
return async_factory::create<Sink>(std::move(logger_name), std::forward<SinkArgs>(sink_args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Sink, typename... SinkArgs>
|
||||||
|
inline std::shared_ptr<spdlog::logger> create_async_nb(std::string logger_name, SinkArgs &&...sink_args)
|
||||||
|
{
|
||||||
|
return async_factory_nonblock::create<Sink>(std::move(logger_name), std::forward<SinkArgs>(sink_args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
// set global thread pool.
|
||||||
|
inline void init_thread_pool(size_t q_size, size_t thread_count, std::function<void()> on_thread_start)
|
||||||
|
{
|
||||||
|
auto tp = std::make_shared<details::thread_pool>(q_size, thread_count, on_thread_start);
|
||||||
|
details::registry::instance().set_tp(std::move(tp));
|
||||||
|
}
|
||||||
|
|
||||||
|
// set global thread pool.
|
||||||
|
inline void init_thread_pool(size_t q_size, size_t thread_count)
|
||||||
|
{
|
||||||
|
init_thread_pool(q_size, thread_count, [] {});
|
||||||
|
}
|
||||||
|
|
||||||
|
// get the global thread pool.
|
||||||
|
inline std::shared_ptr<spdlog::details::thread_pool> thread_pool()
|
||||||
|
{
|
||||||
|
return details::registry::instance().get_tp();
|
||||||
|
}
|
||||||
|
} // namespace spdlog
|
||||||
92
thirdparty/spdlog/async_logger-inl.h
vendored
Normal file
92
thirdparty/spdlog/async_logger-inl.h
vendored
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
|
||||||
|
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifndef SPDLOG_HEADER_ONLY
|
||||||
|
# include <spdlog/async_logger.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <spdlog/sinks/sink.h>
|
||||||
|
#include <spdlog/details/thread_pool.h>
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
SPDLOG_INLINE spdlog::async_logger::async_logger(
|
||||||
|
std::string logger_name, sinks_init_list sinks_list, std::weak_ptr<details::thread_pool> tp, async_overflow_policy overflow_policy)
|
||||||
|
: async_logger(std::move(logger_name), sinks_list.begin(), sinks_list.end(), std::move(tp), overflow_policy)
|
||||||
|
{}
|
||||||
|
|
||||||
|
SPDLOG_INLINE spdlog::async_logger::async_logger(
|
||||||
|
std::string logger_name, sink_ptr single_sink, std::weak_ptr<details::thread_pool> tp, async_overflow_policy overflow_policy)
|
||||||
|
: async_logger(std::move(logger_name), {std::move(single_sink)}, std::move(tp), overflow_policy)
|
||||||
|
{}
|
||||||
|
|
||||||
|
// send the log message to the thread pool
|
||||||
|
SPDLOG_INLINE void spdlog::async_logger::sink_it_(const details::log_msg &msg)
|
||||||
|
{
|
||||||
|
if (auto pool_ptr = thread_pool_.lock())
|
||||||
|
{
|
||||||
|
pool_ptr->post_log(shared_from_this(), msg, overflow_policy_);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw_spdlog_ex("async log: thread pool doesn't exist anymore");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// send flush request to the thread pool
|
||||||
|
SPDLOG_INLINE void spdlog::async_logger::flush_()
|
||||||
|
{
|
||||||
|
if (auto pool_ptr = thread_pool_.lock())
|
||||||
|
{
|
||||||
|
pool_ptr->post_flush(shared_from_this(), overflow_policy_);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw_spdlog_ex("async flush: thread pool doesn't exist anymore");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// backend functions - called from the thread pool to do the actual job
|
||||||
|
//
|
||||||
|
SPDLOG_INLINE void spdlog::async_logger::backend_sink_it_(const details::log_msg &msg)
|
||||||
|
{
|
||||||
|
for (auto &sink : sinks_)
|
||||||
|
{
|
||||||
|
if (sink->should_log(msg.level))
|
||||||
|
{
|
||||||
|
SPDLOG_TRY
|
||||||
|
{
|
||||||
|
sink->log(msg);
|
||||||
|
}
|
||||||
|
SPDLOG_LOGGER_CATCH()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (should_flush_(msg))
|
||||||
|
{
|
||||||
|
backend_flush_();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SPDLOG_INLINE void spdlog::async_logger::backend_flush_()
|
||||||
|
{
|
||||||
|
for (auto &sink : sinks_)
|
||||||
|
{
|
||||||
|
SPDLOG_TRY
|
||||||
|
{
|
||||||
|
sink->flush();
|
||||||
|
}
|
||||||
|
SPDLOG_LOGGER_CATCH()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SPDLOG_INLINE std::shared_ptr<spdlog::logger> spdlog::async_logger::clone(std::string new_name)
|
||||||
|
{
|
||||||
|
auto cloned = std::make_shared<spdlog::async_logger>(*this);
|
||||||
|
cloned->name_ = std::move(new_name);
|
||||||
|
return cloned;
|
||||||
|
}
|
||||||
68
thirdparty/spdlog/async_logger.h
vendored
Normal file
68
thirdparty/spdlog/async_logger.h
vendored
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
|
||||||
|
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
// Fast asynchronous logger.
|
||||||
|
// Uses pre allocated queue.
|
||||||
|
// Creates a single back thread to pop messages from the queue and log them.
|
||||||
|
//
|
||||||
|
// Upon each log write the logger:
|
||||||
|
// 1. Checks if its log level is enough to log the message
|
||||||
|
// 2. Push a new copy of the message to a queue (or block the caller until
|
||||||
|
// space is available in the queue)
|
||||||
|
// Upon destruction, logs all remaining messages in the queue before
|
||||||
|
// destructing..
|
||||||
|
|
||||||
|
#include <spdlog/logger.h>
|
||||||
|
|
||||||
|
namespace spdlog {
|
||||||
|
|
||||||
|
// Async overflow policy - block by default.
|
||||||
|
enum class async_overflow_policy
|
||||||
|
{
|
||||||
|
block, // Block until message can be enqueued
|
||||||
|
overrun_oldest // Discard oldest message in the queue if full when trying to
|
||||||
|
// add new item.
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace details {
|
||||||
|
class thread_pool;
|
||||||
|
}
|
||||||
|
|
||||||
|
class SPDLOG_API async_logger final : public std::enable_shared_from_this<async_logger>, public logger
|
||||||
|
{
|
||||||
|
friend class details::thread_pool;
|
||||||
|
|
||||||
|
public:
|
||||||
|
template<typename It>
|
||||||
|
async_logger(std::string logger_name, It begin, It end, std::weak_ptr<details::thread_pool> tp,
|
||||||
|
async_overflow_policy overflow_policy = async_overflow_policy::block)
|
||||||
|
: logger(std::move(logger_name), begin, end)
|
||||||
|
, thread_pool_(std::move(tp))
|
||||||
|
, overflow_policy_(overflow_policy)
|
||||||
|
{}
|
||||||
|
|
||||||
|
async_logger(std::string logger_name, sinks_init_list sinks_list, std::weak_ptr<details::thread_pool> tp,
|
||||||
|
async_overflow_policy overflow_policy = async_overflow_policy::block);
|
||||||
|
|
||||||
|
async_logger(std::string logger_name, sink_ptr single_sink, std::weak_ptr<details::thread_pool> tp,
|
||||||
|
async_overflow_policy overflow_policy = async_overflow_policy::block);
|
||||||
|
|
||||||
|
std::shared_ptr<logger> clone(std::string new_name) override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void sink_it_(const details::log_msg &msg) override;
|
||||||
|
void flush_() override;
|
||||||
|
void backend_sink_it_(const details::log_msg &incoming_log_msg);
|
||||||
|
void backend_flush_();
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::weak_ptr<details::thread_pool> thread_pool_;
|
||||||
|
async_overflow_policy overflow_policy_;
|
||||||
|
};
|
||||||
|
} // namespace spdlog
|
||||||
|
|
||||||
|
#ifdef SPDLOG_HEADER_ONLY
|
||||||
|
# include "async_logger-inl.h"
|
||||||
|
#endif
|
||||||
44
thirdparty/spdlog/cfg/argv.h
vendored
Normal file
44
thirdparty/spdlog/cfg/argv.h
vendored
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
|
||||||
|
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include <spdlog/cfg/helpers.h>
|
||||||
|
#include <spdlog/details/registry.h>
|
||||||
|
|
||||||
|
//
|
||||||
|
// Init log levels using each argv entry that starts with "SPDLOG_LEVEL="
|
||||||
|
//
|
||||||
|
// set all loggers to debug level:
|
||||||
|
// example.exe "SPDLOG_LEVEL=debug"
|
||||||
|
|
||||||
|
// set logger1 to trace level
|
||||||
|
// example.exe "SPDLOG_LEVEL=logger1=trace"
|
||||||
|
|
||||||
|
// turn off all logging except for logger1 and logger2:
|
||||||
|
// example.exe "SPDLOG_LEVEL=off,logger1=debug,logger2=info"
|
||||||
|
|
||||||
|
namespace spdlog {
|
||||||
|
namespace cfg {
|
||||||
|
|
||||||
|
// search for SPDLOG_LEVEL= in the args and use it to init the levels
|
||||||
|
inline void load_argv_levels(int argc, const char **argv)
|
||||||
|
{
|
||||||
|
const std::string spdlog_level_prefix = "SPDLOG_LEVEL=";
|
||||||
|
for (int i = 1; i < argc; i++)
|
||||||
|
{
|
||||||
|
std::string arg = argv[i];
|
||||||
|
if (arg.find(spdlog_level_prefix) == 0)
|
||||||
|
{
|
||||||
|
auto levels_string = arg.substr(spdlog_level_prefix.size());
|
||||||
|
helpers::load_levels(levels_string);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void load_argv_levels(int argc, char **argv)
|
||||||
|
{
|
||||||
|
load_argv_levels(argc, const_cast<const char **>(argv));
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace cfg
|
||||||
|
} // namespace spdlog
|
||||||
38
thirdparty/spdlog/cfg/env.h
vendored
Normal file
38
thirdparty/spdlog/cfg/env.h
vendored
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
|
||||||
|
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include <spdlog/cfg/helpers.h>
|
||||||
|
#include <spdlog/details/registry.h>
|
||||||
|
#include <spdlog/details/os.h>
|
||||||
|
|
||||||
|
//
|
||||||
|
// Init levels and patterns from env variables SPDLOG_LEVEL
|
||||||
|
// Inspired from Rust's "env_logger" crate (https://crates.io/crates/env_logger).
|
||||||
|
// Note - fallback to "info" level on unrecognized levels
|
||||||
|
//
|
||||||
|
// Examples:
|
||||||
|
//
|
||||||
|
// set global level to debug:
|
||||||
|
// export SPDLOG_LEVEL=debug
|
||||||
|
//
|
||||||
|
// turn off all logging except for logger1:
|
||||||
|
// export SPDLOG_LEVEL="*=off,logger1=debug"
|
||||||
|
//
|
||||||
|
|
||||||
|
// turn off all logging except for logger1 and logger2:
|
||||||
|
// export SPDLOG_LEVEL="off,logger1=debug,logger2=info"
|
||||||
|
|
||||||
|
namespace spdlog {
|
||||||
|
namespace cfg {
|
||||||
|
inline void load_env_levels()
|
||||||
|
{
|
||||||
|
auto env_val = details::os::getenv("SPDLOG_LEVEL");
|
||||||
|
if (!env_val.empty())
|
||||||
|
{
|
||||||
|
helpers::load_levels(env_val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace cfg
|
||||||
|
} // namespace spdlog
|
||||||
120
thirdparty/spdlog/cfg/helpers-inl.h
vendored
Normal file
120
thirdparty/spdlog/cfg/helpers-inl.h
vendored
Normal file
@@ -0,0 +1,120 @@
|
|||||||
|
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
|
||||||
|
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifndef SPDLOG_HEADER_ONLY
|
||||||
|
# include <spdlog/cfg/helpers.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <spdlog/spdlog.h>
|
||||||
|
#include <spdlog/details/os.h>
|
||||||
|
#include <spdlog/details/registry.h>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <string>
|
||||||
|
#include <utility>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
namespace spdlog {
|
||||||
|
namespace cfg {
|
||||||
|
namespace helpers {
|
||||||
|
|
||||||
|
// inplace convert to lowercase
|
||||||
|
inline std::string &to_lower_(std::string &str)
|
||||||
|
{
|
||||||
|
std::transform(
|
||||||
|
str.begin(), str.end(), str.begin(), [](char ch) { return static_cast<char>((ch >= 'A' && ch <= 'Z') ? ch + ('a' - 'A') : ch); });
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
// inplace trim spaces
|
||||||
|
inline std::string &trim_(std::string &str)
|
||||||
|
{
|
||||||
|
const char *spaces = " \n\r\t";
|
||||||
|
str.erase(str.find_last_not_of(spaces) + 1);
|
||||||
|
str.erase(0, str.find_first_not_of(spaces));
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
// return (name,value) trimmed pair from given "name=value" string.
|
||||||
|
// return empty string on missing parts
|
||||||
|
// "key=val" => ("key", "val")
|
||||||
|
// " key = val " => ("key", "val")
|
||||||
|
// "key=" => ("key", "")
|
||||||
|
// "val" => ("", "val")
|
||||||
|
|
||||||
|
inline std::pair<std::string, std::string> extract_kv_(char sep, const std::string &str)
|
||||||
|
{
|
||||||
|
auto n = str.find(sep);
|
||||||
|
std::string k, v;
|
||||||
|
if (n == std::string::npos)
|
||||||
|
{
|
||||||
|
v = str;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
k = str.substr(0, n);
|
||||||
|
v = str.substr(n + 1);
|
||||||
|
}
|
||||||
|
return std::make_pair(trim_(k), trim_(v));
|
||||||
|
}
|
||||||
|
|
||||||
|
// return vector of key/value pairs from sequence of "K1=V1,K2=V2,.."
|
||||||
|
// "a=AAA,b=BBB,c=CCC,.." => {("a","AAA"),("b","BBB"),("c", "CCC"),...}
|
||||||
|
inline std::unordered_map<std::string, std::string> extract_key_vals_(const std::string &str)
|
||||||
|
{
|
||||||
|
std::string token;
|
||||||
|
std::istringstream token_stream(str);
|
||||||
|
std::unordered_map<std::string, std::string> rv{};
|
||||||
|
while (std::getline(token_stream, token, ','))
|
||||||
|
{
|
||||||
|
if (token.empty())
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
auto kv = extract_kv_('=', token);
|
||||||
|
rv[kv.first] = kv.second;
|
||||||
|
}
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
SPDLOG_INLINE void load_levels(const std::string &input)
|
||||||
|
{
|
||||||
|
if (input.empty() || input.size() > 512)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto key_vals = extract_key_vals_(input);
|
||||||
|
std::unordered_map<std::string, level::level_enum> levels;
|
||||||
|
level::level_enum global_level = level::info;
|
||||||
|
bool global_level_found = false;
|
||||||
|
|
||||||
|
for (auto &name_level : key_vals)
|
||||||
|
{
|
||||||
|
auto &logger_name = name_level.first;
|
||||||
|
auto level_name = to_lower_(name_level.second);
|
||||||
|
auto level = level::from_str(level_name);
|
||||||
|
// ignore unrecognized level names
|
||||||
|
if (level == level::off && level_name != "off")
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (logger_name.empty()) // no logger name indicate global level
|
||||||
|
{
|
||||||
|
global_level_found = true;
|
||||||
|
global_level = level;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
levels[logger_name] = level;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
details::registry::instance().set_levels(std::move(levels), global_level_found ? &global_level : nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace helpers
|
||||||
|
} // namespace cfg
|
||||||
|
} // namespace spdlog
|
||||||
29
thirdparty/spdlog/cfg/helpers.h
vendored
Normal file
29
thirdparty/spdlog/cfg/helpers.h
vendored
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
|
||||||
|
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <spdlog/common.h>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
|
namespace spdlog {
|
||||||
|
namespace cfg {
|
||||||
|
namespace helpers {
|
||||||
|
//
|
||||||
|
// Init levels from given string
|
||||||
|
//
|
||||||
|
// Examples:
|
||||||
|
//
|
||||||
|
// set global level to debug: "debug"
|
||||||
|
// turn off all logging except for logger1: "off,logger1=debug"
|
||||||
|
// turn off all logging except for logger1 and logger2: "off,logger1=debug,logger2=info"
|
||||||
|
//
|
||||||
|
SPDLOG_API void load_levels(const std::string &txt);
|
||||||
|
} // namespace helpers
|
||||||
|
|
||||||
|
} // namespace cfg
|
||||||
|
} // namespace spdlog
|
||||||
|
|
||||||
|
#ifdef SPDLOG_HEADER_ONLY
|
||||||
|
# include "helpers-inl.h"
|
||||||
|
#endif // SPDLOG_HEADER_ONLY
|
||||||
78
thirdparty/spdlog/common-inl.h
vendored
Normal file
78
thirdparty/spdlog/common-inl.h
vendored
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
|
||||||
|
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifndef SPDLOG_HEADER_ONLY
|
||||||
|
# include <spdlog/common.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <iterator>
|
||||||
|
|
||||||
|
namespace spdlog {
|
||||||
|
namespace level {
|
||||||
|
|
||||||
|
#if __cplusplus >= 201703L
|
||||||
|
constexpr
|
||||||
|
#endif
|
||||||
|
static string_view_t level_string_views[] SPDLOG_LEVEL_NAMES;
|
||||||
|
|
||||||
|
static const char *short_level_names[] SPDLOG_SHORT_LEVEL_NAMES;
|
||||||
|
|
||||||
|
SPDLOG_INLINE const string_view_t &to_string_view(spdlog::level::level_enum l) SPDLOG_NOEXCEPT
|
||||||
|
{
|
||||||
|
return level_string_views[l];
|
||||||
|
}
|
||||||
|
|
||||||
|
SPDLOG_INLINE const char *to_short_c_str(spdlog::level::level_enum l) SPDLOG_NOEXCEPT
|
||||||
|
{
|
||||||
|
return short_level_names[l];
|
||||||
|
}
|
||||||
|
|
||||||
|
SPDLOG_INLINE spdlog::level::level_enum from_str(const std::string &name) SPDLOG_NOEXCEPT
|
||||||
|
{
|
||||||
|
auto it = std::find(std::begin(level_string_views), std::end(level_string_views), name);
|
||||||
|
if (it != std::end(level_string_views))
|
||||||
|
return static_cast<level::level_enum>(it - std::begin(level_string_views));
|
||||||
|
|
||||||
|
// check also for "warn" and "err" before giving up..
|
||||||
|
if (name == "warn")
|
||||||
|
{
|
||||||
|
return level::warn;
|
||||||
|
}
|
||||||
|
if (name == "err")
|
||||||
|
{
|
||||||
|
return level::err;
|
||||||
|
}
|
||||||
|
return level::off;
|
||||||
|
}
|
||||||
|
} // namespace level
|
||||||
|
|
||||||
|
SPDLOG_INLINE spdlog_ex::spdlog_ex(std::string msg)
|
||||||
|
: msg_(std::move(msg))
|
||||||
|
{}
|
||||||
|
|
||||||
|
SPDLOG_INLINE spdlog_ex::spdlog_ex(const std::string &msg, int last_errno)
|
||||||
|
{
|
||||||
|
memory_buf_t outbuf;
|
||||||
|
fmt::format_system_error(outbuf, last_errno, msg.c_str());
|
||||||
|
msg_ = fmt::to_string(outbuf);
|
||||||
|
}
|
||||||
|
|
||||||
|
SPDLOG_INLINE const char *spdlog_ex::what() const SPDLOG_NOEXCEPT
|
||||||
|
{
|
||||||
|
return msg_.c_str();
|
||||||
|
}
|
||||||
|
|
||||||
|
SPDLOG_INLINE void throw_spdlog_ex(const std::string &msg, int last_errno)
|
||||||
|
{
|
||||||
|
SPDLOG_THROW(spdlog_ex(msg, last_errno));
|
||||||
|
}
|
||||||
|
|
||||||
|
SPDLOG_INLINE void throw_spdlog_ex(std::string msg)
|
||||||
|
{
|
||||||
|
SPDLOG_THROW(spdlog_ex(std::move(msg)));
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace spdlog
|
||||||
276
thirdparty/spdlog/common.h
vendored
Normal file
276
thirdparty/spdlog/common.h
vendored
Normal file
@@ -0,0 +1,276 @@
|
|||||||
|
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
|
||||||
|
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <spdlog/tweakme.h>
|
||||||
|
#include <spdlog/details/null_mutex.h>
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
|
#include <chrono>
|
||||||
|
#include <initializer_list>
|
||||||
|
#include <memory>
|
||||||
|
#include <exception>
|
||||||
|
#include <string>
|
||||||
|
#include <type_traits>
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
#ifdef SPDLOG_COMPILED_LIB
|
||||||
|
# undef SPDLOG_HEADER_ONLY
|
||||||
|
# if defined(_WIN32) && defined(SPDLOG_SHARED_LIB)
|
||||||
|
# ifdef spdlog_EXPORTS
|
||||||
|
# define SPDLOG_API __declspec(dllexport)
|
||||||
|
# else
|
||||||
|
# define SPDLOG_API __declspec(dllimport)
|
||||||
|
# endif
|
||||||
|
# else // !defined(_WIN32) || !defined(SPDLOG_SHARED_LIB)
|
||||||
|
# define SPDLOG_API
|
||||||
|
# endif
|
||||||
|
# define SPDLOG_INLINE
|
||||||
|
#else // !defined(SPDLOG_COMPILED_LIB)
|
||||||
|
# define SPDLOG_API
|
||||||
|
# define SPDLOG_HEADER_ONLY
|
||||||
|
# define SPDLOG_INLINE inline
|
||||||
|
#endif // #ifdef SPDLOG_COMPILED_LIB
|
||||||
|
|
||||||
|
#include <spdlog/fmt/fmt.h>
|
||||||
|
|
||||||
|
// backward compatibility with fmt versions older than 8
|
||||||
|
#if FMT_VERSION >= 80000
|
||||||
|
# define SPDLOG_FMT_RUNTIME(format_string) fmt::runtime(format_string)
|
||||||
|
# if defined(SPDLOG_WCHAR_FILENAMES) || defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT)
|
||||||
|
# include <spdlog/fmt/xchar.h>
|
||||||
|
# endif
|
||||||
|
#else
|
||||||
|
# define SPDLOG_FMT_RUNTIME(format_string) format_string
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// visual studio upto 2013 does not support noexcept nor constexpr
|
||||||
|
#if defined(_MSC_VER) && (_MSC_VER < 1900)
|
||||||
|
# define SPDLOG_NOEXCEPT _NOEXCEPT
|
||||||
|
# define SPDLOG_CONSTEXPR
|
||||||
|
#else
|
||||||
|
# define SPDLOG_NOEXCEPT noexcept
|
||||||
|
# define SPDLOG_CONSTEXPR constexpr
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__GNUC__) || defined(__clang__)
|
||||||
|
# define SPDLOG_DEPRECATED __attribute__((deprecated))
|
||||||
|
#elif defined(_MSC_VER)
|
||||||
|
# define SPDLOG_DEPRECATED __declspec(deprecated)
|
||||||
|
#else
|
||||||
|
# define SPDLOG_DEPRECATED
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// disable thread local on msvc 2013
|
||||||
|
#ifndef SPDLOG_NO_TLS
|
||||||
|
# if (defined(_MSC_VER) && (_MSC_VER < 1900)) || defined(__cplusplus_winrt)
|
||||||
|
# define SPDLOG_NO_TLS 1
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef SPDLOG_FUNCTION
|
||||||
|
# define SPDLOG_FUNCTION static_cast<const char *>(__FUNCTION__)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef SPDLOG_NO_EXCEPTIONS
|
||||||
|
# define SPDLOG_TRY
|
||||||
|
# define SPDLOG_THROW(ex) \
|
||||||
|
do \
|
||||||
|
{ \
|
||||||
|
printf("spdlog fatal error: %s\n", ex.what()); \
|
||||||
|
std::abort(); \
|
||||||
|
} while (0)
|
||||||
|
# define SPDLOG_CATCH_STD
|
||||||
|
#else
|
||||||
|
# define SPDLOG_TRY try
|
||||||
|
# define SPDLOG_THROW(ex) throw(ex)
|
||||||
|
# define SPDLOG_CATCH_STD \
|
||||||
|
catch (const std::exception &) {}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace spdlog {
|
||||||
|
|
||||||
|
class formatter;
|
||||||
|
|
||||||
|
namespace sinks {
|
||||||
|
class sink;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES)
|
||||||
|
using filename_t = std::wstring;
|
||||||
|
// allow macro expansion to occur in SPDLOG_FILENAME_T
|
||||||
|
# define SPDLOG_FILENAME_T_INNER(s) L##s
|
||||||
|
# define SPDLOG_FILENAME_T(s) SPDLOG_FILENAME_T_INNER(s)
|
||||||
|
#else
|
||||||
|
using filename_t = std::string;
|
||||||
|
# define SPDLOG_FILENAME_T(s) s
|
||||||
|
#endif
|
||||||
|
|
||||||
|
using log_clock = std::chrono::system_clock;
|
||||||
|
using sink_ptr = std::shared_ptr<sinks::sink>;
|
||||||
|
using sinks_init_list = std::initializer_list<sink_ptr>;
|
||||||
|
using err_handler = std::function<void(const std::string &err_msg)>;
|
||||||
|
using string_view_t = fmt::basic_string_view<char>;
|
||||||
|
using wstring_view_t = fmt::basic_string_view<wchar_t>;
|
||||||
|
using memory_buf_t = fmt::basic_memory_buffer<char, 250>;
|
||||||
|
using wmemory_buf_t = fmt::basic_memory_buffer<wchar_t, 250>;
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
using remove_cvref_t = typename std::remove_cv<typename std::remove_reference<T>::type>::type;
|
||||||
|
|
||||||
|
// clang doesn't like SFINAE disabled constructor in std::is_convertible<> so have to repeat the condition from basic_format_string here,
|
||||||
|
// in addition, fmt::basic_runtime<Char> is only convertible to basic_format_string<Char> but not basic_string_view<Char>
|
||||||
|
template<class T, class Char = char>
|
||||||
|
struct is_convertible_to_basic_format_string
|
||||||
|
: std::integral_constant<bool,
|
||||||
|
std::is_convertible<T, fmt::basic_string_view<Char>>::value || std::is_same<remove_cvref_t<T>, fmt::basic_runtime<Char>>::value>
|
||||||
|
{};
|
||||||
|
|
||||||
|
#ifdef SPDLOG_WCHAR_TO_UTF8_SUPPORT
|
||||||
|
# ifndef _WIN32
|
||||||
|
# error SPDLOG_WCHAR_TO_UTF8_SUPPORT only supported on windows
|
||||||
|
# endif // _WIN32
|
||||||
|
#endif // SPDLOG_WCHAR_TO_UTF8_SUPPORT
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
struct is_convertible_to_any_format_string : std::integral_constant<bool, is_convertible_to_basic_format_string<T, char>::value ||
|
||||||
|
is_convertible_to_basic_format_string<T, wchar_t>::value>
|
||||||
|
{};
|
||||||
|
|
||||||
|
#if defined(SPDLOG_NO_ATOMIC_LEVELS)
|
||||||
|
using level_t = details::null_atomic_int;
|
||||||
|
#else
|
||||||
|
using level_t = std::atomic<int>;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define SPDLOG_LEVEL_TRACE 0
|
||||||
|
#define SPDLOG_LEVEL_DEBUG 1
|
||||||
|
#define SPDLOG_LEVEL_INFO 2
|
||||||
|
#define SPDLOG_LEVEL_WARN 3
|
||||||
|
#define SPDLOG_LEVEL_ERROR 4
|
||||||
|
#define SPDLOG_LEVEL_CRITICAL 5
|
||||||
|
#define SPDLOG_LEVEL_OFF 6
|
||||||
|
|
||||||
|
#if !defined(SPDLOG_ACTIVE_LEVEL)
|
||||||
|
# define SPDLOG_ACTIVE_LEVEL SPDLOG_LEVEL_INFO
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Log level enum
|
||||||
|
namespace level {
|
||||||
|
enum level_enum
|
||||||
|
{
|
||||||
|
trace = SPDLOG_LEVEL_TRACE,
|
||||||
|
debug = SPDLOG_LEVEL_DEBUG,
|
||||||
|
info = SPDLOG_LEVEL_INFO,
|
||||||
|
warn = SPDLOG_LEVEL_WARN,
|
||||||
|
err = SPDLOG_LEVEL_ERROR,
|
||||||
|
critical = SPDLOG_LEVEL_CRITICAL,
|
||||||
|
off = SPDLOG_LEVEL_OFF,
|
||||||
|
n_levels
|
||||||
|
};
|
||||||
|
|
||||||
|
#define SPDLOG_LEVEL_NAME_TRACE spdlog::string_view_t("trace", 5)
|
||||||
|
#define SPDLOG_LEVEL_NAME_DEBUG spdlog::string_view_t("debug", 5)
|
||||||
|
#define SPDLOG_LEVEL_NAME_INFO spdlog::string_view_t("info", 4)
|
||||||
|
#define SPDLOG_LEVEL_NAME_WARNING spdlog::string_view_t("warning", 7)
|
||||||
|
#define SPDLOG_LEVEL_NAME_ERROR spdlog::string_view_t("error", 5)
|
||||||
|
#define SPDLOG_LEVEL_NAME_CRITICAL spdlog::string_view_t("critical", 8)
|
||||||
|
#define SPDLOG_LEVEL_NAME_OFF spdlog::string_view_t("off", 3)
|
||||||
|
|
||||||
|
#if !defined(SPDLOG_LEVEL_NAMES)
|
||||||
|
# define SPDLOG_LEVEL_NAMES \
|
||||||
|
{ \
|
||||||
|
SPDLOG_LEVEL_NAME_TRACE, SPDLOG_LEVEL_NAME_DEBUG, SPDLOG_LEVEL_NAME_INFO, SPDLOG_LEVEL_NAME_WARNING, SPDLOG_LEVEL_NAME_ERROR, \
|
||||||
|
SPDLOG_LEVEL_NAME_CRITICAL, SPDLOG_LEVEL_NAME_OFF \
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(SPDLOG_SHORT_LEVEL_NAMES)
|
||||||
|
|
||||||
|
# define SPDLOG_SHORT_LEVEL_NAMES \
|
||||||
|
{ \
|
||||||
|
"T", "D", "I", "W", "E", "C", "O" \
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
SPDLOG_API const string_view_t &to_string_view(spdlog::level::level_enum l) SPDLOG_NOEXCEPT;
|
||||||
|
SPDLOG_API const char *to_short_c_str(spdlog::level::level_enum l) SPDLOG_NOEXCEPT;
|
||||||
|
SPDLOG_API spdlog::level::level_enum from_str(const std::string &name) SPDLOG_NOEXCEPT;
|
||||||
|
|
||||||
|
} // namespace level
|
||||||
|
|
||||||
|
//
|
||||||
|
// Color mode used by sinks with color support.
|
||||||
|
//
|
||||||
|
enum class color_mode
|
||||||
|
{
|
||||||
|
always,
|
||||||
|
automatic,
|
||||||
|
never
|
||||||
|
};
|
||||||
|
|
||||||
|
//
|
||||||
|
// Pattern time - specific time getting to use for pattern_formatter.
|
||||||
|
// local time by default
|
||||||
|
//
|
||||||
|
enum class pattern_time_type
|
||||||
|
{
|
||||||
|
local, // log localtime
|
||||||
|
utc // log utc
|
||||||
|
};
|
||||||
|
|
||||||
|
//
|
||||||
|
// Log exception
|
||||||
|
//
|
||||||
|
class SPDLOG_API spdlog_ex : public std::exception
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit spdlog_ex(std::string msg);
|
||||||
|
spdlog_ex(const std::string &msg, int last_errno);
|
||||||
|
const char *what() const SPDLOG_NOEXCEPT override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string msg_;
|
||||||
|
};
|
||||||
|
|
||||||
|
[[noreturn]] SPDLOG_API void throw_spdlog_ex(const std::string &msg, int last_errno);
|
||||||
|
[[noreturn]] SPDLOG_API void throw_spdlog_ex(std::string msg);
|
||||||
|
|
||||||
|
struct source_loc
|
||||||
|
{
|
||||||
|
SPDLOG_CONSTEXPR source_loc() = default;
|
||||||
|
SPDLOG_CONSTEXPR source_loc(const char *filename_in, int line_in, const char *funcname_in)
|
||||||
|
: filename{filename_in}
|
||||||
|
, line{line_in}
|
||||||
|
, funcname{funcname_in}
|
||||||
|
{}
|
||||||
|
|
||||||
|
SPDLOG_CONSTEXPR bool empty() const SPDLOG_NOEXCEPT
|
||||||
|
{
|
||||||
|
return line == 0;
|
||||||
|
}
|
||||||
|
const char *filename{nullptr};
|
||||||
|
int line{0};
|
||||||
|
const char *funcname{nullptr};
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace details {
|
||||||
|
// make_unique support for pre c++14
|
||||||
|
|
||||||
|
#if __cplusplus >= 201402L // C++14 and beyond
|
||||||
|
using std::make_unique;
|
||||||
|
#else
|
||||||
|
template<typename T, typename... Args>
|
||||||
|
std::unique_ptr<T> make_unique(Args &&...args)
|
||||||
|
{
|
||||||
|
static_assert(!std::is_array<T>::value, "arrays not supported");
|
||||||
|
return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
} // namespace details
|
||||||
|
} // namespace spdlog
|
||||||
|
|
||||||
|
#ifdef SPDLOG_HEADER_ONLY
|
||||||
|
# include "common-inl.h"
|
||||||
|
#endif
|
||||||
69
thirdparty/spdlog/details/backtracer-inl.h
vendored
Normal file
69
thirdparty/spdlog/details/backtracer-inl.h
vendored
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
|
||||||
|
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifndef SPDLOG_HEADER_ONLY
|
||||||
|
# include <spdlog/details/backtracer.h>
|
||||||
|
#endif
|
||||||
|
namespace spdlog {
|
||||||
|
namespace details {
|
||||||
|
SPDLOG_INLINE backtracer::backtracer(const backtracer &other)
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(other.mutex_);
|
||||||
|
enabled_ = other.enabled();
|
||||||
|
messages_ = other.messages_;
|
||||||
|
}
|
||||||
|
|
||||||
|
SPDLOG_INLINE backtracer::backtracer(backtracer &&other) SPDLOG_NOEXCEPT
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(other.mutex_);
|
||||||
|
enabled_ = other.enabled();
|
||||||
|
messages_ = std::move(other.messages_);
|
||||||
|
}
|
||||||
|
|
||||||
|
SPDLOG_INLINE backtracer &backtracer::operator=(backtracer other)
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(mutex_);
|
||||||
|
enabled_ = other.enabled();
|
||||||
|
messages_ = std::move(other.messages_);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
SPDLOG_INLINE void backtracer::enable(size_t size)
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock{mutex_};
|
||||||
|
enabled_.store(true, std::memory_order_relaxed);
|
||||||
|
messages_ = circular_q<log_msg_buffer>{size};
|
||||||
|
}
|
||||||
|
|
||||||
|
SPDLOG_INLINE void backtracer::disable()
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock{mutex_};
|
||||||
|
enabled_.store(false, std::memory_order_relaxed);
|
||||||
|
}
|
||||||
|
|
||||||
|
SPDLOG_INLINE bool backtracer::enabled() const
|
||||||
|
{
|
||||||
|
return enabled_.load(std::memory_order_relaxed);
|
||||||
|
}
|
||||||
|
|
||||||
|
SPDLOG_INLINE void backtracer::push_back(const log_msg &msg)
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock{mutex_};
|
||||||
|
messages_.push_back(log_msg_buffer{msg});
|
||||||
|
}
|
||||||
|
|
||||||
|
// pop all items in the q and apply the given fun on each of them.
|
||||||
|
SPDLOG_INLINE void backtracer::foreach_pop(std::function<void(const details::log_msg &)> fun)
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock{mutex_};
|
||||||
|
while (!messages_.empty())
|
||||||
|
{
|
||||||
|
auto &front_msg = messages_.front();
|
||||||
|
fun(front_msg);
|
||||||
|
messages_.pop_front();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // namespace details
|
||||||
|
} // namespace spdlog
|
||||||
45
thirdparty/spdlog/details/backtracer.h
vendored
Normal file
45
thirdparty/spdlog/details/backtracer.h
vendored
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
|
||||||
|
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <spdlog/details/log_msg_buffer.h>
|
||||||
|
#include <spdlog/details/circular_q.h>
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
|
#include <mutex>
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
// Store log messages in circular buffer.
|
||||||
|
// Useful for storing debug data in case of error/warning happens.
|
||||||
|
|
||||||
|
namespace spdlog {
|
||||||
|
namespace details {
|
||||||
|
class SPDLOG_API backtracer
|
||||||
|
{
|
||||||
|
mutable std::mutex mutex_;
|
||||||
|
std::atomic<bool> enabled_{false};
|
||||||
|
circular_q<log_msg_buffer> messages_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
backtracer() = default;
|
||||||
|
backtracer(const backtracer &other);
|
||||||
|
|
||||||
|
backtracer(backtracer &&other) SPDLOG_NOEXCEPT;
|
||||||
|
backtracer &operator=(backtracer other);
|
||||||
|
|
||||||
|
void enable(size_t size);
|
||||||
|
void disable();
|
||||||
|
bool enabled() const;
|
||||||
|
void push_back(const log_msg &msg);
|
||||||
|
|
||||||
|
// pop all items in the q and apply the given fun on each of them.
|
||||||
|
void foreach_pop(std::function<void(const details::log_msg &)> fun);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace details
|
||||||
|
} // namespace spdlog
|
||||||
|
|
||||||
|
#ifdef SPDLOG_HEADER_ONLY
|
||||||
|
# include "backtracer-inl.h"
|
||||||
|
#endif
|
||||||
141
thirdparty/spdlog/details/circular_q.h
vendored
Normal file
141
thirdparty/spdlog/details/circular_q.h
vendored
Normal file
@@ -0,0 +1,141 @@
|
|||||||
|
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
|
||||||
|
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||||
|
|
||||||
|
// circular q view of std::vector.
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
namespace spdlog {
|
||||||
|
namespace details {
|
||||||
|
template<typename T>
|
||||||
|
class circular_q
|
||||||
|
{
|
||||||
|
size_t max_items_ = 0;
|
||||||
|
typename std::vector<T>::size_type head_ = 0;
|
||||||
|
typename std::vector<T>::size_type tail_ = 0;
|
||||||
|
size_t overrun_counter_ = 0;
|
||||||
|
std::vector<T> v_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
using value_type = T;
|
||||||
|
|
||||||
|
// empty ctor - create a disabled queue with no elements allocated at all
|
||||||
|
circular_q() = default;
|
||||||
|
|
||||||
|
explicit circular_q(size_t max_items)
|
||||||
|
: max_items_(max_items + 1) // one item is reserved as marker for full q
|
||||||
|
, v_(max_items_)
|
||||||
|
{}
|
||||||
|
|
||||||
|
circular_q(const circular_q &) = default;
|
||||||
|
circular_q &operator=(const circular_q &) = default;
|
||||||
|
|
||||||
|
// move cannot be default,
|
||||||
|
// since we need to reset head_, tail_, etc to zero in the moved object
|
||||||
|
circular_q(circular_q &&other) SPDLOG_NOEXCEPT
|
||||||
|
{
|
||||||
|
copy_moveable(std::move(other));
|
||||||
|
}
|
||||||
|
|
||||||
|
circular_q &operator=(circular_q &&other) SPDLOG_NOEXCEPT
|
||||||
|
{
|
||||||
|
copy_moveable(std::move(other));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// push back, overrun (oldest) item if no room left
|
||||||
|
void push_back(T &&item)
|
||||||
|
{
|
||||||
|
if (max_items_ > 0)
|
||||||
|
{
|
||||||
|
v_[tail_] = std::move(item);
|
||||||
|
tail_ = (tail_ + 1) % max_items_;
|
||||||
|
|
||||||
|
if (tail_ == head_) // overrun last item if full
|
||||||
|
{
|
||||||
|
head_ = (head_ + 1) % max_items_;
|
||||||
|
++overrun_counter_;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return reference to the front item.
|
||||||
|
// If there are no elements in the container, the behavior is undefined.
|
||||||
|
const T &front() const
|
||||||
|
{
|
||||||
|
return v_[head_];
|
||||||
|
}
|
||||||
|
|
||||||
|
T &front()
|
||||||
|
{
|
||||||
|
return v_[head_];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return number of elements actually stored
|
||||||
|
size_t size() const
|
||||||
|
{
|
||||||
|
if (tail_ >= head_)
|
||||||
|
{
|
||||||
|
return tail_ - head_;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return max_items_ - (head_ - tail_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return const reference to item by index.
|
||||||
|
// If index is out of range 0…size()-1, the behavior is undefined.
|
||||||
|
const T &at(size_t i) const
|
||||||
|
{
|
||||||
|
assert(i < size());
|
||||||
|
return v_[(head_ + i) % max_items_];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pop item from front.
|
||||||
|
// If there are no elements in the container, the behavior is undefined.
|
||||||
|
void pop_front()
|
||||||
|
{
|
||||||
|
head_ = (head_ + 1) % max_items_;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool empty() const
|
||||||
|
{
|
||||||
|
return tail_ == head_;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool full() const
|
||||||
|
{
|
||||||
|
// head is ahead of the tail by 1
|
||||||
|
if (max_items_ > 0)
|
||||||
|
{
|
||||||
|
return ((tail_ + 1) % max_items_) == head_;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t overrun_counter() const
|
||||||
|
{
|
||||||
|
return overrun_counter_;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
// copy from other&& and reset it to disabled state
|
||||||
|
void copy_moveable(circular_q &&other) SPDLOG_NOEXCEPT
|
||||||
|
{
|
||||||
|
max_items_ = other.max_items_;
|
||||||
|
head_ = other.head_;
|
||||||
|
tail_ = other.tail_;
|
||||||
|
overrun_counter_ = other.overrun_counter_;
|
||||||
|
v_ = std::move(other.v_);
|
||||||
|
|
||||||
|
// put &&other in disabled, but valid state
|
||||||
|
other.max_items_ = 0;
|
||||||
|
other.head_ = other.tail_ = 0;
|
||||||
|
other.overrun_counter_ = 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} // namespace details
|
||||||
|
} // namespace spdlog
|
||||||
32
thirdparty/spdlog/details/console_globals.h
vendored
Normal file
32
thirdparty/spdlog/details/console_globals.h
vendored
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
|
||||||
|
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <spdlog/details/null_mutex.h>
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
|
namespace spdlog {
|
||||||
|
namespace details {
|
||||||
|
|
||||||
|
struct console_mutex
|
||||||
|
{
|
||||||
|
using mutex_t = std::mutex;
|
||||||
|
static mutex_t &mutex()
|
||||||
|
{
|
||||||
|
static mutex_t s_mutex;
|
||||||
|
return s_mutex;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct console_nullmutex
|
||||||
|
{
|
||||||
|
using mutex_t = null_mutex;
|
||||||
|
static mutex_t &mutex()
|
||||||
|
{
|
||||||
|
static mutex_t s_mutex;
|
||||||
|
return s_mutex;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} // namespace details
|
||||||
|
} // namespace spdlog
|
||||||
147
thirdparty/spdlog/details/file_helper-inl.h
vendored
Normal file
147
thirdparty/spdlog/details/file_helper-inl.h
vendored
Normal file
@@ -0,0 +1,147 @@
|
|||||||
|
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
|
||||||
|
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifndef SPDLOG_HEADER_ONLY
|
||||||
|
# include <spdlog/details/file_helper.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <spdlog/details/os.h>
|
||||||
|
#include <spdlog/common.h>
|
||||||
|
|
||||||
|
#include <cerrno>
|
||||||
|
#include <chrono>
|
||||||
|
#include <cstdio>
|
||||||
|
#include <string>
|
||||||
|
#include <thread>
|
||||||
|
#include <tuple>
|
||||||
|
|
||||||
|
namespace spdlog {
|
||||||
|
namespace details {
|
||||||
|
|
||||||
|
SPDLOG_INLINE file_helper::~file_helper()
|
||||||
|
{
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
|
||||||
|
SPDLOG_INLINE void file_helper::open(const filename_t &fname, bool truncate)
|
||||||
|
{
|
||||||
|
close();
|
||||||
|
filename_ = fname;
|
||||||
|
|
||||||
|
auto *mode = SPDLOG_FILENAME_T("ab");
|
||||||
|
auto *trunc_mode = SPDLOG_FILENAME_T("wb");
|
||||||
|
|
||||||
|
for (int tries = 0; tries < open_tries_; ++tries)
|
||||||
|
{
|
||||||
|
// create containing folder if not exists already.
|
||||||
|
os::create_dir(os::dir_name(fname));
|
||||||
|
if (truncate)
|
||||||
|
{
|
||||||
|
// Truncate by opening-and-closing a tmp file in "wb" mode, always
|
||||||
|
// opening the actual log-we-write-to in "ab" mode, since that
|
||||||
|
// interacts more politely with eternal processes that might
|
||||||
|
// rotate/truncate the file underneath us.
|
||||||
|
std::FILE *tmp;
|
||||||
|
if (os::fopen_s(&tmp, fname, trunc_mode))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
std::fclose(tmp);
|
||||||
|
}
|
||||||
|
if (!os::fopen_s(&fd_, fname, mode))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
details::os::sleep_for_millis(open_interval_);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw_spdlog_ex("Failed opening file " + os::filename_to_str(filename_) + " for writing", errno);
|
||||||
|
}
|
||||||
|
|
||||||
|
SPDLOG_INLINE void file_helper::reopen(bool truncate)
|
||||||
|
{
|
||||||
|
if (filename_.empty())
|
||||||
|
{
|
||||||
|
throw_spdlog_ex("Failed re opening file - was not opened before");
|
||||||
|
}
|
||||||
|
this->open(filename_, truncate);
|
||||||
|
}
|
||||||
|
|
||||||
|
SPDLOG_INLINE void file_helper::flush()
|
||||||
|
{
|
||||||
|
std::fflush(fd_);
|
||||||
|
}
|
||||||
|
|
||||||
|
SPDLOG_INLINE void file_helper::close()
|
||||||
|
{
|
||||||
|
if (fd_ != nullptr)
|
||||||
|
{
|
||||||
|
std::fclose(fd_);
|
||||||
|
fd_ = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SPDLOG_INLINE void file_helper::write(const memory_buf_t &buf)
|
||||||
|
{
|
||||||
|
size_t msg_size = buf.size();
|
||||||
|
auto data = buf.data();
|
||||||
|
if (std::fwrite(data, 1, msg_size, fd_) != msg_size)
|
||||||
|
{
|
||||||
|
throw_spdlog_ex("Failed writing to file " + os::filename_to_str(filename_), errno);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SPDLOG_INLINE size_t file_helper::size() const
|
||||||
|
{
|
||||||
|
if (fd_ == nullptr)
|
||||||
|
{
|
||||||
|
throw_spdlog_ex("Cannot use size() on closed file " + os::filename_to_str(filename_));
|
||||||
|
}
|
||||||
|
return os::filesize(fd_);
|
||||||
|
}
|
||||||
|
|
||||||
|
SPDLOG_INLINE const filename_t &file_helper::filename() const
|
||||||
|
{
|
||||||
|
return filename_;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// return file path and its extension:
|
||||||
|
//
|
||||||
|
// "mylog.txt" => ("mylog", ".txt")
|
||||||
|
// "mylog" => ("mylog", "")
|
||||||
|
// "mylog." => ("mylog.", "")
|
||||||
|
// "/dir1/dir2/mylog.txt" => ("/dir1/dir2/mylog", ".txt")
|
||||||
|
//
|
||||||
|
// the starting dot in filenames is ignored (hidden files):
|
||||||
|
//
|
||||||
|
// ".mylog" => (".mylog". "")
|
||||||
|
// "my_folder/.mylog" => ("my_folder/.mylog", "")
|
||||||
|
// "my_folder/.mylog.txt" => ("my_folder/.mylog", ".txt")
|
||||||
|
SPDLOG_INLINE std::tuple<filename_t, filename_t> file_helper::split_by_extension(const filename_t &fname)
|
||||||
|
{
|
||||||
|
auto ext_index = fname.rfind('.');
|
||||||
|
|
||||||
|
// no valid extension found - return whole path and empty string as
|
||||||
|
// extension
|
||||||
|
if (ext_index == filename_t::npos || ext_index == 0 || ext_index == fname.size() - 1)
|
||||||
|
{
|
||||||
|
return std::make_tuple(fname, filename_t());
|
||||||
|
}
|
||||||
|
|
||||||
|
// treat cases like "/etc/rc.d/somelogfile or "/abc/.hiddenfile"
|
||||||
|
auto folder_index = fname.find_last_of(details::os::folder_seps_filename);
|
||||||
|
if (folder_index != filename_t::npos && folder_index >= ext_index - 1)
|
||||||
|
{
|
||||||
|
return std::make_tuple(fname, filename_t());
|
||||||
|
}
|
||||||
|
|
||||||
|
// finally - return a valid base and extension tuple
|
||||||
|
return std::make_tuple(fname.substr(0, ext_index), fname.substr(ext_index));
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace details
|
||||||
|
} // namespace spdlog
|
||||||
59
thirdparty/spdlog/details/file_helper.h
vendored
Normal file
59
thirdparty/spdlog/details/file_helper.h
vendored
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
|
||||||
|
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <spdlog/common.h>
|
||||||
|
#include <tuple>
|
||||||
|
|
||||||
|
namespace spdlog {
|
||||||
|
namespace details {
|
||||||
|
|
||||||
|
// Helper class for file sinks.
|
||||||
|
// When failing to open a file, retry several times(5) with a delay interval(10 ms).
|
||||||
|
// Throw spdlog_ex exception on errors.
|
||||||
|
|
||||||
|
class SPDLOG_API file_helper
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit file_helper() = default;
|
||||||
|
|
||||||
|
file_helper(const file_helper &) = delete;
|
||||||
|
file_helper &operator=(const file_helper &) = delete;
|
||||||
|
~file_helper();
|
||||||
|
|
||||||
|
void open(const filename_t &fname, bool truncate = false);
|
||||||
|
void reopen(bool truncate);
|
||||||
|
void flush();
|
||||||
|
void close();
|
||||||
|
void write(const memory_buf_t &buf);
|
||||||
|
size_t size() const;
|
||||||
|
const filename_t &filename() const;
|
||||||
|
|
||||||
|
//
|
||||||
|
// return file path and its extension:
|
||||||
|
//
|
||||||
|
// "mylog.txt" => ("mylog", ".txt")
|
||||||
|
// "mylog" => ("mylog", "")
|
||||||
|
// "mylog." => ("mylog.", "")
|
||||||
|
// "/dir1/dir2/mylog.txt" => ("/dir1/dir2/mylog", ".txt")
|
||||||
|
//
|
||||||
|
// the starting dot in filenames is ignored (hidden files):
|
||||||
|
//
|
||||||
|
// ".mylog" => (".mylog". "")
|
||||||
|
// "my_folder/.mylog" => ("my_folder/.mylog", "")
|
||||||
|
// "my_folder/.mylog.txt" => ("my_folder/.mylog", ".txt")
|
||||||
|
static std::tuple<filename_t, filename_t> split_by_extension(const filename_t &fname);
|
||||||
|
|
||||||
|
private:
|
||||||
|
const int open_tries_ = 5;
|
||||||
|
const unsigned int open_interval_ = 10;
|
||||||
|
std::FILE *fd_{nullptr};
|
||||||
|
filename_t filename_;
|
||||||
|
};
|
||||||
|
} // namespace details
|
||||||
|
} // namespace spdlog
|
||||||
|
|
||||||
|
#ifdef SPDLOG_HEADER_ONLY
|
||||||
|
# include "file_helper-inl.h"
|
||||||
|
#endif
|
||||||
117
thirdparty/spdlog/details/fmt_helper.h
vendored
Normal file
117
thirdparty/spdlog/details/fmt_helper.h
vendored
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
|
||||||
|
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
#include <type_traits>
|
||||||
|
#include <iterator>
|
||||||
|
#include <spdlog/fmt/fmt.h>
|
||||||
|
#include <spdlog/common.h>
|
||||||
|
|
||||||
|
// Some fmt helpers to efficiently format and pad ints and strings
|
||||||
|
namespace spdlog {
|
||||||
|
namespace details {
|
||||||
|
namespace fmt_helper {
|
||||||
|
|
||||||
|
inline spdlog::string_view_t to_string_view(const memory_buf_t &buf) SPDLOG_NOEXCEPT
|
||||||
|
{
|
||||||
|
return spdlog::string_view_t{buf.data(), buf.size()};
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void append_string_view(spdlog::string_view_t view, memory_buf_t &dest)
|
||||||
|
{
|
||||||
|
auto *buf_ptr = view.data();
|
||||||
|
dest.append(buf_ptr, buf_ptr + view.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
inline void append_int(T n, memory_buf_t &dest)
|
||||||
|
{
|
||||||
|
fmt::format_int i(n);
|
||||||
|
dest.append(i.data(), i.data() + i.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
inline unsigned int count_digits(T n)
|
||||||
|
{
|
||||||
|
using count_type = typename std::conditional<(sizeof(T) > sizeof(uint32_t)), uint64_t, uint32_t>::type;
|
||||||
|
return static_cast<unsigned int>(fmt::
|
||||||
|
// fmt 7.0.0 renamed the internal namespace to detail.
|
||||||
|
// See: https://github.com/fmtlib/fmt/issues/1538
|
||||||
|
#if FMT_VERSION < 70000
|
||||||
|
internal
|
||||||
|
#else
|
||||||
|
detail
|
||||||
|
#endif
|
||||||
|
::count_digits(static_cast<count_type>(n)));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void pad2(int n, memory_buf_t &dest)
|
||||||
|
{
|
||||||
|
if (n >= 0 && n < 100) // 0-99
|
||||||
|
{
|
||||||
|
dest.push_back(static_cast<char>('0' + n / 10));
|
||||||
|
dest.push_back(static_cast<char>('0' + n % 10));
|
||||||
|
}
|
||||||
|
else // unlikely, but just in case, let fmt deal with it
|
||||||
|
{
|
||||||
|
fmt::format_to(std::back_inserter(dest), SPDLOG_FMT_RUNTIME("{:02}"), n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
inline void pad_uint(T n, unsigned int width, memory_buf_t &dest)
|
||||||
|
{
|
||||||
|
static_assert(std::is_unsigned<T>::value, "pad_uint must get unsigned T");
|
||||||
|
for (auto digits = count_digits(n); digits < width; digits++)
|
||||||
|
{
|
||||||
|
dest.push_back('0');
|
||||||
|
}
|
||||||
|
append_int(n, dest);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
inline void pad3(T n, memory_buf_t &dest)
|
||||||
|
{
|
||||||
|
static_assert(std::is_unsigned<T>::value, "pad3 must get unsigned T");
|
||||||
|
if (n < 1000)
|
||||||
|
{
|
||||||
|
dest.push_back(static_cast<char>(n / 100 + '0'));
|
||||||
|
n = n % 100;
|
||||||
|
dest.push_back(static_cast<char>((n / 10) + '0'));
|
||||||
|
dest.push_back(static_cast<char>((n % 10) + '0'));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
append_int(n, dest);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
inline void pad6(T n, memory_buf_t &dest)
|
||||||
|
{
|
||||||
|
pad_uint(n, 6, dest);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
inline void pad9(T n, memory_buf_t &dest)
|
||||||
|
{
|
||||||
|
pad_uint(n, 9, dest);
|
||||||
|
}
|
||||||
|
|
||||||
|
// return fraction of a second of the given time_point.
|
||||||
|
// e.g.
|
||||||
|
// fraction<std::milliseconds>(tp) -> will return the millis part of the second
|
||||||
|
template<typename ToDuration>
|
||||||
|
inline ToDuration time_fraction(log_clock::time_point tp)
|
||||||
|
{
|
||||||
|
using std::chrono::duration_cast;
|
||||||
|
using std::chrono::seconds;
|
||||||
|
auto duration = tp.time_since_epoch();
|
||||||
|
auto secs = duration_cast<seconds>(duration);
|
||||||
|
return duration_cast<ToDuration>(duration) - duration_cast<ToDuration>(secs);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace fmt_helper
|
||||||
|
} // namespace details
|
||||||
|
} // namespace spdlog
|
||||||
37
thirdparty/spdlog/details/log_msg-inl.h
vendored
Normal file
37
thirdparty/spdlog/details/log_msg-inl.h
vendored
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
|
||||||
|
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifndef SPDLOG_HEADER_ONLY
|
||||||
|
# include <spdlog/details/log_msg.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <spdlog/details/os.h>
|
||||||
|
|
||||||
|
namespace spdlog {
|
||||||
|
namespace details {
|
||||||
|
|
||||||
|
SPDLOG_INLINE log_msg::log_msg(spdlog::log_clock::time_point log_time, spdlog::source_loc loc, string_view_t a_logger_name,
|
||||||
|
spdlog::level::level_enum lvl, spdlog::string_view_t msg)
|
||||||
|
: logger_name(a_logger_name)
|
||||||
|
, level(lvl)
|
||||||
|
, time(log_time)
|
||||||
|
#ifndef SPDLOG_NO_THREAD_ID
|
||||||
|
, thread_id(os::thread_id())
|
||||||
|
#endif
|
||||||
|
, source(loc)
|
||||||
|
, payload(msg)
|
||||||
|
{}
|
||||||
|
|
||||||
|
SPDLOG_INLINE log_msg::log_msg(
|
||||||
|
spdlog::source_loc loc, string_view_t a_logger_name, spdlog::level::level_enum lvl, spdlog::string_view_t msg)
|
||||||
|
: log_msg(os::now(), loc, a_logger_name, lvl, msg)
|
||||||
|
{}
|
||||||
|
|
||||||
|
SPDLOG_INLINE log_msg::log_msg(string_view_t a_logger_name, spdlog::level::level_enum lvl, spdlog::string_view_t msg)
|
||||||
|
: log_msg(os::now(), source_loc{}, a_logger_name, lvl, msg)
|
||||||
|
{}
|
||||||
|
|
||||||
|
} // namespace details
|
||||||
|
} // namespace spdlog
|
||||||
37
thirdparty/spdlog/details/log_msg.h
vendored
Normal file
37
thirdparty/spdlog/details/log_msg.h
vendored
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
|
||||||
|
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <spdlog/common.h>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace spdlog {
|
||||||
|
namespace details {
|
||||||
|
struct SPDLOG_API log_msg
|
||||||
|
{
|
||||||
|
log_msg() = default;
|
||||||
|
log_msg(log_clock::time_point log_time, source_loc loc, string_view_t logger_name, level::level_enum lvl, string_view_t msg);
|
||||||
|
log_msg(source_loc loc, string_view_t logger_name, level::level_enum lvl, string_view_t msg);
|
||||||
|
log_msg(string_view_t logger_name, level::level_enum lvl, string_view_t msg);
|
||||||
|
log_msg(const log_msg &other) = default;
|
||||||
|
log_msg &operator=(const log_msg &other) = default;
|
||||||
|
|
||||||
|
string_view_t logger_name;
|
||||||
|
level::level_enum level{level::off};
|
||||||
|
log_clock::time_point time;
|
||||||
|
size_t thread_id{0};
|
||||||
|
|
||||||
|
// wrapping the formatted text with color (updated by pattern_formatter).
|
||||||
|
mutable size_t color_range_start{0};
|
||||||
|
mutable size_t color_range_end{0};
|
||||||
|
|
||||||
|
source_loc source;
|
||||||
|
string_view_t payload;
|
||||||
|
};
|
||||||
|
} // namespace details
|
||||||
|
} // namespace spdlog
|
||||||
|
|
||||||
|
#ifdef SPDLOG_HEADER_ONLY
|
||||||
|
# include "log_msg-inl.h"
|
||||||
|
#endif
|
||||||
58
thirdparty/spdlog/details/log_msg_buffer-inl.h
vendored
Normal file
58
thirdparty/spdlog/details/log_msg_buffer-inl.h
vendored
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
|
||||||
|
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifndef SPDLOG_HEADER_ONLY
|
||||||
|
# include <spdlog/details/log_msg_buffer.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace spdlog {
|
||||||
|
namespace details {
|
||||||
|
|
||||||
|
SPDLOG_INLINE log_msg_buffer::log_msg_buffer(const log_msg &orig_msg)
|
||||||
|
: log_msg{orig_msg}
|
||||||
|
{
|
||||||
|
buffer.append(logger_name.begin(), logger_name.end());
|
||||||
|
buffer.append(payload.begin(), payload.end());
|
||||||
|
update_string_views();
|
||||||
|
}
|
||||||
|
|
||||||
|
SPDLOG_INLINE log_msg_buffer::log_msg_buffer(const log_msg_buffer &other)
|
||||||
|
: log_msg{other}
|
||||||
|
{
|
||||||
|
buffer.append(logger_name.begin(), logger_name.end());
|
||||||
|
buffer.append(payload.begin(), payload.end());
|
||||||
|
update_string_views();
|
||||||
|
}
|
||||||
|
|
||||||
|
SPDLOG_INLINE log_msg_buffer::log_msg_buffer(log_msg_buffer &&other) SPDLOG_NOEXCEPT : log_msg{other}, buffer{std::move(other.buffer)}
|
||||||
|
{
|
||||||
|
update_string_views();
|
||||||
|
}
|
||||||
|
|
||||||
|
SPDLOG_INLINE log_msg_buffer &log_msg_buffer::operator=(const log_msg_buffer &other)
|
||||||
|
{
|
||||||
|
log_msg::operator=(other);
|
||||||
|
buffer.clear();
|
||||||
|
buffer.append(other.buffer.data(), other.buffer.data() + other.buffer.size());
|
||||||
|
update_string_views();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
SPDLOG_INLINE log_msg_buffer &log_msg_buffer::operator=(log_msg_buffer &&other) SPDLOG_NOEXCEPT
|
||||||
|
{
|
||||||
|
log_msg::operator=(other);
|
||||||
|
buffer = std::move(other.buffer);
|
||||||
|
update_string_views();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
SPDLOG_INLINE void log_msg_buffer::update_string_views()
|
||||||
|
{
|
||||||
|
logger_name = string_view_t{buffer.data(), logger_name.size()};
|
||||||
|
payload = string_view_t{buffer.data() + logger_name.size(), payload.size()};
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace details
|
||||||
|
} // namespace spdlog
|
||||||
33
thirdparty/spdlog/details/log_msg_buffer.h
vendored
Normal file
33
thirdparty/spdlog/details/log_msg_buffer.h
vendored
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
|
||||||
|
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <spdlog/details/log_msg.h>
|
||||||
|
|
||||||
|
namespace spdlog {
|
||||||
|
namespace details {
|
||||||
|
|
||||||
|
// Extend log_msg with internal buffer to store its payload.
|
||||||
|
// This is needed since log_msg holds string_views that points to stack data.
|
||||||
|
|
||||||
|
class SPDLOG_API log_msg_buffer : public log_msg
|
||||||
|
{
|
||||||
|
memory_buf_t buffer;
|
||||||
|
void update_string_views();
|
||||||
|
|
||||||
|
public:
|
||||||
|
log_msg_buffer() = default;
|
||||||
|
explicit log_msg_buffer(const log_msg &orig_msg);
|
||||||
|
log_msg_buffer(const log_msg_buffer &other);
|
||||||
|
log_msg_buffer(log_msg_buffer &&other) SPDLOG_NOEXCEPT;
|
||||||
|
log_msg_buffer &operator=(const log_msg_buffer &other);
|
||||||
|
log_msg_buffer &operator=(log_msg_buffer &&other) SPDLOG_NOEXCEPT;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace details
|
||||||
|
} // namespace spdlog
|
||||||
|
|
||||||
|
#ifdef SPDLOG_HEADER_ONLY
|
||||||
|
# include "log_msg_buffer-inl.h"
|
||||||
|
#endif
|
||||||
126
thirdparty/spdlog/details/mpmc_blocking_q.h
vendored
Normal file
126
thirdparty/spdlog/details/mpmc_blocking_q.h
vendored
Normal file
@@ -0,0 +1,126 @@
|
|||||||
|
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
|
||||||
|
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
// multi producer-multi consumer blocking queue.
|
||||||
|
// enqueue(..) - will block until room found to put the new message.
|
||||||
|
// enqueue_nowait(..) - will return immediately with false if no room left in
|
||||||
|
// the queue.
|
||||||
|
// dequeue_for(..) - will block until the queue is not empty or timeout have
|
||||||
|
// passed.
|
||||||
|
|
||||||
|
#include <spdlog/details/circular_q.h>
|
||||||
|
|
||||||
|
#include <condition_variable>
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
|
namespace spdlog {
|
||||||
|
namespace details {
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
class mpmc_blocking_queue
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using item_type = T;
|
||||||
|
explicit mpmc_blocking_queue(size_t max_items)
|
||||||
|
: q_(max_items)
|
||||||
|
{}
|
||||||
|
|
||||||
|
#ifndef __MINGW32__
|
||||||
|
// try to enqueue and block if no room left
|
||||||
|
void enqueue(T &&item)
|
||||||
|
{
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> lock(queue_mutex_);
|
||||||
|
pop_cv_.wait(lock, [this] { return !this->q_.full(); });
|
||||||
|
q_.push_back(std::move(item));
|
||||||
|
}
|
||||||
|
push_cv_.notify_one();
|
||||||
|
}
|
||||||
|
|
||||||
|
// enqueue immediately. overrun oldest message in the queue if no room left.
|
||||||
|
void enqueue_nowait(T &&item)
|
||||||
|
{
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> lock(queue_mutex_);
|
||||||
|
q_.push_back(std::move(item));
|
||||||
|
}
|
||||||
|
push_cv_.notify_one();
|
||||||
|
}
|
||||||
|
|
||||||
|
// try to dequeue item. if no item found. wait upto timeout and try again
|
||||||
|
// Return true, if succeeded dequeue item, false otherwise
|
||||||
|
bool dequeue_for(T &popped_item, std::chrono::milliseconds wait_duration)
|
||||||
|
{
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> lock(queue_mutex_);
|
||||||
|
if (!push_cv_.wait_for(lock, wait_duration, [this] { return !this->q_.empty(); }))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
popped_item = std::move(q_.front());
|
||||||
|
q_.pop_front();
|
||||||
|
}
|
||||||
|
pop_cv_.notify_one();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
// apparently mingw deadlocks if the mutex is released before cv.notify_one(),
|
||||||
|
// so release the mutex at the very end each function.
|
||||||
|
|
||||||
|
// try to enqueue and block if no room left
|
||||||
|
void enqueue(T &&item)
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> lock(queue_mutex_);
|
||||||
|
pop_cv_.wait(lock, [this] { return !this->q_.full(); });
|
||||||
|
q_.push_back(std::move(item));
|
||||||
|
push_cv_.notify_one();
|
||||||
|
}
|
||||||
|
|
||||||
|
// enqueue immediately. overrun oldest message in the queue if no room left.
|
||||||
|
void enqueue_nowait(T &&item)
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> lock(queue_mutex_);
|
||||||
|
q_.push_back(std::move(item));
|
||||||
|
push_cv_.notify_one();
|
||||||
|
}
|
||||||
|
|
||||||
|
// try to dequeue item. if no item found. wait upto timeout and try again
|
||||||
|
// Return true, if succeeded dequeue item, false otherwise
|
||||||
|
bool dequeue_for(T &popped_item, std::chrono::milliseconds wait_duration)
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> lock(queue_mutex_);
|
||||||
|
if (!push_cv_.wait_for(lock, wait_duration, [this] { return !this->q_.empty(); }))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
popped_item = std::move(q_.front());
|
||||||
|
q_.pop_front();
|
||||||
|
pop_cv_.notify_one();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
size_t overrun_counter()
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> lock(queue_mutex_);
|
||||||
|
return q_.overrun_counter();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t size()
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> lock(queue_mutex_);
|
||||||
|
return q_.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::mutex queue_mutex_;
|
||||||
|
std::condition_variable push_cv_;
|
||||||
|
std::condition_variable pop_cv_;
|
||||||
|
spdlog::details::circular_q<T> q_;
|
||||||
|
};
|
||||||
|
} // namespace details
|
||||||
|
} // namespace spdlog
|
||||||
49
thirdparty/spdlog/details/null_mutex.h
vendored
Normal file
49
thirdparty/spdlog/details/null_mutex.h
vendored
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
|
||||||
|
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
|
#include <utility>
|
||||||
|
// null, no cost dummy "mutex" and dummy "atomic" int
|
||||||
|
|
||||||
|
namespace spdlog {
|
||||||
|
namespace details {
|
||||||
|
struct null_mutex
|
||||||
|
{
|
||||||
|
void lock() const {}
|
||||||
|
void unlock() const {}
|
||||||
|
bool try_lock() const
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct null_atomic_int
|
||||||
|
{
|
||||||
|
int value;
|
||||||
|
null_atomic_int() = default;
|
||||||
|
|
||||||
|
explicit null_atomic_int(int new_value)
|
||||||
|
: value(new_value)
|
||||||
|
{}
|
||||||
|
|
||||||
|
int load(std::memory_order = std::memory_order_relaxed) const
|
||||||
|
{
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void store(int new_value, std::memory_order = std::memory_order_relaxed)
|
||||||
|
{
|
||||||
|
value = new_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
int exchange(int new_value, std::memory_order = std::memory_order_relaxed)
|
||||||
|
{
|
||||||
|
std::swap(new_value, value);
|
||||||
|
return new_value; // return value before the call
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace details
|
||||||
|
} // namespace spdlog
|
||||||
599
thirdparty/spdlog/details/os-inl.h
vendored
Normal file
599
thirdparty/spdlog/details/os-inl.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
118
thirdparty/spdlog/details/os.h
vendored
Normal file
118
thirdparty/spdlog/details/os.h
vendored
Normal file
@@ -0,0 +1,118 @@
|
|||||||
|
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
|
||||||
|
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <spdlog/common.h>
|
||||||
|
#include <ctime> // std::time_t
|
||||||
|
|
||||||
|
namespace spdlog {
|
||||||
|
namespace details {
|
||||||
|
namespace os {
|
||||||
|
|
||||||
|
SPDLOG_API spdlog::log_clock::time_point now() SPDLOG_NOEXCEPT;
|
||||||
|
|
||||||
|
SPDLOG_API std::tm localtime(const std::time_t &time_tt) SPDLOG_NOEXCEPT;
|
||||||
|
|
||||||
|
SPDLOG_API std::tm localtime() SPDLOG_NOEXCEPT;
|
||||||
|
|
||||||
|
SPDLOG_API std::tm gmtime(const std::time_t &time_tt) SPDLOG_NOEXCEPT;
|
||||||
|
|
||||||
|
SPDLOG_API std::tm gmtime() SPDLOG_NOEXCEPT;
|
||||||
|
|
||||||
|
// eol definition
|
||||||
|
#if !defined(SPDLOG_EOL)
|
||||||
|
# ifdef _WIN32
|
||||||
|
# define SPDLOG_EOL "\r\n"
|
||||||
|
# else
|
||||||
|
# define SPDLOG_EOL "\n"
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
SPDLOG_CONSTEXPR static const char *default_eol = SPDLOG_EOL;
|
||||||
|
|
||||||
|
// folder separator
|
||||||
|
#if !defined(SPDLOG_FOLDER_SEPS)
|
||||||
|
# ifdef _WIN32
|
||||||
|
# define SPDLOG_FOLDER_SEPS "\\/"
|
||||||
|
# else
|
||||||
|
# define SPDLOG_FOLDER_SEPS "/"
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
SPDLOG_CONSTEXPR static const char folder_seps[] = SPDLOG_FOLDER_SEPS;
|
||||||
|
SPDLOG_CONSTEXPR static const filename_t::value_type folder_seps_filename[] = SPDLOG_FILENAME_T(SPDLOG_FOLDER_SEPS);
|
||||||
|
|
||||||
|
// fopen_s on non windows for writing
|
||||||
|
SPDLOG_API bool fopen_s(FILE **fp, const filename_t &filename, const filename_t &mode);
|
||||||
|
|
||||||
|
// Remove filename. return 0 on success
|
||||||
|
SPDLOG_API int remove(const filename_t &filename) SPDLOG_NOEXCEPT;
|
||||||
|
|
||||||
|
// Remove file if exists. return 0 on success
|
||||||
|
// Note: Non atomic (might return failure to delete if concurrently deleted by other process/thread)
|
||||||
|
SPDLOG_API int remove_if_exists(const filename_t &filename) SPDLOG_NOEXCEPT;
|
||||||
|
|
||||||
|
SPDLOG_API int rename(const filename_t &filename1, const filename_t &filename2) SPDLOG_NOEXCEPT;
|
||||||
|
|
||||||
|
// Return if file exists.
|
||||||
|
SPDLOG_API bool path_exists(const filename_t &filename) SPDLOG_NOEXCEPT;
|
||||||
|
|
||||||
|
// Return file size according to open FILE* object
|
||||||
|
SPDLOG_API size_t filesize(FILE *f);
|
||||||
|
|
||||||
|
// Return utc offset in minutes or throw spdlog_ex on failure
|
||||||
|
SPDLOG_API int utc_minutes_offset(const std::tm &tm = details::os::localtime());
|
||||||
|
|
||||||
|
// Return current thread id as size_t
|
||||||
|
// It exists because the std::this_thread::get_id() is much slower(especially
|
||||||
|
// under VS 2013)
|
||||||
|
SPDLOG_API size_t _thread_id() SPDLOG_NOEXCEPT;
|
||||||
|
|
||||||
|
// Return current thread id as size_t (from thread local storage)
|
||||||
|
SPDLOG_API size_t thread_id() SPDLOG_NOEXCEPT;
|
||||||
|
|
||||||
|
// This is avoid msvc issue in sleep_for that happens if the clock changes.
|
||||||
|
// See https://github.com/gabime/spdlog/issues/609
|
||||||
|
SPDLOG_API void sleep_for_millis(unsigned int milliseconds) SPDLOG_NOEXCEPT;
|
||||||
|
|
||||||
|
SPDLOG_API std::string filename_to_str(const filename_t &filename);
|
||||||
|
|
||||||
|
SPDLOG_API int pid() SPDLOG_NOEXCEPT;
|
||||||
|
|
||||||
|
// Determine if the terminal supports colors
|
||||||
|
// Source: https://github.com/agauniyal/rang/
|
||||||
|
SPDLOG_API bool is_color_terminal() SPDLOG_NOEXCEPT;
|
||||||
|
|
||||||
|
// Determine if the terminal attached
|
||||||
|
// Source: https://github.com/agauniyal/rang/
|
||||||
|
SPDLOG_API bool in_terminal(FILE *file) SPDLOG_NOEXCEPT;
|
||||||
|
|
||||||
|
#if (defined(SPDLOG_WCHAR_TO_UTF8_SUPPORT) || defined(SPDLOG_WCHAR_FILENAMES)) && defined(_WIN32)
|
||||||
|
SPDLOG_API void wstr_to_utf8buf(wstring_view_t wstr, memory_buf_t &target);
|
||||||
|
|
||||||
|
SPDLOG_API void utf8_to_wstrbuf(string_view_t str, wmemory_buf_t &target);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Return directory name from given path or empty string
|
||||||
|
// "abc/file" => "abc"
|
||||||
|
// "abc/" => "abc"
|
||||||
|
// "abc" => ""
|
||||||
|
// "abc///" => "abc//"
|
||||||
|
SPDLOG_API filename_t dir_name(filename_t path);
|
||||||
|
|
||||||
|
// Create a dir from the given path.
|
||||||
|
// Return true if succeeded or if this dir already exists.
|
||||||
|
SPDLOG_API bool create_dir(filename_t path);
|
||||||
|
|
||||||
|
// non thread safe, cross platform getenv/getenv_s
|
||||||
|
// return empty string if field not found
|
||||||
|
SPDLOG_API std::string getenv(const char *field);
|
||||||
|
|
||||||
|
} // namespace os
|
||||||
|
} // namespace details
|
||||||
|
} // namespace spdlog
|
||||||
|
|
||||||
|
#ifdef SPDLOG_HEADER_ONLY
|
||||||
|
# include "os-inl.h"
|
||||||
|
#endif
|
||||||
49
thirdparty/spdlog/details/periodic_worker-inl.h
vendored
Normal file
49
thirdparty/spdlog/details/periodic_worker-inl.h
vendored
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
|
||||||
|
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifndef SPDLOG_HEADER_ONLY
|
||||||
|
# include <spdlog/details/periodic_worker.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace spdlog {
|
||||||
|
namespace details {
|
||||||
|
|
||||||
|
SPDLOG_INLINE periodic_worker::periodic_worker(const std::function<void()> &callback_fun, std::chrono::seconds interval)
|
||||||
|
{
|
||||||
|
active_ = (interval > std::chrono::seconds::zero());
|
||||||
|
if (!active_)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
worker_thread_ = std::thread([this, callback_fun, interval]() {
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> lock(this->mutex_);
|
||||||
|
if (this->cv_.wait_for(lock, interval, [this] { return !this->active_; }))
|
||||||
|
{
|
||||||
|
return; // active_ == false, so exit this thread
|
||||||
|
}
|
||||||
|
callback_fun();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// stop the worker thread and join it
|
||||||
|
SPDLOG_INLINE periodic_worker::~periodic_worker()
|
||||||
|
{
|
||||||
|
if (worker_thread_.joinable())
|
||||||
|
{
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(mutex_);
|
||||||
|
active_ = false;
|
||||||
|
}
|
||||||
|
cv_.notify_one();
|
||||||
|
worker_thread_.join();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace details
|
||||||
|
} // namespace spdlog
|
||||||
40
thirdparty/spdlog/details/periodic_worker.h
vendored
Normal file
40
thirdparty/spdlog/details/periodic_worker.h
vendored
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
|
||||||
|
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
// periodic worker thread - periodically executes the given callback function.
|
||||||
|
//
|
||||||
|
// RAII over the owned thread:
|
||||||
|
// creates the thread on construction.
|
||||||
|
// stops and joins the thread on destruction (if the thread is executing a callback, wait for it to finish first).
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
#include <condition_variable>
|
||||||
|
#include <functional>
|
||||||
|
#include <mutex>
|
||||||
|
#include <thread>
|
||||||
|
namespace spdlog {
|
||||||
|
namespace details {
|
||||||
|
|
||||||
|
class SPDLOG_API periodic_worker
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
periodic_worker(const std::function<void()> &callback_fun, std::chrono::seconds interval);
|
||||||
|
periodic_worker(const periodic_worker &) = delete;
|
||||||
|
periodic_worker &operator=(const periodic_worker &) = delete;
|
||||||
|
// stop the worker thread and join it
|
||||||
|
~periodic_worker();
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool active_;
|
||||||
|
std::thread worker_thread_;
|
||||||
|
std::mutex mutex_;
|
||||||
|
std::condition_variable cv_;
|
||||||
|
};
|
||||||
|
} // namespace details
|
||||||
|
} // namespace spdlog
|
||||||
|
|
||||||
|
#ifdef SPDLOG_HEADER_ONLY
|
||||||
|
# include "periodic_worker-inl.h"
|
||||||
|
#endif
|
||||||
313
thirdparty/spdlog/details/registry-inl.h
vendored
Normal file
313
thirdparty/spdlog/details/registry-inl.h
vendored
Normal file
@@ -0,0 +1,313 @@
|
|||||||
|
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
|
||||||
|
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifndef SPDLOG_HEADER_ONLY
|
||||||
|
# include <spdlog/details/registry.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <spdlog/common.h>
|
||||||
|
#include <spdlog/details/periodic_worker.h>
|
||||||
|
#include <spdlog/logger.h>
|
||||||
|
#include <spdlog/pattern_formatter.h>
|
||||||
|
|
||||||
|
#ifndef SPDLOG_DISABLE_DEFAULT_LOGGER
|
||||||
|
// support for the default stdout color logger
|
||||||
|
# ifdef _WIN32
|
||||||
|
# include <spdlog/sinks/wincolor_sink.h>
|
||||||
|
# else
|
||||||
|
# include <spdlog/sinks/ansicolor_sink.h>
|
||||||
|
# endif
|
||||||
|
#endif // SPDLOG_DISABLE_DEFAULT_LOGGER
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
#include <functional>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
|
namespace spdlog {
|
||||||
|
namespace details {
|
||||||
|
|
||||||
|
SPDLOG_INLINE registry::registry()
|
||||||
|
: formatter_(new pattern_formatter())
|
||||||
|
{
|
||||||
|
|
||||||
|
#ifndef SPDLOG_DISABLE_DEFAULT_LOGGER
|
||||||
|
// create default logger (ansicolor_stdout_sink_mt or wincolor_stdout_sink_mt in windows).
|
||||||
|
# ifdef _WIN32
|
||||||
|
auto color_sink = std::make_shared<sinks::wincolor_stdout_sink_mt>();
|
||||||
|
# else
|
||||||
|
auto color_sink = std::make_shared<sinks::ansicolor_stdout_sink_mt>();
|
||||||
|
# endif
|
||||||
|
|
||||||
|
const char *default_logger_name = "";
|
||||||
|
default_logger_ = std::make_shared<spdlog::logger>(default_logger_name, std::move(color_sink));
|
||||||
|
loggers_[default_logger_name] = default_logger_;
|
||||||
|
|
||||||
|
#endif // SPDLOG_DISABLE_DEFAULT_LOGGER
|
||||||
|
}
|
||||||
|
|
||||||
|
SPDLOG_INLINE registry::~registry() = default;
|
||||||
|
|
||||||
|
SPDLOG_INLINE void registry::register_logger(std::shared_ptr<logger> new_logger)
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(logger_map_mutex_);
|
||||||
|
register_logger_(std::move(new_logger));
|
||||||
|
}
|
||||||
|
|
||||||
|
SPDLOG_INLINE void registry::initialize_logger(std::shared_ptr<logger> new_logger)
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(logger_map_mutex_);
|
||||||
|
new_logger->set_formatter(formatter_->clone());
|
||||||
|
|
||||||
|
if (err_handler_)
|
||||||
|
{
|
||||||
|
new_logger->set_error_handler(err_handler_);
|
||||||
|
}
|
||||||
|
|
||||||
|
// set new level according to previously configured level or default level
|
||||||
|
auto it = log_levels_.find(new_logger->name());
|
||||||
|
auto new_level = it != log_levels_.end() ? it->second : global_log_level_;
|
||||||
|
new_logger->set_level(new_level);
|
||||||
|
|
||||||
|
new_logger->flush_on(flush_level_);
|
||||||
|
|
||||||
|
if (backtrace_n_messages_ > 0)
|
||||||
|
{
|
||||||
|
new_logger->enable_backtrace(backtrace_n_messages_);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (automatic_registration_)
|
||||||
|
{
|
||||||
|
register_logger_(std::move(new_logger));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SPDLOG_INLINE std::shared_ptr<logger> registry::get(const std::string &logger_name)
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(logger_map_mutex_);
|
||||||
|
auto found = loggers_.find(logger_name);
|
||||||
|
return found == loggers_.end() ? nullptr : found->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
SPDLOG_INLINE std::shared_ptr<logger> registry::default_logger()
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(logger_map_mutex_);
|
||||||
|
return default_logger_;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return raw ptr to the default logger.
|
||||||
|
// To be used directly by the spdlog default api (e.g. spdlog::info)
|
||||||
|
// This make the default API faster, but cannot be used concurrently with set_default_logger().
|
||||||
|
// e.g do not call set_default_logger() from one thread while calling spdlog::info() from another.
|
||||||
|
SPDLOG_INLINE logger *registry::get_default_raw()
|
||||||
|
{
|
||||||
|
return default_logger_.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
// set default logger.
|
||||||
|
// default logger is stored in default_logger_ (for faster retrieval) and in the loggers_ map.
|
||||||
|
SPDLOG_INLINE void registry::set_default_logger(std::shared_ptr<logger> new_default_logger)
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(logger_map_mutex_);
|
||||||
|
// remove previous default logger from the map
|
||||||
|
if (default_logger_ != nullptr)
|
||||||
|
{
|
||||||
|
loggers_.erase(default_logger_->name());
|
||||||
|
}
|
||||||
|
if (new_default_logger != nullptr)
|
||||||
|
{
|
||||||
|
loggers_[new_default_logger->name()] = new_default_logger;
|
||||||
|
}
|
||||||
|
default_logger_ = std::move(new_default_logger);
|
||||||
|
}
|
||||||
|
|
||||||
|
SPDLOG_INLINE void registry::set_tp(std::shared_ptr<thread_pool> tp)
|
||||||
|
{
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(tp_mutex_);
|
||||||
|
tp_ = std::move(tp);
|
||||||
|
}
|
||||||
|
|
||||||
|
SPDLOG_INLINE std::shared_ptr<thread_pool> registry::get_tp()
|
||||||
|
{
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(tp_mutex_);
|
||||||
|
return tp_;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set global formatter. Each sink in each logger will get a clone of this object
|
||||||
|
SPDLOG_INLINE void registry::set_formatter(std::unique_ptr<formatter> formatter)
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(logger_map_mutex_);
|
||||||
|
formatter_ = std::move(formatter);
|
||||||
|
for (auto &l : loggers_)
|
||||||
|
{
|
||||||
|
l.second->set_formatter(formatter_->clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SPDLOG_INLINE void registry::enable_backtrace(size_t n_messages)
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(logger_map_mutex_);
|
||||||
|
backtrace_n_messages_ = n_messages;
|
||||||
|
|
||||||
|
for (auto &l : loggers_)
|
||||||
|
{
|
||||||
|
l.second->enable_backtrace(n_messages);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SPDLOG_INLINE void registry::disable_backtrace()
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(logger_map_mutex_);
|
||||||
|
backtrace_n_messages_ = 0;
|
||||||
|
for (auto &l : loggers_)
|
||||||
|
{
|
||||||
|
l.second->disable_backtrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SPDLOG_INLINE void registry::set_level(level::level_enum log_level)
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(logger_map_mutex_);
|
||||||
|
for (auto &l : loggers_)
|
||||||
|
{
|
||||||
|
l.second->set_level(log_level);
|
||||||
|
}
|
||||||
|
global_log_level_ = log_level;
|
||||||
|
}
|
||||||
|
|
||||||
|
SPDLOG_INLINE void registry::flush_on(level::level_enum log_level)
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(logger_map_mutex_);
|
||||||
|
for (auto &l : loggers_)
|
||||||
|
{
|
||||||
|
l.second->flush_on(log_level);
|
||||||
|
}
|
||||||
|
flush_level_ = log_level;
|
||||||
|
}
|
||||||
|
|
||||||
|
SPDLOG_INLINE void registry::flush_every(std::chrono::seconds interval)
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(flusher_mutex_);
|
||||||
|
auto clbk = [this]() { this->flush_all(); };
|
||||||
|
periodic_flusher_ = details::make_unique<periodic_worker>(clbk, interval);
|
||||||
|
}
|
||||||
|
|
||||||
|
SPDLOG_INLINE void registry::set_error_handler(err_handler handler)
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(logger_map_mutex_);
|
||||||
|
for (auto &l : loggers_)
|
||||||
|
{
|
||||||
|
l.second->set_error_handler(handler);
|
||||||
|
}
|
||||||
|
err_handler_ = std::move(handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
SPDLOG_INLINE void registry::apply_all(const std::function<void(const std::shared_ptr<logger>)> &fun)
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(logger_map_mutex_);
|
||||||
|
for (auto &l : loggers_)
|
||||||
|
{
|
||||||
|
fun(l.second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SPDLOG_INLINE void registry::flush_all()
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(logger_map_mutex_);
|
||||||
|
for (auto &l : loggers_)
|
||||||
|
{
|
||||||
|
l.second->flush();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SPDLOG_INLINE void registry::drop(const std::string &logger_name)
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(logger_map_mutex_);
|
||||||
|
loggers_.erase(logger_name);
|
||||||
|
if (default_logger_ && default_logger_->name() == logger_name)
|
||||||
|
{
|
||||||
|
default_logger_.reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SPDLOG_INLINE void registry::drop_all()
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(logger_map_mutex_);
|
||||||
|
loggers_.clear();
|
||||||
|
default_logger_.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
// clean all resources and threads started by the registry
|
||||||
|
SPDLOG_INLINE void registry::shutdown()
|
||||||
|
{
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(flusher_mutex_);
|
||||||
|
periodic_flusher_.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
drop_all();
|
||||||
|
|
||||||
|
{
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(tp_mutex_);
|
||||||
|
tp_.reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SPDLOG_INLINE std::recursive_mutex ®istry::tp_mutex()
|
||||||
|
{
|
||||||
|
return tp_mutex_;
|
||||||
|
}
|
||||||
|
|
||||||
|
SPDLOG_INLINE void registry::set_automatic_registration(bool automatic_registration)
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(logger_map_mutex_);
|
||||||
|
automatic_registration_ = automatic_registration;
|
||||||
|
}
|
||||||
|
|
||||||
|
SPDLOG_INLINE void registry::set_levels(log_levels levels, level::level_enum *global_level)
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(logger_map_mutex_);
|
||||||
|
log_levels_ = std::move(levels);
|
||||||
|
auto global_level_requested = global_level != nullptr;
|
||||||
|
global_log_level_ = global_level_requested ? *global_level : global_log_level_;
|
||||||
|
|
||||||
|
for (auto &logger : loggers_)
|
||||||
|
{
|
||||||
|
auto logger_entry = log_levels_.find(logger.first);
|
||||||
|
if (logger_entry != log_levels_.end())
|
||||||
|
{
|
||||||
|
logger.second->set_level(logger_entry->second);
|
||||||
|
}
|
||||||
|
else if (global_level_requested)
|
||||||
|
{
|
||||||
|
logger.second->set_level(*global_level);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SPDLOG_INLINE registry ®istry::instance()
|
||||||
|
{
|
||||||
|
static registry s_instance;
|
||||||
|
return s_instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
SPDLOG_INLINE void registry::throw_if_exists_(const std::string &logger_name)
|
||||||
|
{
|
||||||
|
if (loggers_.find(logger_name) != loggers_.end())
|
||||||
|
{
|
||||||
|
throw_spdlog_ex("logger with name '" + logger_name + "' already exists");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SPDLOG_INLINE void registry::register_logger_(std::shared_ptr<logger> new_logger)
|
||||||
|
{
|
||||||
|
auto logger_name = new_logger->name();
|
||||||
|
throw_if_exists_(logger_name);
|
||||||
|
loggers_[logger_name] = std::move(new_logger);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace details
|
||||||
|
} // namespace spdlog
|
||||||
115
thirdparty/spdlog/details/registry.h
vendored
Normal file
115
thirdparty/spdlog/details/registry.h
vendored
Normal file
@@ -0,0 +1,115 @@
|
|||||||
|
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
|
||||||
|
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
// Loggers registry of unique name->logger pointer
|
||||||
|
// An attempt to create a logger with an already existing name will result with spdlog_ex exception.
|
||||||
|
// If user requests a non existing logger, nullptr will be returned
|
||||||
|
// This class is thread safe
|
||||||
|
|
||||||
|
#include <spdlog/common.h>
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
#include <functional>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
|
namespace spdlog {
|
||||||
|
class logger;
|
||||||
|
|
||||||
|
namespace details {
|
||||||
|
class thread_pool;
|
||||||
|
class periodic_worker;
|
||||||
|
|
||||||
|
class SPDLOG_API registry
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using log_levels = std::unordered_map<std::string, level::level_enum>;
|
||||||
|
registry(const registry &) = delete;
|
||||||
|
registry &operator=(const registry &) = delete;
|
||||||
|
|
||||||
|
void register_logger(std::shared_ptr<logger> new_logger);
|
||||||
|
void initialize_logger(std::shared_ptr<logger> new_logger);
|
||||||
|
std::shared_ptr<logger> get(const std::string &logger_name);
|
||||||
|
std::shared_ptr<logger> default_logger();
|
||||||
|
|
||||||
|
// Return raw ptr to the default logger.
|
||||||
|
// To be used directly by the spdlog default api (e.g. spdlog::info)
|
||||||
|
// This make the default API faster, but cannot be used concurrently with set_default_logger().
|
||||||
|
// e.g do not call set_default_logger() from one thread while calling spdlog::info() from another.
|
||||||
|
logger *get_default_raw();
|
||||||
|
|
||||||
|
// set default logger.
|
||||||
|
// default logger is stored in default_logger_ (for faster retrieval) and in the loggers_ map.
|
||||||
|
void set_default_logger(std::shared_ptr<logger> new_default_logger);
|
||||||
|
|
||||||
|
void set_tp(std::shared_ptr<thread_pool> tp);
|
||||||
|
|
||||||
|
std::shared_ptr<thread_pool> get_tp();
|
||||||
|
|
||||||
|
// Set global formatter. Each sink in each logger will get a clone of this object
|
||||||
|
void set_formatter(std::unique_ptr<formatter> formatter);
|
||||||
|
|
||||||
|
void enable_backtrace(size_t n_messages);
|
||||||
|
|
||||||
|
void disable_backtrace();
|
||||||
|
|
||||||
|
void set_level(level::level_enum log_level);
|
||||||
|
|
||||||
|
void flush_on(level::level_enum log_level);
|
||||||
|
|
||||||
|
void flush_every(std::chrono::seconds interval);
|
||||||
|
|
||||||
|
void set_error_handler(err_handler handler);
|
||||||
|
|
||||||
|
void apply_all(const std::function<void(const std::shared_ptr<logger>)> &fun);
|
||||||
|
|
||||||
|
void flush_all();
|
||||||
|
|
||||||
|
void drop(const std::string &logger_name);
|
||||||
|
|
||||||
|
void drop_all();
|
||||||
|
|
||||||
|
// clean all resources and threads started by the registry
|
||||||
|
void shutdown();
|
||||||
|
|
||||||
|
std::recursive_mutex &tp_mutex();
|
||||||
|
|
||||||
|
void set_automatic_registration(bool automatic_registration);
|
||||||
|
|
||||||
|
// set levels for all existing/future loggers. global_level can be null if should not set.
|
||||||
|
void set_levels(log_levels levels, level::level_enum *global_level);
|
||||||
|
|
||||||
|
static registry &instance();
|
||||||
|
|
||||||
|
private:
|
||||||
|
registry();
|
||||||
|
~registry();
|
||||||
|
|
||||||
|
void throw_if_exists_(const std::string &logger_name);
|
||||||
|
void register_logger_(std::shared_ptr<logger> new_logger);
|
||||||
|
bool set_level_from_cfg_(logger *logger);
|
||||||
|
std::mutex logger_map_mutex_, flusher_mutex_;
|
||||||
|
std::recursive_mutex tp_mutex_;
|
||||||
|
std::unordered_map<std::string, std::shared_ptr<logger>> loggers_;
|
||||||
|
log_levels log_levels_;
|
||||||
|
std::unique_ptr<formatter> formatter_;
|
||||||
|
spdlog::level::level_enum global_log_level_ = level::info;
|
||||||
|
level::level_enum flush_level_ = level::off;
|
||||||
|
err_handler err_handler_;
|
||||||
|
std::shared_ptr<thread_pool> tp_;
|
||||||
|
std::unique_ptr<periodic_worker> periodic_flusher_;
|
||||||
|
std::shared_ptr<logger> default_logger_;
|
||||||
|
bool automatic_registration_ = true;
|
||||||
|
size_t backtrace_n_messages_ = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace details
|
||||||
|
} // namespace spdlog
|
||||||
|
|
||||||
|
#ifdef SPDLOG_HEADER_ONLY
|
||||||
|
# include "registry-inl.h"
|
||||||
|
#endif
|
||||||
24
thirdparty/spdlog/details/synchronous_factory.h
vendored
Normal file
24
thirdparty/spdlog/details/synchronous_factory.h
vendored
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
|
||||||
|
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "registry.h"
|
||||||
|
|
||||||
|
namespace spdlog {
|
||||||
|
|
||||||
|
// Default logger factory- creates synchronous loggers
|
||||||
|
class logger;
|
||||||
|
|
||||||
|
struct synchronous_factory
|
||||||
|
{
|
||||||
|
template<typename Sink, typename... SinkArgs>
|
||||||
|
static std::shared_ptr<spdlog::logger> create(std::string logger_name, SinkArgs &&...args)
|
||||||
|
{
|
||||||
|
auto sink = std::make_shared<Sink>(std::forward<SinkArgs>(args)...);
|
||||||
|
auto new_logger = std::make_shared<spdlog::logger>(std::move(logger_name), std::move(sink));
|
||||||
|
details::registry::instance().initialize_logger(new_logger);
|
||||||
|
return new_logger;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} // namespace spdlog
|
||||||
175
thirdparty/spdlog/details/tcp_client-windows.h
vendored
Normal file
175
thirdparty/spdlog/details/tcp_client-windows.h
vendored
Normal file
@@ -0,0 +1,175 @@
|
|||||||
|
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
|
||||||
|
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
// tcp client helper
|
||||||
|
#include <spdlog/common.h>
|
||||||
|
#include <spdlog/details/os.h>
|
||||||
|
|
||||||
|
#include <winsock2.h>
|
||||||
|
#include <windows.h>
|
||||||
|
#include <ws2tcpip.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#pragma comment(lib, "Ws2_32.lib")
|
||||||
|
#pragma comment(lib, "Mswsock.lib")
|
||||||
|
#pragma comment(lib, "AdvApi32.lib")
|
||||||
|
|
||||||
|
namespace spdlog {
|
||||||
|
namespace details {
|
||||||
|
class tcp_client
|
||||||
|
{
|
||||||
|
SOCKET socket_ = INVALID_SOCKET;
|
||||||
|
|
||||||
|
static bool winsock_initialized_()
|
||||||
|
{
|
||||||
|
SOCKET s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||||
|
if (s == INVALID_SOCKET)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
closesocket(s);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void init_winsock_()
|
||||||
|
{
|
||||||
|
WSADATA wsaData;
|
||||||
|
auto rv = WSAStartup(MAKEWORD(2, 2), &wsaData);
|
||||||
|
if (rv != 0)
|
||||||
|
{
|
||||||
|
throw_winsock_error_("WSAStartup failed", ::WSAGetLastError());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void throw_winsock_error_(const std::string &msg, int last_error)
|
||||||
|
{
|
||||||
|
char buf[512];
|
||||||
|
::FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, last_error,
|
||||||
|
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), buf, (sizeof(buf) / sizeof(char)), NULL);
|
||||||
|
|
||||||
|
throw_spdlog_ex(fmt::format("tcp_sink - {}: {}", msg, buf));
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
bool is_connected() const
|
||||||
|
{
|
||||||
|
return socket_ != INVALID_SOCKET;
|
||||||
|
}
|
||||||
|
|
||||||
|
void close()
|
||||||
|
{
|
||||||
|
::closesocket(socket_);
|
||||||
|
socket_ = INVALID_SOCKET;
|
||||||
|
WSACleanup();
|
||||||
|
}
|
||||||
|
|
||||||
|
SOCKET fd() const
|
||||||
|
{
|
||||||
|
return socket_;
|
||||||
|
}
|
||||||
|
|
||||||
|
~tcp_client()
|
||||||
|
{
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
|
||||||
|
// try to connect or throw on failure
|
||||||
|
void connect(const std::string &host, int port)
|
||||||
|
{
|
||||||
|
// initialize winsock if needed
|
||||||
|
if (!winsock_initialized_())
|
||||||
|
{
|
||||||
|
init_winsock_();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_connected())
|
||||||
|
{
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
struct addrinfo hints
|
||||||
|
{};
|
||||||
|
ZeroMemory(&hints, sizeof(hints));
|
||||||
|
|
||||||
|
hints.ai_family = AF_INET; // IPv4
|
||||||
|
hints.ai_socktype = SOCK_STREAM; // TCP
|
||||||
|
hints.ai_flags = AI_NUMERICSERV; // port passed as as numeric value
|
||||||
|
hints.ai_protocol = 0;
|
||||||
|
|
||||||
|
auto port_str = std::to_string(port);
|
||||||
|
struct addrinfo *addrinfo_result;
|
||||||
|
auto rv = ::getaddrinfo(host.c_str(), port_str.c_str(), &hints, &addrinfo_result);
|
||||||
|
int last_error = 0;
|
||||||
|
if (rv != 0)
|
||||||
|
{
|
||||||
|
last_error = ::WSAGetLastError();
|
||||||
|
WSACleanup();
|
||||||
|
throw_winsock_error_("getaddrinfo failed", last_error);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try each address until we successfully connect(2).
|
||||||
|
|
||||||
|
for (auto *rp = addrinfo_result; rp != nullptr; rp = rp->ai_next)
|
||||||
|
{
|
||||||
|
socket_ = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
|
||||||
|
if (socket_ == INVALID_SOCKET)
|
||||||
|
{
|
||||||
|
last_error = ::WSAGetLastError();
|
||||||
|
WSACleanup();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (::connect(socket_, rp->ai_addr, (int)rp->ai_addrlen) == 0)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
last_error = ::WSAGetLastError();
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
::freeaddrinfo(addrinfo_result);
|
||||||
|
if (socket_ == INVALID_SOCKET)
|
||||||
|
{
|
||||||
|
WSACleanup();
|
||||||
|
throw_winsock_error_("connect failed", last_error);
|
||||||
|
}
|
||||||
|
|
||||||
|
// set TCP_NODELAY
|
||||||
|
int enable_flag = 1;
|
||||||
|
::setsockopt(socket_, IPPROTO_TCP, TCP_NODELAY, reinterpret_cast<char *>(&enable_flag), sizeof(enable_flag));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send exactly n_bytes of the given data.
|
||||||
|
// On error close the connection and throw.
|
||||||
|
void send(const char *data, size_t n_bytes)
|
||||||
|
{
|
||||||
|
size_t bytes_sent = 0;
|
||||||
|
while (bytes_sent < n_bytes)
|
||||||
|
{
|
||||||
|
const int send_flags = 0;
|
||||||
|
auto write_result = ::send(socket_, data + bytes_sent, (int)(n_bytes - bytes_sent), send_flags);
|
||||||
|
if (write_result == SOCKET_ERROR)
|
||||||
|
{
|
||||||
|
int last_error = ::WSAGetLastError();
|
||||||
|
close();
|
||||||
|
throw_winsock_error_("send failed", last_error);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (write_result == 0) // (probably should not happen but in any case..)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
bytes_sent += static_cast<size_t>(write_result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} // namespace details
|
||||||
|
} // namespace spdlog
|
||||||
146
thirdparty/spdlog/details/tcp_client.h
vendored
Normal file
146
thirdparty/spdlog/details/tcp_client.h
vendored
Normal file
@@ -0,0 +1,146 @@
|
|||||||
|
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
|
||||||
|
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
# error include tcp_client-windows.h instead
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// tcp client helper
|
||||||
|
#include <spdlog/common.h>
|
||||||
|
#include <spdlog/details/os.h>
|
||||||
|
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <netdb.h>
|
||||||
|
#include <netinet/tcp.h>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace spdlog {
|
||||||
|
namespace details {
|
||||||
|
class tcp_client
|
||||||
|
{
|
||||||
|
int socket_ = -1;
|
||||||
|
|
||||||
|
public:
|
||||||
|
bool is_connected() const
|
||||||
|
{
|
||||||
|
return socket_ != -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void close()
|
||||||
|
{
|
||||||
|
if (is_connected())
|
||||||
|
{
|
||||||
|
::close(socket_);
|
||||||
|
socket_ = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int fd() const
|
||||||
|
{
|
||||||
|
return socket_;
|
||||||
|
}
|
||||||
|
|
||||||
|
~tcp_client()
|
||||||
|
{
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
|
||||||
|
// try to connect or throw on failure
|
||||||
|
void connect(const std::string &host, int port)
|
||||||
|
{
|
||||||
|
close();
|
||||||
|
struct addrinfo hints
|
||||||
|
{};
|
||||||
|
memset(&hints, 0, sizeof(struct addrinfo));
|
||||||
|
hints.ai_family = AF_INET; // IPv4
|
||||||
|
hints.ai_socktype = SOCK_STREAM; // TCP
|
||||||
|
hints.ai_flags = AI_NUMERICSERV; // port passed as as numeric value
|
||||||
|
hints.ai_protocol = 0;
|
||||||
|
|
||||||
|
auto port_str = std::to_string(port);
|
||||||
|
struct addrinfo *addrinfo_result;
|
||||||
|
auto rv = ::getaddrinfo(host.c_str(), port_str.c_str(), &hints, &addrinfo_result);
|
||||||
|
if (rv != 0)
|
||||||
|
{
|
||||||
|
auto msg = fmt::format("::getaddrinfo failed: {}", gai_strerror(rv));
|
||||||
|
throw_spdlog_ex(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try each address until we successfully connect(2).
|
||||||
|
int last_errno = 0;
|
||||||
|
for (auto *rp = addrinfo_result; rp != nullptr; rp = rp->ai_next)
|
||||||
|
{
|
||||||
|
#if defined(SOCK_CLOEXEC)
|
||||||
|
const int flags = SOCK_CLOEXEC;
|
||||||
|
#else
|
||||||
|
const int flags = 0;
|
||||||
|
#endif
|
||||||
|
socket_ = ::socket(rp->ai_family, rp->ai_socktype | flags, rp->ai_protocol);
|
||||||
|
if (socket_ == -1)
|
||||||
|
{
|
||||||
|
last_errno = errno;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
rv = ::connect(socket_, rp->ai_addr, rp->ai_addrlen);
|
||||||
|
if (rv == 0)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
last_errno = errno;
|
||||||
|
::close(socket_);
|
||||||
|
socket_ = -1;
|
||||||
|
}
|
||||||
|
::freeaddrinfo(addrinfo_result);
|
||||||
|
if (socket_ == -1)
|
||||||
|
{
|
||||||
|
throw_spdlog_ex("::connect failed", last_errno);
|
||||||
|
}
|
||||||
|
|
||||||
|
// set TCP_NODELAY
|
||||||
|
int enable_flag = 1;
|
||||||
|
::setsockopt(socket_, IPPROTO_TCP, TCP_NODELAY, reinterpret_cast<char *>(&enable_flag), sizeof(enable_flag));
|
||||||
|
|
||||||
|
// prevent sigpipe on systems where MSG_NOSIGNAL is not available
|
||||||
|
#if defined(SO_NOSIGPIPE) && !defined(MSG_NOSIGNAL)
|
||||||
|
::setsockopt(socket_, SOL_SOCKET, SO_NOSIGPIPE, reinterpret_cast<char *>(&enable_flag), sizeof(enable_flag));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(SO_NOSIGPIPE) && !defined(MSG_NOSIGNAL)
|
||||||
|
# error "tcp_sink would raise SIGPIPE since niether SO_NOSIGPIPE nor MSG_NOSIGNAL are available"
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send exactly n_bytes of the given data.
|
||||||
|
// On error close the connection and throw.
|
||||||
|
void send(const char *data, size_t n_bytes)
|
||||||
|
{
|
||||||
|
size_t bytes_sent = 0;
|
||||||
|
while (bytes_sent < n_bytes)
|
||||||
|
{
|
||||||
|
#if defined(MSG_NOSIGNAL)
|
||||||
|
const int send_flags = MSG_NOSIGNAL;
|
||||||
|
#else
|
||||||
|
const int send_flags = 0;
|
||||||
|
#endif
|
||||||
|
auto write_result = ::send(socket_, data + bytes_sent, n_bytes - bytes_sent, send_flags);
|
||||||
|
if (write_result < 0)
|
||||||
|
{
|
||||||
|
close();
|
||||||
|
throw_spdlog_ex("write(2) failed", errno);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (write_result == 0) // (probably should not happen but in any case..)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
bytes_sent += static_cast<size_t>(write_result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} // namespace details
|
||||||
|
} // namespace spdlog
|
||||||
129
thirdparty/spdlog/details/thread_pool-inl.h
vendored
Normal file
129
thirdparty/spdlog/details/thread_pool-inl.h
vendored
Normal file
@@ -0,0 +1,129 @@
|
|||||||
|
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
|
||||||
|
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifndef SPDLOG_HEADER_ONLY
|
||||||
|
# include <spdlog/details/thread_pool.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <spdlog/common.h>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
namespace spdlog {
|
||||||
|
namespace details {
|
||||||
|
|
||||||
|
SPDLOG_INLINE thread_pool::thread_pool(size_t q_max_items, size_t threads_n, std::function<void()> on_thread_start)
|
||||||
|
: q_(q_max_items)
|
||||||
|
{
|
||||||
|
if (threads_n == 0 || threads_n > 1000)
|
||||||
|
{
|
||||||
|
throw_spdlog_ex("spdlog::thread_pool(): invalid threads_n param (valid "
|
||||||
|
"range is 1-1000)");
|
||||||
|
}
|
||||||
|
for (size_t i = 0; i < threads_n; i++)
|
||||||
|
{
|
||||||
|
threads_.emplace_back([this, on_thread_start] {
|
||||||
|
on_thread_start();
|
||||||
|
this->thread_pool::worker_loop_();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SPDLOG_INLINE thread_pool::thread_pool(size_t q_max_items, size_t threads_n)
|
||||||
|
: thread_pool(q_max_items, threads_n, [] {})
|
||||||
|
{}
|
||||||
|
|
||||||
|
// message all threads to terminate gracefully join them
|
||||||
|
SPDLOG_INLINE thread_pool::~thread_pool()
|
||||||
|
{
|
||||||
|
SPDLOG_TRY
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < threads_.size(); i++)
|
||||||
|
{
|
||||||
|
post_async_msg_(async_msg(async_msg_type::terminate), async_overflow_policy::block);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto &t : threads_)
|
||||||
|
{
|
||||||
|
t.join();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SPDLOG_CATCH_STD
|
||||||
|
}
|
||||||
|
|
||||||
|
void SPDLOG_INLINE thread_pool::post_log(async_logger_ptr &&worker_ptr, const details::log_msg &msg, async_overflow_policy overflow_policy)
|
||||||
|
{
|
||||||
|
async_msg async_m(std::move(worker_ptr), async_msg_type::log, msg);
|
||||||
|
post_async_msg_(std::move(async_m), overflow_policy);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SPDLOG_INLINE thread_pool::post_flush(async_logger_ptr &&worker_ptr, async_overflow_policy overflow_policy)
|
||||||
|
{
|
||||||
|
post_async_msg_(async_msg(std::move(worker_ptr), async_msg_type::flush), overflow_policy);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t SPDLOG_INLINE thread_pool::overrun_counter()
|
||||||
|
{
|
||||||
|
return q_.overrun_counter();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t SPDLOG_INLINE thread_pool::queue_size()
|
||||||
|
{
|
||||||
|
return q_.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SPDLOG_INLINE thread_pool::post_async_msg_(async_msg &&new_msg, async_overflow_policy overflow_policy)
|
||||||
|
{
|
||||||
|
if (overflow_policy == async_overflow_policy::block)
|
||||||
|
{
|
||||||
|
q_.enqueue(std::move(new_msg));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
q_.enqueue_nowait(std::move(new_msg));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SPDLOG_INLINE thread_pool::worker_loop_()
|
||||||
|
{
|
||||||
|
while (process_next_msg_()) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// process next message in the queue
|
||||||
|
// return true if this thread should still be active (while no terminate msg
|
||||||
|
// was received)
|
||||||
|
bool SPDLOG_INLINE thread_pool::process_next_msg_()
|
||||||
|
{
|
||||||
|
async_msg incoming_async_msg;
|
||||||
|
bool dequeued = q_.dequeue_for(incoming_async_msg, std::chrono::seconds(10));
|
||||||
|
if (!dequeued)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (incoming_async_msg.msg_type)
|
||||||
|
{
|
||||||
|
case async_msg_type::log: {
|
||||||
|
incoming_async_msg.worker_ptr->backend_sink_it_(incoming_async_msg);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
case async_msg_type::flush: {
|
||||||
|
incoming_async_msg.worker_ptr->backend_flush_();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
case async_msg_type::terminate: {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
default: {
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace details
|
||||||
|
} // namespace spdlog
|
||||||
120
thirdparty/spdlog/details/thread_pool.h
vendored
Normal file
120
thirdparty/spdlog/details/thread_pool.h
vendored
Normal file
@@ -0,0 +1,120 @@
|
|||||||
|
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
|
||||||
|
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <spdlog/details/log_msg_buffer.h>
|
||||||
|
#include <spdlog/details/mpmc_blocking_q.h>
|
||||||
|
#include <spdlog/details/os.h>
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
#include <memory>
|
||||||
|
#include <thread>
|
||||||
|
#include <vector>
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
namespace spdlog {
|
||||||
|
class async_logger;
|
||||||
|
|
||||||
|
namespace details {
|
||||||
|
|
||||||
|
using async_logger_ptr = std::shared_ptr<spdlog::async_logger>;
|
||||||
|
|
||||||
|
enum class async_msg_type
|
||||||
|
{
|
||||||
|
log,
|
||||||
|
flush,
|
||||||
|
terminate
|
||||||
|
};
|
||||||
|
|
||||||
|
// Async msg to move to/from the queue
|
||||||
|
// Movable only. should never be copied
|
||||||
|
struct async_msg : log_msg_buffer
|
||||||
|
{
|
||||||
|
async_msg_type msg_type{async_msg_type::log};
|
||||||
|
async_logger_ptr worker_ptr;
|
||||||
|
|
||||||
|
async_msg() = default;
|
||||||
|
~async_msg() = default;
|
||||||
|
|
||||||
|
// should only be moved in or out of the queue..
|
||||||
|
async_msg(const async_msg &) = delete;
|
||||||
|
|
||||||
|
// support for vs2013 move
|
||||||
|
#if defined(_MSC_VER) && _MSC_VER <= 1800
|
||||||
|
async_msg(async_msg &&other)
|
||||||
|
: log_msg_buffer(std::move(other))
|
||||||
|
, msg_type(other.msg_type)
|
||||||
|
, worker_ptr(std::move(other.worker_ptr))
|
||||||
|
{}
|
||||||
|
|
||||||
|
async_msg &operator=(async_msg &&other)
|
||||||
|
{
|
||||||
|
*static_cast<log_msg_buffer *>(this) = std::move(other);
|
||||||
|
msg_type = other.msg_type;
|
||||||
|
worker_ptr = std::move(other.worker_ptr);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
#else // (_MSC_VER) && _MSC_VER <= 1800
|
||||||
|
async_msg(async_msg &&) = default;
|
||||||
|
async_msg &operator=(async_msg &&) = default;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// construct from log_msg with given type
|
||||||
|
async_msg(async_logger_ptr &&worker, async_msg_type the_type, const details::log_msg &m)
|
||||||
|
: log_msg_buffer{m}
|
||||||
|
, msg_type{the_type}
|
||||||
|
, worker_ptr{std::move(worker)}
|
||||||
|
{}
|
||||||
|
|
||||||
|
async_msg(async_logger_ptr &&worker, async_msg_type the_type)
|
||||||
|
: log_msg_buffer{}
|
||||||
|
, msg_type{the_type}
|
||||||
|
, worker_ptr{std::move(worker)}
|
||||||
|
{}
|
||||||
|
|
||||||
|
explicit async_msg(async_msg_type the_type)
|
||||||
|
: async_msg{nullptr, the_type}
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
class SPDLOG_API thread_pool
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using item_type = async_msg;
|
||||||
|
using q_type = details::mpmc_blocking_queue<item_type>;
|
||||||
|
|
||||||
|
thread_pool(size_t q_max_items, size_t threads_n, std::function<void()> on_thread_start);
|
||||||
|
thread_pool(size_t q_max_items, size_t threads_n);
|
||||||
|
|
||||||
|
// message all threads to terminate gracefully join them
|
||||||
|
~thread_pool();
|
||||||
|
|
||||||
|
thread_pool(const thread_pool &) = delete;
|
||||||
|
thread_pool &operator=(thread_pool &&) = delete;
|
||||||
|
|
||||||
|
void post_log(async_logger_ptr &&worker_ptr, const details::log_msg &msg, async_overflow_policy overflow_policy);
|
||||||
|
void post_flush(async_logger_ptr &&worker_ptr, async_overflow_policy overflow_policy);
|
||||||
|
size_t overrun_counter();
|
||||||
|
size_t queue_size();
|
||||||
|
|
||||||
|
private:
|
||||||
|
q_type q_;
|
||||||
|
|
||||||
|
std::vector<std::thread> threads_;
|
||||||
|
|
||||||
|
void post_async_msg_(async_msg &&new_msg, async_overflow_policy overflow_policy);
|
||||||
|
void worker_loop_();
|
||||||
|
|
||||||
|
// process next message in the queue
|
||||||
|
// return true if this thread should still be active (while no terminate msg
|
||||||
|
// was received)
|
||||||
|
bool process_next_msg_();
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace details
|
||||||
|
} // namespace spdlog
|
||||||
|
|
||||||
|
#ifdef SPDLOG_HEADER_ONLY
|
||||||
|
# include "thread_pool-inl.h"
|
||||||
|
#endif
|
||||||
11
thirdparty/spdlog/details/windows_include.h
vendored
Normal file
11
thirdparty/spdlog/details/windows_include.h
vendored
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifndef NOMINMAX
|
||||||
|
# define NOMINMAX // prevent windows redefining min/max
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef WIN32_LEAN_AND_MEAN
|
||||||
|
# define WIN32_LEAN_AND_MEAN
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
217
thirdparty/spdlog/fmt/bin_to_hex.h
vendored
Normal file
217
thirdparty/spdlog/fmt/bin_to_hex.h
vendored
Normal file
@@ -0,0 +1,217 @@
|
|||||||
|
//
|
||||||
|
// Copyright(c) 2015 Gabi Melman.
|
||||||
|
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||||
|
//
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cctype>
|
||||||
|
#include <spdlog/common.h>
|
||||||
|
|
||||||
|
//
|
||||||
|
// Support for logging binary data as hex
|
||||||
|
// format flags, any combination of the followng:
|
||||||
|
// {:X} - print in uppercase.
|
||||||
|
// {:s} - don't separate each byte with space.
|
||||||
|
// {:p} - don't print the position on each line start.
|
||||||
|
// {:n} - don't split the output to lines.
|
||||||
|
// {:a} - show ASCII if :n is not set
|
||||||
|
|
||||||
|
//
|
||||||
|
// Examples:
|
||||||
|
//
|
||||||
|
// std::vector<char> v(200, 0x0b);
|
||||||
|
// logger->info("Some buffer {}", spdlog::to_hex(v));
|
||||||
|
// char buf[128];
|
||||||
|
// logger->info("Some buffer {:X}", spdlog::to_hex(std::begin(buf), std::end(buf)));
|
||||||
|
// logger->info("Some buffer {:X}", spdlog::to_hex(std::begin(buf), std::end(buf), 16));
|
||||||
|
|
||||||
|
namespace spdlog {
|
||||||
|
namespace details {
|
||||||
|
|
||||||
|
template<typename It>
|
||||||
|
class dump_info
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
dump_info(It range_begin, It range_end, size_t size_per_line)
|
||||||
|
: begin_(range_begin)
|
||||||
|
, end_(range_end)
|
||||||
|
, size_per_line_(size_per_line)
|
||||||
|
{}
|
||||||
|
|
||||||
|
It begin() const
|
||||||
|
{
|
||||||
|
return begin_;
|
||||||
|
}
|
||||||
|
It end() const
|
||||||
|
{
|
||||||
|
return end_;
|
||||||
|
}
|
||||||
|
size_t size_per_line() const
|
||||||
|
{
|
||||||
|
return size_per_line_;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
It begin_, end_;
|
||||||
|
size_t size_per_line_;
|
||||||
|
};
|
||||||
|
} // namespace details
|
||||||
|
|
||||||
|
// create a dump_info that wraps the given container
|
||||||
|
template<typename Container>
|
||||||
|
inline details::dump_info<typename Container::const_iterator> to_hex(const Container &container, size_t size_per_line = 32)
|
||||||
|
{
|
||||||
|
static_assert(sizeof(typename Container::value_type) == 1, "sizeof(Container::value_type) != 1");
|
||||||
|
using Iter = typename Container::const_iterator;
|
||||||
|
return details::dump_info<Iter>(std::begin(container), std::end(container), size_per_line);
|
||||||
|
}
|
||||||
|
|
||||||
|
// create dump_info from ranges
|
||||||
|
template<typename It>
|
||||||
|
inline details::dump_info<It> to_hex(const It range_begin, const It range_end, size_t size_per_line = 32)
|
||||||
|
{
|
||||||
|
return details::dump_info<It>(range_begin, range_end, size_per_line);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace spdlog
|
||||||
|
|
||||||
|
namespace fmt {
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct formatter<spdlog::details::dump_info<T>>
|
||||||
|
{
|
||||||
|
const char delimiter = ' ';
|
||||||
|
bool put_newlines = true;
|
||||||
|
bool put_delimiters = true;
|
||||||
|
bool use_uppercase = false;
|
||||||
|
bool put_positions = true; // position on start of each line
|
||||||
|
bool show_ascii = false;
|
||||||
|
|
||||||
|
// parse the format string flags
|
||||||
|
template<typename ParseContext>
|
||||||
|
FMT_CONSTEXPR auto parse(ParseContext &ctx) -> decltype(ctx.begin())
|
||||||
|
{
|
||||||
|
auto it = ctx.begin();
|
||||||
|
while (it != ctx.end() && *it != '}')
|
||||||
|
{
|
||||||
|
switch (*it)
|
||||||
|
{
|
||||||
|
case 'X':
|
||||||
|
use_uppercase = true;
|
||||||
|
break;
|
||||||
|
case 's':
|
||||||
|
put_delimiters = false;
|
||||||
|
break;
|
||||||
|
case 'p':
|
||||||
|
put_positions = false;
|
||||||
|
break;
|
||||||
|
case 'n':
|
||||||
|
put_newlines = false;
|
||||||
|
show_ascii = false;
|
||||||
|
break;
|
||||||
|
case 'a':
|
||||||
|
if (put_newlines)
|
||||||
|
{
|
||||||
|
show_ascii = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
return it;
|
||||||
|
}
|
||||||
|
|
||||||
|
// format the given bytes range as hex
|
||||||
|
template<typename FormatContext, typename Container>
|
||||||
|
auto format(const spdlog::details::dump_info<Container> &the_range, FormatContext &ctx) -> decltype(ctx.out())
|
||||||
|
{
|
||||||
|
SPDLOG_CONSTEXPR const char *hex_upper = "0123456789ABCDEF";
|
||||||
|
SPDLOG_CONSTEXPR const char *hex_lower = "0123456789abcdef";
|
||||||
|
const char *hex_chars = use_uppercase ? hex_upper : hex_lower;
|
||||||
|
|
||||||
|
#if FMT_VERSION < 60000
|
||||||
|
auto inserter = ctx.begin();
|
||||||
|
#else
|
||||||
|
auto inserter = ctx.out();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int size_per_line = static_cast<int>(the_range.size_per_line());
|
||||||
|
auto start_of_line = the_range.begin();
|
||||||
|
for (auto i = the_range.begin(); i != the_range.end(); i++)
|
||||||
|
{
|
||||||
|
auto ch = static_cast<unsigned char>(*i);
|
||||||
|
|
||||||
|
if (put_newlines && (i == the_range.begin() || i - start_of_line >= size_per_line))
|
||||||
|
{
|
||||||
|
if (show_ascii && i != the_range.begin())
|
||||||
|
{
|
||||||
|
*inserter++ = delimiter;
|
||||||
|
*inserter++ = delimiter;
|
||||||
|
for (auto j = start_of_line; j < i; j++)
|
||||||
|
{
|
||||||
|
auto pc = static_cast<unsigned char>(*j);
|
||||||
|
*inserter++ = std::isprint(pc) ? static_cast<char>(*j) : '.';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
put_newline(inserter, static_cast<size_t>(i - the_range.begin()));
|
||||||
|
|
||||||
|
// put first byte without delimiter in front of it
|
||||||
|
*inserter++ = hex_chars[(ch >> 4) & 0x0f];
|
||||||
|
*inserter++ = hex_chars[ch & 0x0f];
|
||||||
|
start_of_line = i;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (put_delimiters)
|
||||||
|
{
|
||||||
|
*inserter++ = delimiter;
|
||||||
|
}
|
||||||
|
|
||||||
|
*inserter++ = hex_chars[(ch >> 4) & 0x0f];
|
||||||
|
*inserter++ = hex_chars[ch & 0x0f];
|
||||||
|
}
|
||||||
|
if (show_ascii) // add ascii to last line
|
||||||
|
{
|
||||||
|
if (the_range.end() - the_range.begin() > size_per_line)
|
||||||
|
{
|
||||||
|
auto blank_num = size_per_line - (the_range.end() - start_of_line);
|
||||||
|
while (blank_num-- > 0)
|
||||||
|
{
|
||||||
|
*inserter++ = delimiter;
|
||||||
|
*inserter++ = delimiter;
|
||||||
|
if (put_delimiters)
|
||||||
|
{
|
||||||
|
*inserter++ = delimiter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*inserter++ = delimiter;
|
||||||
|
*inserter++ = delimiter;
|
||||||
|
for (auto j = start_of_line; j != the_range.end(); j++)
|
||||||
|
{
|
||||||
|
auto pc = static_cast<unsigned char>(*j);
|
||||||
|
*inserter++ = std::isprint(pc) ? static_cast<char>(*j) : '.';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return inserter;
|
||||||
|
}
|
||||||
|
|
||||||
|
// put newline(and position header)
|
||||||
|
template<typename It>
|
||||||
|
void put_newline(It inserter, std::size_t pos)
|
||||||
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
|
*inserter++ = '\r';
|
||||||
|
#endif
|
||||||
|
*inserter++ = '\n';
|
||||||
|
|
||||||
|
if (put_positions)
|
||||||
|
{
|
||||||
|
fmt::format_to(inserter, "{:04X}: ", pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} // namespace fmt
|
||||||
232
thirdparty/spdlog/fmt/bundled/args.h
vendored
Normal file
232
thirdparty/spdlog/fmt/bundled/args.h
vendored
Normal file
@@ -0,0 +1,232 @@
|
|||||||
|
// Formatting library for C++ - dynamic format arguments
|
||||||
|
//
|
||||||
|
// Copyright (c) 2012 - present, Victor Zverovich
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// For the license information refer to format.h.
|
||||||
|
|
||||||
|
#ifndef FMT_ARGS_H_
|
||||||
|
#define FMT_ARGS_H_
|
||||||
|
|
||||||
|
#include <functional> // std::reference_wrapper
|
||||||
|
#include <memory> // std::unique_ptr
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "core.h"
|
||||||
|
|
||||||
|
FMT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
template <typename T> struct is_reference_wrapper : std::false_type {};
|
||||||
|
template <typename T>
|
||||||
|
struct is_reference_wrapper<std::reference_wrapper<T>> : std::true_type {};
|
||||||
|
|
||||||
|
template <typename T> const T& unwrap(const T& v) { return v; }
|
||||||
|
template <typename T> const T& unwrap(const std::reference_wrapper<T>& v) {
|
||||||
|
return static_cast<const T&>(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
class dynamic_arg_list {
|
||||||
|
// Workaround for clang's -Wweak-vtables. Unlike for regular classes, for
|
||||||
|
// templates it doesn't complain about inability to deduce single translation
|
||||||
|
// unit for placing vtable. So storage_node_base is made a fake template.
|
||||||
|
template <typename = void> struct node {
|
||||||
|
virtual ~node() = default;
|
||||||
|
std::unique_ptr<node<>> next;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T> struct typed_node : node<> {
|
||||||
|
T value;
|
||||||
|
|
||||||
|
template <typename Arg>
|
||||||
|
FMT_CONSTEXPR typed_node(const Arg& arg) : value(arg) {}
|
||||||
|
|
||||||
|
template <typename Char>
|
||||||
|
FMT_CONSTEXPR typed_node(const basic_string_view<Char>& arg)
|
||||||
|
: value(arg.data(), arg.size()) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
std::unique_ptr<node<>> head_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
template <typename T, typename Arg> const T& push(const Arg& arg) {
|
||||||
|
auto new_node = std::unique_ptr<typed_node<T>>(new typed_node<T>(arg));
|
||||||
|
auto& value = new_node->value;
|
||||||
|
new_node->next = std::move(head_);
|
||||||
|
head_ = std::move(new_node);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
/**
|
||||||
|
\rst
|
||||||
|
A dynamic version of `fmt::format_arg_store`.
|
||||||
|
It's equipped with a storage to potentially temporary objects which lifetimes
|
||||||
|
could be shorter than the format arguments object.
|
||||||
|
|
||||||
|
It can be implicitly converted into `~fmt::basic_format_args` for passing
|
||||||
|
into type-erased formatting functions such as `~fmt::vformat`.
|
||||||
|
\endrst
|
||||||
|
*/
|
||||||
|
template <typename Context>
|
||||||
|
class dynamic_format_arg_store
|
||||||
|
#if FMT_GCC_VERSION && FMT_GCC_VERSION < 409
|
||||||
|
// Workaround a GCC template argument substitution bug.
|
||||||
|
: public basic_format_args<Context>
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
using char_type = typename Context::char_type;
|
||||||
|
|
||||||
|
template <typename T> struct need_copy {
|
||||||
|
static constexpr detail::type mapped_type =
|
||||||
|
detail::mapped_type_constant<T, Context>::value;
|
||||||
|
|
||||||
|
enum {
|
||||||
|
value = !(detail::is_reference_wrapper<T>::value ||
|
||||||
|
std::is_same<T, basic_string_view<char_type>>::value ||
|
||||||
|
std::is_same<T, detail::std_string_view<char_type>>::value ||
|
||||||
|
(mapped_type != detail::type::cstring_type &&
|
||||||
|
mapped_type != detail::type::string_type &&
|
||||||
|
mapped_type != detail::type::custom_type))
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
using stored_type = conditional_t<detail::is_string<T>::value &&
|
||||||
|
!has_formatter<T, Context>::value &&
|
||||||
|
!detail::is_reference_wrapper<T>::value,
|
||||||
|
std::basic_string<char_type>, T>;
|
||||||
|
|
||||||
|
// Storage of basic_format_arg must be contiguous.
|
||||||
|
std::vector<basic_format_arg<Context>> data_;
|
||||||
|
std::vector<detail::named_arg_info<char_type>> named_info_;
|
||||||
|
|
||||||
|
// Storage of arguments not fitting into basic_format_arg must grow
|
||||||
|
// without relocation because items in data_ refer to it.
|
||||||
|
detail::dynamic_arg_list dynamic_args_;
|
||||||
|
|
||||||
|
friend class basic_format_args<Context>;
|
||||||
|
|
||||||
|
unsigned long long get_types() const {
|
||||||
|
return detail::is_unpacked_bit | data_.size() |
|
||||||
|
(named_info_.empty()
|
||||||
|
? 0ULL
|
||||||
|
: static_cast<unsigned long long>(detail::has_named_args_bit));
|
||||||
|
}
|
||||||
|
|
||||||
|
const basic_format_arg<Context>* data() const {
|
||||||
|
return named_info_.empty() ? data_.data() : data_.data() + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T> void emplace_arg(const T& arg) {
|
||||||
|
data_.emplace_back(detail::make_arg<Context>(arg));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void emplace_arg(const detail::named_arg<char_type, T>& arg) {
|
||||||
|
if (named_info_.empty()) {
|
||||||
|
constexpr const detail::named_arg_info<char_type>* zero_ptr{nullptr};
|
||||||
|
data_.insert(data_.begin(), {zero_ptr, 0});
|
||||||
|
}
|
||||||
|
data_.emplace_back(detail::make_arg<Context>(detail::unwrap(arg.value)));
|
||||||
|
auto pop_one = [](std::vector<basic_format_arg<Context>>* data) {
|
||||||
|
data->pop_back();
|
||||||
|
};
|
||||||
|
std::unique_ptr<std::vector<basic_format_arg<Context>>, decltype(pop_one)>
|
||||||
|
guard{&data_, pop_one};
|
||||||
|
named_info_.push_back({arg.name, static_cast<int>(data_.size() - 2u)});
|
||||||
|
data_[0].value_.named_args = {named_info_.data(), named_info_.size()};
|
||||||
|
guard.release();
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
\rst
|
||||||
|
Adds an argument into the dynamic store for later passing to a formatting
|
||||||
|
function.
|
||||||
|
|
||||||
|
Note that custom types and string types (but not string views) are copied
|
||||||
|
into the store dynamically allocating memory if necessary.
|
||||||
|
|
||||||
|
**Example**::
|
||||||
|
|
||||||
|
fmt::dynamic_format_arg_store<fmt::format_context> store;
|
||||||
|
store.push_back(42);
|
||||||
|
store.push_back("abc");
|
||||||
|
store.push_back(1.5f);
|
||||||
|
std::string result = fmt::vformat("{} and {} and {}", store);
|
||||||
|
\endrst
|
||||||
|
*/
|
||||||
|
template <typename T> void push_back(const T& arg) {
|
||||||
|
if (detail::const_check(need_copy<T>::value))
|
||||||
|
emplace_arg(dynamic_args_.push<stored_type<T>>(arg));
|
||||||
|
else
|
||||||
|
emplace_arg(detail::unwrap(arg));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
\rst
|
||||||
|
Adds a reference to the argument into the dynamic store for later passing to
|
||||||
|
a formatting function.
|
||||||
|
|
||||||
|
**Example**::
|
||||||
|
|
||||||
|
fmt::dynamic_format_arg_store<fmt::format_context> store;
|
||||||
|
char band[] = "Rolling Stones";
|
||||||
|
store.push_back(std::cref(band));
|
||||||
|
band[9] = 'c'; // Changing str affects the output.
|
||||||
|
std::string result = fmt::vformat("{}", store);
|
||||||
|
// result == "Rolling Scones"
|
||||||
|
\endrst
|
||||||
|
*/
|
||||||
|
template <typename T> void push_back(std::reference_wrapper<T> arg) {
|
||||||
|
static_assert(
|
||||||
|
need_copy<T>::value,
|
||||||
|
"objects of built-in types and string views are always copied");
|
||||||
|
emplace_arg(arg.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Adds named argument into the dynamic store for later passing to a formatting
|
||||||
|
function. ``std::reference_wrapper`` is supported to avoid copying of the
|
||||||
|
argument. The name is always copied into the store.
|
||||||
|
*/
|
||||||
|
template <typename T>
|
||||||
|
void push_back(const detail::named_arg<char_type, T>& arg) {
|
||||||
|
const char_type* arg_name =
|
||||||
|
dynamic_args_.push<std::basic_string<char_type>>(arg.name).c_str();
|
||||||
|
if (detail::const_check(need_copy<T>::value)) {
|
||||||
|
emplace_arg(
|
||||||
|
fmt::arg(arg_name, dynamic_args_.push<stored_type<T>>(arg.value)));
|
||||||
|
} else {
|
||||||
|
emplace_arg(fmt::arg(arg_name, arg.value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Erase all elements from the store */
|
||||||
|
void clear() {
|
||||||
|
data_.clear();
|
||||||
|
named_info_.clear();
|
||||||
|
dynamic_args_ = detail::dynamic_arg_list();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
\rst
|
||||||
|
Reserves space to store at least *new_cap* arguments including
|
||||||
|
*new_cap_named* named arguments.
|
||||||
|
\endrst
|
||||||
|
*/
|
||||||
|
void reserve(size_t new_cap, size_t new_cap_named) {
|
||||||
|
FMT_ASSERT(new_cap >= new_cap_named,
|
||||||
|
"Set of arguments includes set of named arguments");
|
||||||
|
data_.reserve(new_cap);
|
||||||
|
named_info_.reserve(new_cap_named);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
FMT_END_NAMESPACE
|
||||||
|
|
||||||
|
#endif // FMT_ARGS_H_
|
||||||
1308
thirdparty/spdlog/fmt/bundled/chrono.h
vendored
Normal file
1308
thirdparty/spdlog/fmt/bundled/chrono.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
627
thirdparty/spdlog/fmt/bundled/color.h
vendored
Normal file
627
thirdparty/spdlog/fmt/bundled/color.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
639
thirdparty/spdlog/fmt/bundled/compile.h
vendored
Normal file
639
thirdparty/spdlog/fmt/bundled/compile.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
3002
thirdparty/spdlog/fmt/bundled/core.h
vendored
Normal file
3002
thirdparty/spdlog/fmt/bundled/core.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
2620
thirdparty/spdlog/fmt/bundled/format-inl.h
vendored
Normal file
2620
thirdparty/spdlog/fmt/bundled/format-inl.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
2830
thirdparty/spdlog/fmt/bundled/format.h
vendored
Normal file
2830
thirdparty/spdlog/fmt/bundled/format.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
2
thirdparty/spdlog/fmt/bundled/locale.h
vendored
Normal file
2
thirdparty/spdlog/fmt/bundled/locale.h
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
#include "xchar.h"
|
||||||
|
#warning fmt/locale.h is deprecated, include fmt/format.h or fmt/xchar.h instead
|
||||||
515
thirdparty/spdlog/fmt/bundled/os.h
vendored
Normal file
515
thirdparty/spdlog/fmt/bundled/os.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
181
thirdparty/spdlog/fmt/bundled/ostream.h
vendored
Normal file
181
thirdparty/spdlog/fmt/bundled/ostream.h
vendored
Normal file
@@ -0,0 +1,181 @@
|
|||||||
|
// Formatting library for C++ - std::ostream support
|
||||||
|
//
|
||||||
|
// Copyright (c) 2012 - present, Victor Zverovich
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// For the license information refer to format.h.
|
||||||
|
|
||||||
|
#ifndef FMT_OSTREAM_H_
|
||||||
|
#define FMT_OSTREAM_H_
|
||||||
|
|
||||||
|
#include <ostream>
|
||||||
|
|
||||||
|
#include "format.h"
|
||||||
|
|
||||||
|
FMT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
|
template <typename Char> class basic_printf_parse_context;
|
||||||
|
template <typename OutputIt, typename Char> class basic_printf_context;
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
template <class Char> class formatbuf : public std::basic_streambuf<Char> {
|
||||||
|
private:
|
||||||
|
using int_type = typename std::basic_streambuf<Char>::int_type;
|
||||||
|
using traits_type = typename std::basic_streambuf<Char>::traits_type;
|
||||||
|
|
||||||
|
buffer<Char>& buffer_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
formatbuf(buffer<Char>& buf) : buffer_(buf) {}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// The put-area is actually always empty. This makes the implementation
|
||||||
|
// simpler and has the advantage that the streambuf and the buffer are always
|
||||||
|
// in sync and sputc never writes into uninitialized memory. The obvious
|
||||||
|
// disadvantage is that each call to sputc always results in a (virtual) call
|
||||||
|
// to overflow. There is no disadvantage here for sputn since this always
|
||||||
|
// results in a call to xsputn.
|
||||||
|
|
||||||
|
int_type overflow(int_type ch = traits_type::eof()) FMT_OVERRIDE {
|
||||||
|
if (!traits_type::eq_int_type(ch, traits_type::eof()))
|
||||||
|
buffer_.push_back(static_cast<Char>(ch));
|
||||||
|
return ch;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::streamsize xsputn(const Char* s, std::streamsize count) FMT_OVERRIDE {
|
||||||
|
buffer_.append(s, s + count);
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct converter {
|
||||||
|
template <typename T, FMT_ENABLE_IF(is_integral<T>::value)> converter(T);
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Char> struct test_stream : std::basic_ostream<Char> {
|
||||||
|
private:
|
||||||
|
void_t<> operator<<(converter);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Hide insertion operators for built-in types.
|
||||||
|
template <typename Char, typename Traits>
|
||||||
|
void_t<> operator<<(std::basic_ostream<Char, Traits>&, Char);
|
||||||
|
template <typename Char, typename Traits>
|
||||||
|
void_t<> operator<<(std::basic_ostream<Char, Traits>&, char);
|
||||||
|
template <typename Traits>
|
||||||
|
void_t<> operator<<(std::basic_ostream<char, Traits>&, char);
|
||||||
|
template <typename Traits>
|
||||||
|
void_t<> operator<<(std::basic_ostream<char, Traits>&, signed char);
|
||||||
|
template <typename Traits>
|
||||||
|
void_t<> operator<<(std::basic_ostream<char, Traits>&, unsigned char);
|
||||||
|
|
||||||
|
// Checks if T has a user-defined operator<< (e.g. not a member of
|
||||||
|
// std::ostream).
|
||||||
|
template <typename T, typename Char> class is_streamable {
|
||||||
|
private:
|
||||||
|
template <typename U>
|
||||||
|
static bool_constant<!std::is_same<decltype(std::declval<test_stream<Char>&>()
|
||||||
|
<< std::declval<U>()),
|
||||||
|
void_t<>>::value>
|
||||||
|
test(int);
|
||||||
|
|
||||||
|
template <typename> static std::false_type test(...);
|
||||||
|
|
||||||
|
using result = decltype(test<T>(0));
|
||||||
|
|
||||||
|
public:
|
||||||
|
is_streamable() = default;
|
||||||
|
|
||||||
|
static const bool value = result::value;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Write the content of buf to os.
|
||||||
|
template <typename Char>
|
||||||
|
void write_buffer(std::basic_ostream<Char>& os, buffer<Char>& buf) {
|
||||||
|
const Char* buf_data = buf.data();
|
||||||
|
using unsigned_streamsize = std::make_unsigned<std::streamsize>::type;
|
||||||
|
unsigned_streamsize size = buf.size();
|
||||||
|
unsigned_streamsize max_size = to_unsigned(max_value<std::streamsize>());
|
||||||
|
do {
|
||||||
|
unsigned_streamsize n = size <= max_size ? size : max_size;
|
||||||
|
os.write(buf_data, static_cast<std::streamsize>(n));
|
||||||
|
buf_data += n;
|
||||||
|
size -= n;
|
||||||
|
} while (size != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Char, typename T>
|
||||||
|
void format_value(buffer<Char>& buf, const T& value,
|
||||||
|
locale_ref loc = locale_ref()) {
|
||||||
|
formatbuf<Char> format_buf(buf);
|
||||||
|
std::basic_ostream<Char> output(&format_buf);
|
||||||
|
#if !defined(FMT_STATIC_THOUSANDS_SEPARATOR)
|
||||||
|
if (loc) output.imbue(loc.get<std::locale>());
|
||||||
|
#endif
|
||||||
|
output << value;
|
||||||
|
output.exceptions(std::ios_base::failbit | std::ios_base::badbit);
|
||||||
|
buf.try_resize(buf.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Formats an object of type T that has an overloaded ostream operator<<.
|
||||||
|
template <typename T, typename Char>
|
||||||
|
struct fallback_formatter<T, Char, enable_if_t<is_streamable<T, Char>::value>>
|
||||||
|
: private formatter<basic_string_view<Char>, Char> {
|
||||||
|
FMT_CONSTEXPR auto parse(basic_format_parse_context<Char>& ctx)
|
||||||
|
-> decltype(ctx.begin()) {
|
||||||
|
return formatter<basic_string_view<Char>, Char>::parse(ctx);
|
||||||
|
}
|
||||||
|
template <typename ParseCtx,
|
||||||
|
FMT_ENABLE_IF(std::is_same<
|
||||||
|
ParseCtx, basic_printf_parse_context<Char>>::value)>
|
||||||
|
auto parse(ParseCtx& ctx) -> decltype(ctx.begin()) {
|
||||||
|
return ctx.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename OutputIt>
|
||||||
|
auto format(const T& value, basic_format_context<OutputIt, Char>& ctx)
|
||||||
|
-> OutputIt {
|
||||||
|
basic_memory_buffer<Char> buffer;
|
||||||
|
format_value(buffer, value, ctx.locale());
|
||||||
|
basic_string_view<Char> str(buffer.data(), buffer.size());
|
||||||
|
return formatter<basic_string_view<Char>, Char>::format(str, ctx);
|
||||||
|
}
|
||||||
|
template <typename OutputIt>
|
||||||
|
auto format(const T& value, basic_printf_context<OutputIt, Char>& ctx)
|
||||||
|
-> OutputIt {
|
||||||
|
basic_memory_buffer<Char> buffer;
|
||||||
|
format_value(buffer, value, ctx.locale());
|
||||||
|
return std::copy(buffer.begin(), buffer.end(), ctx.out());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
FMT_MODULE_EXPORT
|
||||||
|
template <typename Char>
|
||||||
|
void vprint(std::basic_ostream<Char>& os, basic_string_view<Char> format_str,
|
||||||
|
basic_format_args<buffer_context<type_identity_t<Char>>> args) {
|
||||||
|
basic_memory_buffer<Char> buffer;
|
||||||
|
detail::vformat_to(buffer, format_str, args);
|
||||||
|
detail::write_buffer(os, buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
\rst
|
||||||
|
Prints formatted data to the stream *os*.
|
||||||
|
|
||||||
|
**Example**::
|
||||||
|
|
||||||
|
fmt::print(cerr, "Don't {}!", "panic");
|
||||||
|
\endrst
|
||||||
|
*/
|
||||||
|
FMT_MODULE_EXPORT
|
||||||
|
template <typename S, typename... Args,
|
||||||
|
typename Char = enable_if_t<detail::is_string<S>::value, char_t<S>>>
|
||||||
|
void print(std::basic_ostream<Char>& os, const S& format_str, Args&&... args) {
|
||||||
|
vprint(os, to_string_view(format_str),
|
||||||
|
fmt::make_args_checked<Args...>(format_str, args...));
|
||||||
|
}
|
||||||
|
FMT_END_NAMESPACE
|
||||||
|
|
||||||
|
#endif // FMT_OSTREAM_H_
|
||||||
652
thirdparty/spdlog/fmt/bundled/printf.h
vendored
Normal file
652
thirdparty/spdlog/fmt/bundled/printf.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
468
thirdparty/spdlog/fmt/bundled/ranges.h
vendored
Normal file
468
thirdparty/spdlog/fmt/bundled/ranges.h
vendored
Normal file
@@ -0,0 +1,468 @@
|
|||||||
|
// Formatting library for C++ - experimental range support
|
||||||
|
//
|
||||||
|
// Copyright (c) 2012 - present, Victor Zverovich
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// For the license information refer to format.h.
|
||||||
|
//
|
||||||
|
// Copyright (c) 2018 - present, Remotion (Igor Schulz)
|
||||||
|
// All Rights Reserved
|
||||||
|
// {fmt} support for ranges, containers and types tuple interface.
|
||||||
|
|
||||||
|
#ifndef FMT_RANGES_H_
|
||||||
|
#define FMT_RANGES_H_
|
||||||
|
|
||||||
|
#include <initializer_list>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
#include "format.h"
|
||||||
|
|
||||||
|
FMT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
|
template <typename Char, typename Enable = void> struct formatting_range {
|
||||||
|
#ifdef FMT_DEPRECATED_BRACED_RANGES
|
||||||
|
Char prefix = '{';
|
||||||
|
Char postfix = '}';
|
||||||
|
#else
|
||||||
|
Char prefix = '[';
|
||||||
|
Char postfix = ']';
|
||||||
|
#endif
|
||||||
|
|
||||||
|
template <typename ParseContext>
|
||||||
|
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
|
||||||
|
return ctx.begin();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Char, typename Enable = void> struct formatting_tuple {
|
||||||
|
Char prefix = '(';
|
||||||
|
Char postfix = ')';
|
||||||
|
|
||||||
|
template <typename ParseContext>
|
||||||
|
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
|
||||||
|
return ctx.begin();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
template <typename RangeT, typename OutputIterator>
|
||||||
|
OutputIterator copy(const RangeT& range, OutputIterator out) {
|
||||||
|
for (auto it = range.begin(), end = range.end(); it != end; ++it)
|
||||||
|
*out++ = *it;
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename OutputIterator>
|
||||||
|
OutputIterator copy(const char* str, OutputIterator out) {
|
||||||
|
while (*str) *out++ = *str++;
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename OutputIterator>
|
||||||
|
OutputIterator copy(char ch, OutputIterator out) {
|
||||||
|
*out++ = ch;
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename OutputIterator>
|
||||||
|
OutputIterator copy(wchar_t ch, OutputIterator out) {
|
||||||
|
*out++ = ch;
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return true value if T has std::string interface, like std::string_view.
|
||||||
|
template <typename T> class is_std_string_like {
|
||||||
|
template <typename U>
|
||||||
|
static auto check(U* p)
|
||||||
|
-> decltype((void)p->find('a'), p->length(), (void)p->data(), int());
|
||||||
|
template <typename> static void check(...);
|
||||||
|
|
||||||
|
public:
|
||||||
|
static FMT_CONSTEXPR_DECL const bool value =
|
||||||
|
is_string<T>::value || !std::is_void<decltype(check<T>(nullptr))>::value;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Char>
|
||||||
|
struct is_std_string_like<fmt::basic_string_view<Char>> : std::true_type {};
|
||||||
|
|
||||||
|
template <typename... Ts> struct conditional_helper {};
|
||||||
|
|
||||||
|
template <typename T, typename _ = void> struct is_range_ : std::false_type {};
|
||||||
|
|
||||||
|
#if !FMT_MSC_VER || FMT_MSC_VER > 1800
|
||||||
|
|
||||||
|
# define FMT_DECLTYPE_RETURN(val) \
|
||||||
|
->decltype(val) { return val; } \
|
||||||
|
static_assert( \
|
||||||
|
true, "") // This makes it so that a semicolon is required after the
|
||||||
|
// macro, which helps clang-format handle the formatting.
|
||||||
|
|
||||||
|
// C array overload
|
||||||
|
template <typename T, std::size_t N>
|
||||||
|
auto range_begin(const T (&arr)[N]) -> const T* {
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
template <typename T, std::size_t N>
|
||||||
|
auto range_end(const T (&arr)[N]) -> const T* {
|
||||||
|
return arr + N;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename Enable = void>
|
||||||
|
struct has_member_fn_begin_end_t : std::false_type {};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct has_member_fn_begin_end_t<T, void_t<decltype(std::declval<T>().begin()),
|
||||||
|
decltype(std::declval<T>().end())>>
|
||||||
|
: std::true_type {};
|
||||||
|
|
||||||
|
// Member function overload
|
||||||
|
template <typename T>
|
||||||
|
auto range_begin(T&& rng) FMT_DECLTYPE_RETURN(static_cast<T&&>(rng).begin());
|
||||||
|
template <typename T>
|
||||||
|
auto range_end(T&& rng) FMT_DECLTYPE_RETURN(static_cast<T&&>(rng).end());
|
||||||
|
|
||||||
|
// ADL overload. Only participates in overload resolution if member functions
|
||||||
|
// are not found.
|
||||||
|
template <typename T>
|
||||||
|
auto range_begin(T&& rng)
|
||||||
|
-> enable_if_t<!has_member_fn_begin_end_t<T&&>::value,
|
||||||
|
decltype(begin(static_cast<T&&>(rng)))> {
|
||||||
|
return begin(static_cast<T&&>(rng));
|
||||||
|
}
|
||||||
|
template <typename T>
|
||||||
|
auto range_end(T&& rng) -> enable_if_t<!has_member_fn_begin_end_t<T&&>::value,
|
||||||
|
decltype(end(static_cast<T&&>(rng)))> {
|
||||||
|
return end(static_cast<T&&>(rng));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename Enable = void>
|
||||||
|
struct has_const_begin_end : std::false_type {};
|
||||||
|
template <typename T, typename Enable = void>
|
||||||
|
struct has_mutable_begin_end : std::false_type {};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct has_const_begin_end<
|
||||||
|
T, void_t<decltype(detail::range_begin(
|
||||||
|
std::declval<const remove_cvref_t<T>&>())),
|
||||||
|
decltype(detail::range_begin(
|
||||||
|
std::declval<const remove_cvref_t<T>&>()))>>
|
||||||
|
: std::true_type {};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct has_mutable_begin_end<
|
||||||
|
T, void_t<decltype(detail::range_begin(std::declval<T>())),
|
||||||
|
decltype(detail::range_begin(std::declval<T>())),
|
||||||
|
enable_if_t<std::is_copy_constructible<T>::value>>>
|
||||||
|
: std::true_type {};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct is_range_<T, void>
|
||||||
|
: std::integral_constant<bool, (has_const_begin_end<T>::value ||
|
||||||
|
has_mutable_begin_end<T>::value)> {};
|
||||||
|
|
||||||
|
template <typename T, typename Enable = void> struct range_to_view;
|
||||||
|
template <typename T>
|
||||||
|
struct range_to_view<T, enable_if_t<has_const_begin_end<T>::value>> {
|
||||||
|
struct view_t {
|
||||||
|
const T* m_range_ptr;
|
||||||
|
|
||||||
|
auto begin() const FMT_DECLTYPE_RETURN(detail::range_begin(*m_range_ptr));
|
||||||
|
auto end() const FMT_DECLTYPE_RETURN(detail::range_end(*m_range_ptr));
|
||||||
|
};
|
||||||
|
static auto view(const T& range) -> view_t { return {&range}; }
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct range_to_view<T, enable_if_t<!has_const_begin_end<T>::value &&
|
||||||
|
has_mutable_begin_end<T>::value>> {
|
||||||
|
struct view_t {
|
||||||
|
T m_range_copy;
|
||||||
|
|
||||||
|
auto begin() FMT_DECLTYPE_RETURN(detail::range_begin(m_range_copy));
|
||||||
|
auto end() FMT_DECLTYPE_RETURN(detail::range_end(m_range_copy));
|
||||||
|
};
|
||||||
|
static auto view(const T& range) -> view_t { return {range}; }
|
||||||
|
};
|
||||||
|
# undef FMT_DECLTYPE_RETURN
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// tuple_size and tuple_element check.
|
||||||
|
template <typename T> class is_tuple_like_ {
|
||||||
|
template <typename U>
|
||||||
|
static auto check(U* p) -> decltype(std::tuple_size<U>::value, int());
|
||||||
|
template <typename> static void check(...);
|
||||||
|
|
||||||
|
public:
|
||||||
|
static FMT_CONSTEXPR_DECL const bool value =
|
||||||
|
!std::is_void<decltype(check<T>(nullptr))>::value;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Check for integer_sequence
|
||||||
|
#if defined(__cpp_lib_integer_sequence) || FMT_MSC_VER >= 1900
|
||||||
|
template <typename T, T... N>
|
||||||
|
using integer_sequence = std::integer_sequence<T, N...>;
|
||||||
|
template <size_t... N> using index_sequence = std::index_sequence<N...>;
|
||||||
|
template <size_t N> using make_index_sequence = std::make_index_sequence<N>;
|
||||||
|
#else
|
||||||
|
template <typename T, T... N> struct integer_sequence {
|
||||||
|
using value_type = T;
|
||||||
|
|
||||||
|
static FMT_CONSTEXPR size_t size() { return sizeof...(N); }
|
||||||
|
};
|
||||||
|
|
||||||
|
template <size_t... N> using index_sequence = integer_sequence<size_t, N...>;
|
||||||
|
|
||||||
|
template <typename T, size_t N, T... Ns>
|
||||||
|
struct make_integer_sequence : make_integer_sequence<T, N - 1, N - 1, Ns...> {};
|
||||||
|
template <typename T, T... Ns>
|
||||||
|
struct make_integer_sequence<T, 0, Ns...> : integer_sequence<T, Ns...> {};
|
||||||
|
|
||||||
|
template <size_t N>
|
||||||
|
using make_index_sequence = make_integer_sequence<size_t, N>;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
template <class Tuple, class F, size_t... Is>
|
||||||
|
void for_each(index_sequence<Is...>, Tuple&& tup, F&& f) FMT_NOEXCEPT {
|
||||||
|
using std::get;
|
||||||
|
// using free function get<I>(T) now.
|
||||||
|
const int _[] = {0, ((void)f(get<Is>(tup)), 0)...};
|
||||||
|
(void)_; // blocks warnings
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
FMT_CONSTEXPR make_index_sequence<std::tuple_size<T>::value> get_indexes(
|
||||||
|
T const&) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Tuple, class F> void for_each(Tuple&& tup, F&& f) {
|
||||||
|
const auto indexes = get_indexes(tup);
|
||||||
|
for_each(indexes, std::forward<Tuple>(tup), std::forward<F>(f));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Range>
|
||||||
|
using value_type =
|
||||||
|
remove_cvref_t<decltype(*detail::range_begin(std::declval<Range>()))>;
|
||||||
|
|
||||||
|
template <typename OutputIt> OutputIt write_delimiter(OutputIt out) {
|
||||||
|
*out++ = ',';
|
||||||
|
*out++ = ' ';
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <
|
||||||
|
typename Char, typename OutputIt, typename Arg,
|
||||||
|
FMT_ENABLE_IF(is_std_string_like<typename std::decay<Arg>::type>::value)>
|
||||||
|
OutputIt write_range_entry(OutputIt out, const Arg& v) {
|
||||||
|
*out++ = '"';
|
||||||
|
out = write<Char>(out, v);
|
||||||
|
*out++ = '"';
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Char, typename OutputIt, typename Arg,
|
||||||
|
FMT_ENABLE_IF(std::is_same<Arg, Char>::value)>
|
||||||
|
OutputIt write_range_entry(OutputIt out, const Arg v) {
|
||||||
|
*out++ = '\'';
|
||||||
|
*out++ = v;
|
||||||
|
*out++ = '\'';
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <
|
||||||
|
typename Char, typename OutputIt, typename Arg,
|
||||||
|
FMT_ENABLE_IF(!is_std_string_like<typename std::decay<Arg>::type>::value &&
|
||||||
|
!std::is_same<Arg, Char>::value)>
|
||||||
|
OutputIt write_range_entry(OutputIt out, const Arg& v) {
|
||||||
|
return write<Char>(out, v);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
template <typename T> struct is_tuple_like {
|
||||||
|
static FMT_CONSTEXPR_DECL const bool value =
|
||||||
|
detail::is_tuple_like_<T>::value && !detail::is_range_<T>::value;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename TupleT, typename Char>
|
||||||
|
struct formatter<TupleT, Char, enable_if_t<fmt::is_tuple_like<TupleT>::value>> {
|
||||||
|
private:
|
||||||
|
// C++11 generic lambda for format()
|
||||||
|
template <typename FormatContext> struct format_each {
|
||||||
|
template <typename T> void operator()(const T& v) {
|
||||||
|
if (i > 0) out = detail::write_delimiter(out);
|
||||||
|
out = detail::write_range_entry<Char>(out, v);
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
formatting_tuple<Char>& formatting;
|
||||||
|
size_t& i;
|
||||||
|
typename std::add_lvalue_reference<
|
||||||
|
decltype(std::declval<FormatContext>().out())>::type out;
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
formatting_tuple<Char> formatting;
|
||||||
|
|
||||||
|
template <typename ParseContext>
|
||||||
|
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
|
||||||
|
return formatting.parse(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename FormatContext = format_context>
|
||||||
|
auto format(const TupleT& values, FormatContext& ctx) -> decltype(ctx.out()) {
|
||||||
|
auto out = ctx.out();
|
||||||
|
size_t i = 0;
|
||||||
|
|
||||||
|
detail::copy(formatting.prefix, out);
|
||||||
|
detail::for_each(values, format_each<FormatContext>{formatting, i, out});
|
||||||
|
detail::copy(formatting.postfix, out);
|
||||||
|
|
||||||
|
return ctx.out();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T, typename Char> struct is_range {
|
||||||
|
static FMT_CONSTEXPR_DECL const bool value =
|
||||||
|
detail::is_range_<T>::value && !detail::is_std_string_like<T>::value &&
|
||||||
|
!std::is_convertible<T, std::basic_string<Char>>::value &&
|
||||||
|
!std::is_constructible<detail::std_string_view<Char>, T>::value;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T, typename Char>
|
||||||
|
struct formatter<
|
||||||
|
T, Char,
|
||||||
|
enable_if_t<
|
||||||
|
fmt::is_range<T, Char>::value
|
||||||
|
// Workaround a bug in MSVC 2017 and earlier.
|
||||||
|
#if !FMT_MSC_VER || FMT_MSC_VER >= 1927
|
||||||
|
&& (has_formatter<detail::value_type<T>, format_context>::value ||
|
||||||
|
detail::has_fallback_formatter<detail::value_type<T>, Char>::value)
|
||||||
|
#endif
|
||||||
|
>> {
|
||||||
|
formatting_range<Char> formatting;
|
||||||
|
|
||||||
|
template <typename ParseContext>
|
||||||
|
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
|
||||||
|
return formatting.parse(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename FormatContext>
|
||||||
|
typename FormatContext::iterator format(const T& values, FormatContext& ctx) {
|
||||||
|
auto out = detail::copy(formatting.prefix, ctx.out());
|
||||||
|
size_t i = 0;
|
||||||
|
auto view = detail::range_to_view<T>::view(values);
|
||||||
|
auto it = view.begin();
|
||||||
|
auto end = view.end();
|
||||||
|
for (; it != end; ++it) {
|
||||||
|
if (i > 0) out = detail::write_delimiter(out);
|
||||||
|
out = detail::write_range_entry<Char>(out, *it);
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
return detail::copy(formatting.postfix, out);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Char, typename... T> struct tuple_join_view : detail::view {
|
||||||
|
const std::tuple<T...>& tuple;
|
||||||
|
basic_string_view<Char> sep;
|
||||||
|
|
||||||
|
tuple_join_view(const std::tuple<T...>& t, basic_string_view<Char> s)
|
||||||
|
: tuple(t), sep{s} {}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Char, typename... T>
|
||||||
|
using tuple_arg_join = tuple_join_view<Char, T...>;
|
||||||
|
|
||||||
|
template <typename Char, typename... T>
|
||||||
|
struct formatter<tuple_join_view<Char, T...>, Char> {
|
||||||
|
template <typename ParseContext>
|
||||||
|
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
|
||||||
|
return ctx.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename FormatContext>
|
||||||
|
auto format(const tuple_join_view<Char, T...>& value, FormatContext& ctx) ->
|
||||||
|
typename FormatContext::iterator {
|
||||||
|
return format(value, ctx, detail::make_index_sequence<sizeof...(T)>{});
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
template <typename FormatContext, size_t... N>
|
||||||
|
auto format(const tuple_join_view<Char, T...>& value, FormatContext& ctx,
|
||||||
|
detail::index_sequence<N...>) ->
|
||||||
|
typename FormatContext::iterator {
|
||||||
|
using std::get;
|
||||||
|
return format_args(value, ctx, get<N>(value.tuple)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename FormatContext>
|
||||||
|
auto format_args(const tuple_join_view<Char, T...>&, FormatContext& ctx) ->
|
||||||
|
typename FormatContext::iterator {
|
||||||
|
// NOTE: for compilers that support C++17, this empty function instantiation
|
||||||
|
// can be replaced with a constexpr branch in the variadic overload.
|
||||||
|
return ctx.out();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename FormatContext, typename Arg, typename... Args>
|
||||||
|
auto format_args(const tuple_join_view<Char, T...>& value, FormatContext& ctx,
|
||||||
|
const Arg& arg, const Args&... args) ->
|
||||||
|
typename FormatContext::iterator {
|
||||||
|
using base = formatter<typename std::decay<Arg>::type, Char>;
|
||||||
|
auto out = base().format(arg, ctx);
|
||||||
|
if (sizeof...(Args) > 0) {
|
||||||
|
out = std::copy(value.sep.begin(), value.sep.end(), out);
|
||||||
|
ctx.advance_to(out);
|
||||||
|
return format_args(value, ctx, args...);
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
FMT_MODULE_EXPORT_BEGIN
|
||||||
|
|
||||||
|
/**
|
||||||
|
\rst
|
||||||
|
Returns an object that formats `tuple` with elements separated by `sep`.
|
||||||
|
|
||||||
|
**Example**::
|
||||||
|
|
||||||
|
std::tuple<int, char> t = {1, 'a'};
|
||||||
|
fmt::print("{}", fmt::join(t, ", "));
|
||||||
|
// Output: "1, a"
|
||||||
|
\endrst
|
||||||
|
*/
|
||||||
|
template <typename... T>
|
||||||
|
FMT_CONSTEXPR auto join(const std::tuple<T...>& tuple, string_view sep)
|
||||||
|
-> tuple_join_view<char, T...> {
|
||||||
|
return {tuple, sep};
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename... T>
|
||||||
|
FMT_CONSTEXPR auto join(const std::tuple<T...>& tuple,
|
||||||
|
basic_string_view<wchar_t> sep)
|
||||||
|
-> tuple_join_view<wchar_t, T...> {
|
||||||
|
return {tuple, sep};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
\rst
|
||||||
|
Returns an object that formats `initializer_list` with elements separated by
|
||||||
|
`sep`.
|
||||||
|
|
||||||
|
**Example**::
|
||||||
|
|
||||||
|
fmt::print("{}", fmt::join({1, 2, 3}, ", "));
|
||||||
|
// Output: "1, 2, 3"
|
||||||
|
\endrst
|
||||||
|
*/
|
||||||
|
template <typename T>
|
||||||
|
auto join(std::initializer_list<T> list, string_view sep)
|
||||||
|
-> join_view<const T*, const T*> {
|
||||||
|
return join(std::begin(list), std::end(list), sep);
|
||||||
|
}
|
||||||
|
|
||||||
|
FMT_MODULE_EXPORT_END
|
||||||
|
FMT_END_NAMESPACE
|
||||||
|
|
||||||
|
#endif // FMT_RANGES_H_
|
||||||
236
thirdparty/spdlog/fmt/bundled/xchar.h
vendored
Normal file
236
thirdparty/spdlog/fmt/bundled/xchar.h
vendored
Normal file
@@ -0,0 +1,236 @@
|
|||||||
|
// Formatting library for C++ - optional wchar_t and exotic character support
|
||||||
|
//
|
||||||
|
// Copyright (c) 2012 - present, Victor Zverovich
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// For the license information refer to format.h.
|
||||||
|
|
||||||
|
#ifndef FMT_WCHAR_H_
|
||||||
|
#define FMT_WCHAR_H_
|
||||||
|
|
||||||
|
#include <cwchar>
|
||||||
|
#include <tuple>
|
||||||
|
|
||||||
|
#include "format.h"
|
||||||
|
|
||||||
|
FMT_BEGIN_NAMESPACE
|
||||||
|
namespace detail {
|
||||||
|
template <typename T>
|
||||||
|
using is_exotic_char = bool_constant<!std::is_same<T, char>::value>;
|
||||||
|
}
|
||||||
|
|
||||||
|
FMT_MODULE_EXPORT_BEGIN
|
||||||
|
|
||||||
|
using wstring_view = basic_string_view<wchar_t>;
|
||||||
|
using wformat_parse_context = basic_format_parse_context<wchar_t>;
|
||||||
|
using wformat_context = buffer_context<wchar_t>;
|
||||||
|
using wformat_args = basic_format_args<wformat_context>;
|
||||||
|
using wmemory_buffer = basic_memory_buffer<wchar_t>;
|
||||||
|
|
||||||
|
#if FMT_GCC_VERSION && FMT_GCC_VERSION < 409
|
||||||
|
// Workaround broken conversion on older gcc.
|
||||||
|
template <typename... Args> using wformat_string = wstring_view;
|
||||||
|
#else
|
||||||
|
template <typename... Args>
|
||||||
|
using wformat_string = basic_format_string<wchar_t, type_identity_t<Args>...>;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
template <> struct is_char<wchar_t> : std::true_type {};
|
||||||
|
template <> struct is_char<detail::char8_type> : std::true_type {};
|
||||||
|
template <> struct is_char<char16_t> : std::true_type {};
|
||||||
|
template <> struct is_char<char32_t> : std::true_type {};
|
||||||
|
|
||||||
|
template <typename... Args>
|
||||||
|
constexpr format_arg_store<wformat_context, Args...> make_wformat_args(
|
||||||
|
const Args&... args) {
|
||||||
|
return {args...};
|
||||||
|
}
|
||||||
|
|
||||||
|
inline namespace literals {
|
||||||
|
constexpr auto operator"" _format(const wchar_t* s, size_t n)
|
||||||
|
-> detail::udl_formatter<wchar_t> {
|
||||||
|
return {{s, n}};
|
||||||
|
}
|
||||||
|
|
||||||
|
#if FMT_USE_USER_DEFINED_LITERALS && !FMT_USE_NONTYPE_TEMPLATE_PARAMETERS
|
||||||
|
constexpr detail::udl_arg<wchar_t> operator"" _a(const wchar_t* s, size_t) {
|
||||||
|
return {s};
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
} // namespace literals
|
||||||
|
|
||||||
|
template <typename It, typename Sentinel>
|
||||||
|
auto join(It begin, Sentinel end, wstring_view sep)
|
||||||
|
-> join_view<It, Sentinel, wchar_t> {
|
||||||
|
return {begin, end, sep};
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Range>
|
||||||
|
auto join(Range&& range, wstring_view sep)
|
||||||
|
-> join_view<detail::iterator_t<Range>, detail::sentinel_t<Range>,
|
||||||
|
wchar_t> {
|
||||||
|
return join(std::begin(range), std::end(range), sep);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
auto join(std::initializer_list<T> list, wstring_view sep)
|
||||||
|
-> join_view<const T*, const T*, wchar_t> {
|
||||||
|
return join(std::begin(list), std::end(list), sep);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Char, FMT_ENABLE_IF(!std::is_same<Char, char>::value)>
|
||||||
|
auto vformat(basic_string_view<Char> format_str,
|
||||||
|
basic_format_args<buffer_context<type_identity_t<Char>>> args)
|
||||||
|
-> std::basic_string<Char> {
|
||||||
|
basic_memory_buffer<Char> buffer;
|
||||||
|
detail::vformat_to(buffer, format_str, args);
|
||||||
|
return to_string(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pass char_t as a default template parameter instead of using
|
||||||
|
// std::basic_string<char_t<S>> to reduce the symbol size.
|
||||||
|
template <typename S, typename... Args, typename Char = char_t<S>,
|
||||||
|
FMT_ENABLE_IF(!std::is_same<Char, char>::value)>
|
||||||
|
auto format(const S& format_str, Args&&... args) -> std::basic_string<Char> {
|
||||||
|
const auto& vargs = fmt::make_args_checked<Args...>(format_str, args...);
|
||||||
|
return vformat(to_string_view(format_str), vargs);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Locale, typename S, typename Char = char_t<S>,
|
||||||
|
FMT_ENABLE_IF(detail::is_locale<Locale>::value&&
|
||||||
|
detail::is_exotic_char<Char>::value)>
|
||||||
|
inline auto vformat(
|
||||||
|
const Locale& loc, const S& format_str,
|
||||||
|
basic_format_args<buffer_context<type_identity_t<Char>>> args)
|
||||||
|
-> std::basic_string<Char> {
|
||||||
|
return detail::vformat(loc, to_string_view(format_str), args);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Locale, typename S, typename... Args,
|
||||||
|
typename Char = char_t<S>,
|
||||||
|
FMT_ENABLE_IF(detail::is_locale<Locale>::value&&
|
||||||
|
detail::is_exotic_char<Char>::value)>
|
||||||
|
inline auto format(const Locale& loc, const S& format_str, Args&&... args)
|
||||||
|
-> std::basic_string<Char> {
|
||||||
|
return detail::vformat(loc, to_string_view(format_str),
|
||||||
|
fmt::make_args_checked<Args...>(format_str, args...));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename OutputIt, typename S, typename Char = char_t<S>,
|
||||||
|
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value&&
|
||||||
|
detail::is_exotic_char<Char>::value)>
|
||||||
|
auto vformat_to(OutputIt out, const S& format_str,
|
||||||
|
basic_format_args<buffer_context<type_identity_t<Char>>> args)
|
||||||
|
-> OutputIt {
|
||||||
|
auto&& buf = detail::get_buffer<Char>(out);
|
||||||
|
detail::vformat_to(buf, to_string_view(format_str), args);
|
||||||
|
return detail::get_iterator(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename OutputIt, typename S, typename... Args,
|
||||||
|
typename Char = char_t<S>,
|
||||||
|
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value&&
|
||||||
|
detail::is_exotic_char<Char>::value)>
|
||||||
|
inline auto format_to(OutputIt out, const S& fmt, Args&&... args) -> OutputIt {
|
||||||
|
const auto& vargs = fmt::make_args_checked<Args...>(fmt, args...);
|
||||||
|
return vformat_to(out, to_string_view(fmt), vargs);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename S, typename... Args, typename Char, size_t SIZE,
|
||||||
|
typename Allocator, FMT_ENABLE_IF(detail::is_string<S>::value)>
|
||||||
|
FMT_DEPRECATED auto format_to(basic_memory_buffer<Char, SIZE, Allocator>& buf,
|
||||||
|
const S& format_str, Args&&... args) ->
|
||||||
|
typename buffer_context<Char>::iterator {
|
||||||
|
const auto& vargs = fmt::make_args_checked<Args...>(format_str, args...);
|
||||||
|
detail::vformat_to(buf, to_string_view(format_str), vargs, {});
|
||||||
|
return detail::buffer_appender<Char>(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Locale, typename S, typename OutputIt, typename... Args,
|
||||||
|
typename Char = char_t<S>,
|
||||||
|
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value&&
|
||||||
|
detail::is_locale<Locale>::value&&
|
||||||
|
detail::is_exotic_char<Char>::value)>
|
||||||
|
inline auto vformat_to(
|
||||||
|
OutputIt out, const Locale& loc, const S& format_str,
|
||||||
|
basic_format_args<buffer_context<type_identity_t<Char>>> args) -> OutputIt {
|
||||||
|
auto&& buf = detail::get_buffer<Char>(out);
|
||||||
|
vformat_to(buf, to_string_view(format_str), args, detail::locale_ref(loc));
|
||||||
|
return detail::get_iterator(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <
|
||||||
|
typename OutputIt, typename Locale, typename S, typename... Args,
|
||||||
|
typename Char = char_t<S>,
|
||||||
|
bool enable = detail::is_output_iterator<OutputIt, Char>::value&&
|
||||||
|
detail::is_locale<Locale>::value&& detail::is_exotic_char<Char>::value>
|
||||||
|
inline auto format_to(OutputIt out, const Locale& loc, const S& format_str,
|
||||||
|
Args&&... args) ->
|
||||||
|
typename std::enable_if<enable, OutputIt>::type {
|
||||||
|
const auto& vargs = fmt::make_args_checked<Args...>(format_str, args...);
|
||||||
|
return vformat_to(out, loc, to_string_view(format_str), vargs);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename OutputIt, typename Char, typename... Args,
|
||||||
|
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value&&
|
||||||
|
detail::is_exotic_char<Char>::value)>
|
||||||
|
inline auto vformat_to_n(
|
||||||
|
OutputIt out, size_t n, basic_string_view<Char> format_str,
|
||||||
|
basic_format_args<buffer_context<type_identity_t<Char>>> args)
|
||||||
|
-> format_to_n_result<OutputIt> {
|
||||||
|
detail::iterator_buffer<OutputIt, Char, detail::fixed_buffer_traits> buf(out,
|
||||||
|
n);
|
||||||
|
detail::vformat_to(buf, format_str, args);
|
||||||
|
return {buf.out(), buf.count()};
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename OutputIt, typename S, typename... Args,
|
||||||
|
typename Char = char_t<S>,
|
||||||
|
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value&&
|
||||||
|
detail::is_exotic_char<Char>::value)>
|
||||||
|
inline auto format_to_n(OutputIt out, size_t n, const S& fmt,
|
||||||
|
const Args&... args) -> format_to_n_result<OutputIt> {
|
||||||
|
const auto& vargs = fmt::make_args_checked<Args...>(fmt, args...);
|
||||||
|
return vformat_to_n(out, n, to_string_view(fmt), vargs);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename S, typename... Args, typename Char = char_t<S>,
|
||||||
|
FMT_ENABLE_IF(detail::is_exotic_char<Char>::value)>
|
||||||
|
inline auto formatted_size(const S& fmt, Args&&... args) -> size_t {
|
||||||
|
detail::counting_buffer<Char> buf;
|
||||||
|
const auto& vargs = fmt::make_args_checked<Args...>(fmt, args...);
|
||||||
|
detail::vformat_to(buf, to_string_view(fmt), vargs);
|
||||||
|
return buf.count();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void vprint(std::FILE* f, wstring_view fmt, wformat_args args) {
|
||||||
|
wmemory_buffer buffer;
|
||||||
|
detail::vformat_to(buffer, fmt, args);
|
||||||
|
buffer.push_back(L'\0');
|
||||||
|
if (std::fputws(buffer.data(), f) == -1)
|
||||||
|
FMT_THROW(system_error(errno, FMT_STRING("cannot write to file")));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void vprint(wstring_view fmt, wformat_args args) {
|
||||||
|
vprint(stdout, fmt, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename... T>
|
||||||
|
void print(std::FILE* f, wformat_string<T...> fmt, T&&... args) {
|
||||||
|
return vprint(f, wstring_view(fmt), make_wformat_args(args...));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename... T> void print(wformat_string<T...> fmt, T&&... args) {
|
||||||
|
return vprint(wstring_view(fmt), make_wformat_args(args...));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Converts *value* to ``std::wstring`` using the default format for type *T*.
|
||||||
|
*/
|
||||||
|
template <typename T> inline auto to_wstring(const T& value) -> std::wstring {
|
||||||
|
return format(FMT_STRING(L"{}"), value);
|
||||||
|
}
|
||||||
|
FMT_MODULE_EXPORT_END
|
||||||
|
FMT_END_NAMESPACE
|
||||||
|
|
||||||
|
#endif // FMT_WCHAR_H_
|
||||||
20
thirdparty/spdlog/fmt/chrono.h
vendored
Normal file
20
thirdparty/spdlog/fmt/chrono.h
vendored
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
//
|
||||||
|
// Copyright(c) 2016 Gabi Melman.
|
||||||
|
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||||
|
//
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
//
|
||||||
|
// include bundled or external copy of fmtlib's chrono support
|
||||||
|
//
|
||||||
|
|
||||||
|
#if !defined(SPDLOG_FMT_EXTERNAL)
|
||||||
|
# ifdef SPDLOG_HEADER_ONLY
|
||||||
|
# ifndef FMT_HEADER_ONLY
|
||||||
|
# define FMT_HEADER_ONLY
|
||||||
|
# endif
|
||||||
|
# endif
|
||||||
|
# include <spdlog/fmt/bundled/chrono.h>
|
||||||
|
#else
|
||||||
|
# include <fmt/chrono.h>
|
||||||
|
#endif
|
||||||
20
thirdparty/spdlog/fmt/compile.h
vendored
Normal file
20
thirdparty/spdlog/fmt/compile.h
vendored
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
//
|
||||||
|
// Copyright(c) 2016 Gabi Melman.
|
||||||
|
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||||
|
//
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
//
|
||||||
|
// include bundled or external copy of fmtlib's ostream support
|
||||||
|
//
|
||||||
|
|
||||||
|
#if !defined(SPDLOG_FMT_EXTERNAL)
|
||||||
|
# ifdef SPDLOG_HEADER_ONLY
|
||||||
|
# ifndef FMT_HEADER_ONLY
|
||||||
|
# define FMT_HEADER_ONLY
|
||||||
|
# endif
|
||||||
|
# endif
|
||||||
|
# include <spdlog/fmt/bundled/compile.h>
|
||||||
|
#else
|
||||||
|
# include <fmt/compile.h>
|
||||||
|
#endif
|
||||||
27
thirdparty/spdlog/fmt/fmt.h
vendored
Normal file
27
thirdparty/spdlog/fmt/fmt.h
vendored
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
//
|
||||||
|
// Copyright(c) 2016-2018 Gabi Melman.
|
||||||
|
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||||
|
//
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
//
|
||||||
|
// Include a bundled header-only copy of fmtlib or an external one.
|
||||||
|
// By default spdlog include its own copy.
|
||||||
|
//
|
||||||
|
|
||||||
|
#if !defined(SPDLOG_FMT_EXTERNAL)
|
||||||
|
# if !defined(SPDLOG_COMPILED_LIB) && !defined(FMT_HEADER_ONLY)
|
||||||
|
# define FMT_HEADER_ONLY
|
||||||
|
# endif
|
||||||
|
# ifndef FMT_USE_WINDOWS_H
|
||||||
|
# define FMT_USE_WINDOWS_H 0
|
||||||
|
# endif
|
||||||
|
// enable the 'n' flag in for backward compatibility with fmt 6.x
|
||||||
|
# define FMT_DEPRECATED_N_SPECIFIER
|
||||||
|
# include <spdlog/fmt/bundled/core.h>
|
||||||
|
# include <spdlog/fmt/bundled/format.h>
|
||||||
|
#else // SPDLOG_FMT_EXTERNAL is defined - use external fmtlib
|
||||||
|
# include <fmt/core.h>
|
||||||
|
# include <fmt/format.h>
|
||||||
|
#endif
|
||||||
20
thirdparty/spdlog/fmt/ostr.h
vendored
Normal file
20
thirdparty/spdlog/fmt/ostr.h
vendored
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
//
|
||||||
|
// Copyright(c) 2016 Gabi Melman.
|
||||||
|
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||||
|
//
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
//
|
||||||
|
// include bundled or external copy of fmtlib's ostream support
|
||||||
|
//
|
||||||
|
|
||||||
|
#if !defined(SPDLOG_FMT_EXTERNAL)
|
||||||
|
# ifdef SPDLOG_HEADER_ONLY
|
||||||
|
# ifndef FMT_HEADER_ONLY
|
||||||
|
# define FMT_HEADER_ONLY
|
||||||
|
# endif
|
||||||
|
# endif
|
||||||
|
# include <spdlog/fmt/bundled/ostream.h>
|
||||||
|
#else
|
||||||
|
# include <fmt/ostream.h>
|
||||||
|
#endif
|
||||||
20
thirdparty/spdlog/fmt/xchar.h
vendored
Normal file
20
thirdparty/spdlog/fmt/xchar.h
vendored
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
//
|
||||||
|
// Copyright(c) 2016 Gabi Melman.
|
||||||
|
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||||
|
//
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
//
|
||||||
|
// include bundled or external copy of fmtlib's ostream support
|
||||||
|
//
|
||||||
|
|
||||||
|
#if !defined(SPDLOG_FMT_EXTERNAL)
|
||||||
|
# ifdef SPDLOG_HEADER_ONLY
|
||||||
|
# ifndef FMT_HEADER_ONLY
|
||||||
|
# define FMT_HEADER_ONLY
|
||||||
|
# endif
|
||||||
|
# endif
|
||||||
|
# include <spdlog/fmt/bundled/xchar.h>
|
||||||
|
#else
|
||||||
|
# include <fmt/xchar.h>
|
||||||
|
#endif
|
||||||
18
thirdparty/spdlog/formatter.h
vendored
Normal file
18
thirdparty/spdlog/formatter.h
vendored
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
|
||||||
|
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <spdlog/fmt/fmt.h>
|
||||||
|
#include <spdlog/details/log_msg.h>
|
||||||
|
|
||||||
|
namespace spdlog {
|
||||||
|
|
||||||
|
class formatter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~formatter() = default;
|
||||||
|
virtual void format(const details::log_msg &msg, memory_buf_t &dest) = 0;
|
||||||
|
virtual std::unique_ptr<formatter> clone() const = 0;
|
||||||
|
};
|
||||||
|
} // namespace spdlog
|
||||||
14
thirdparty/spdlog/fwd.h
vendored
Normal file
14
thirdparty/spdlog/fwd.h
vendored
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
|
||||||
|
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace spdlog {
|
||||||
|
class logger;
|
||||||
|
class formatter;
|
||||||
|
|
||||||
|
namespace sinks {
|
||||||
|
class sink;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace spdlog
|
||||||
257
thirdparty/spdlog/logger-inl.h
vendored
Normal file
257
thirdparty/spdlog/logger-inl.h
vendored
Normal file
@@ -0,0 +1,257 @@
|
|||||||
|
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
|
||||||
|
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifndef SPDLOG_HEADER_ONLY
|
||||||
|
# include <spdlog/logger.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <spdlog/sinks/sink.h>
|
||||||
|
#include <spdlog/details/backtracer.h>
|
||||||
|
#include <spdlog/pattern_formatter.h>
|
||||||
|
|
||||||
|
#include <cstdio>
|
||||||
|
|
||||||
|
namespace spdlog {
|
||||||
|
|
||||||
|
// public methods
|
||||||
|
SPDLOG_INLINE logger::logger(const logger &other)
|
||||||
|
: name_(other.name_)
|
||||||
|
, sinks_(other.sinks_)
|
||||||
|
, level_(other.level_.load(std::memory_order_relaxed))
|
||||||
|
, flush_level_(other.flush_level_.load(std::memory_order_relaxed))
|
||||||
|
, custom_err_handler_(other.custom_err_handler_)
|
||||||
|
, tracer_(other.tracer_)
|
||||||
|
{}
|
||||||
|
|
||||||
|
SPDLOG_INLINE logger::logger(logger &&other) SPDLOG_NOEXCEPT : name_(std::move(other.name_)),
|
||||||
|
sinks_(std::move(other.sinks_)),
|
||||||
|
level_(other.level_.load(std::memory_order_relaxed)),
|
||||||
|
flush_level_(other.flush_level_.load(std::memory_order_relaxed)),
|
||||||
|
custom_err_handler_(std::move(other.custom_err_handler_)),
|
||||||
|
tracer_(std::move(other.tracer_))
|
||||||
|
|
||||||
|
{}
|
||||||
|
|
||||||
|
SPDLOG_INLINE logger &logger::operator=(logger other) SPDLOG_NOEXCEPT
|
||||||
|
{
|
||||||
|
this->swap(other);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
SPDLOG_INLINE void logger::swap(spdlog::logger &other) SPDLOG_NOEXCEPT
|
||||||
|
{
|
||||||
|
name_.swap(other.name_);
|
||||||
|
sinks_.swap(other.sinks_);
|
||||||
|
|
||||||
|
// swap level_
|
||||||
|
auto other_level = other.level_.load();
|
||||||
|
auto my_level = level_.exchange(other_level);
|
||||||
|
other.level_.store(my_level);
|
||||||
|
|
||||||
|
// swap flush level_
|
||||||
|
other_level = other.flush_level_.load();
|
||||||
|
my_level = flush_level_.exchange(other_level);
|
||||||
|
other.flush_level_.store(my_level);
|
||||||
|
|
||||||
|
custom_err_handler_.swap(other.custom_err_handler_);
|
||||||
|
std::swap(tracer_, other.tracer_);
|
||||||
|
}
|
||||||
|
|
||||||
|
SPDLOG_INLINE void swap(logger &a, logger &b)
|
||||||
|
{
|
||||||
|
a.swap(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
SPDLOG_INLINE void logger::set_level(level::level_enum log_level)
|
||||||
|
{
|
||||||
|
level_.store(log_level);
|
||||||
|
}
|
||||||
|
|
||||||
|
SPDLOG_INLINE level::level_enum logger::level() const
|
||||||
|
{
|
||||||
|
return static_cast<level::level_enum>(level_.load(std::memory_order_relaxed));
|
||||||
|
}
|
||||||
|
|
||||||
|
SPDLOG_INLINE const std::string &logger::name() const
|
||||||
|
{
|
||||||
|
return name_;
|
||||||
|
}
|
||||||
|
|
||||||
|
// set formatting for the sinks in this logger.
|
||||||
|
// each sink will get a separate instance of the formatter object.
|
||||||
|
SPDLOG_INLINE void logger::set_formatter(std::unique_ptr<formatter> f)
|
||||||
|
{
|
||||||
|
for (auto it = sinks_.begin(); it != sinks_.end(); ++it)
|
||||||
|
{
|
||||||
|
if (std::next(it) == sinks_.end())
|
||||||
|
{
|
||||||
|
// last element - we can be move it.
|
||||||
|
(*it)->set_formatter(std::move(f));
|
||||||
|
break; // to prevent clang-tidy warning
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
(*it)->set_formatter(f->clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SPDLOG_INLINE void logger::set_pattern(std::string pattern, pattern_time_type time_type)
|
||||||
|
{
|
||||||
|
auto new_formatter = details::make_unique<pattern_formatter>(std::move(pattern), time_type);
|
||||||
|
set_formatter(std::move(new_formatter));
|
||||||
|
}
|
||||||
|
|
||||||
|
// create new backtrace sink and move to it all our child sinks
|
||||||
|
SPDLOG_INLINE void logger::enable_backtrace(size_t n_messages)
|
||||||
|
{
|
||||||
|
tracer_.enable(n_messages);
|
||||||
|
}
|
||||||
|
|
||||||
|
// restore orig sinks and level and delete the backtrace sink
|
||||||
|
SPDLOG_INLINE void logger::disable_backtrace()
|
||||||
|
{
|
||||||
|
tracer_.disable();
|
||||||
|
}
|
||||||
|
|
||||||
|
SPDLOG_INLINE void logger::dump_backtrace()
|
||||||
|
{
|
||||||
|
dump_backtrace_();
|
||||||
|
}
|
||||||
|
|
||||||
|
// flush functions
|
||||||
|
SPDLOG_INLINE void logger::flush()
|
||||||
|
{
|
||||||
|
flush_();
|
||||||
|
}
|
||||||
|
|
||||||
|
SPDLOG_INLINE void logger::flush_on(level::level_enum log_level)
|
||||||
|
{
|
||||||
|
flush_level_.store(log_level);
|
||||||
|
}
|
||||||
|
|
||||||
|
SPDLOG_INLINE level::level_enum logger::flush_level() const
|
||||||
|
{
|
||||||
|
return static_cast<level::level_enum>(flush_level_.load(std::memory_order_relaxed));
|
||||||
|
}
|
||||||
|
|
||||||
|
// sinks
|
||||||
|
SPDLOG_INLINE const std::vector<sink_ptr> &logger::sinks() const
|
||||||
|
{
|
||||||
|
return sinks_;
|
||||||
|
}
|
||||||
|
|
||||||
|
SPDLOG_INLINE std::vector<sink_ptr> &logger::sinks()
|
||||||
|
{
|
||||||
|
return sinks_;
|
||||||
|
}
|
||||||
|
|
||||||
|
// error handler
|
||||||
|
SPDLOG_INLINE void logger::set_error_handler(err_handler handler)
|
||||||
|
{
|
||||||
|
custom_err_handler_ = std::move(handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
// create new logger with same sinks and configuration.
|
||||||
|
SPDLOG_INLINE std::shared_ptr<logger> logger::clone(std::string logger_name)
|
||||||
|
{
|
||||||
|
auto cloned = std::make_shared<logger>(*this);
|
||||||
|
cloned->name_ = std::move(logger_name);
|
||||||
|
return cloned;
|
||||||
|
}
|
||||||
|
|
||||||
|
// protected methods
|
||||||
|
SPDLOG_INLINE void logger::log_it_(const spdlog::details::log_msg &log_msg, bool log_enabled, bool traceback_enabled)
|
||||||
|
{
|
||||||
|
if (log_enabled)
|
||||||
|
{
|
||||||
|
sink_it_(log_msg);
|
||||||
|
}
|
||||||
|
if (traceback_enabled)
|
||||||
|
{
|
||||||
|
tracer_.push_back(log_msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SPDLOG_INLINE void logger::sink_it_(const details::log_msg &msg)
|
||||||
|
{
|
||||||
|
for (auto &sink : sinks_)
|
||||||
|
{
|
||||||
|
if (sink->should_log(msg.level))
|
||||||
|
{
|
||||||
|
SPDLOG_TRY
|
||||||
|
{
|
||||||
|
sink->log(msg);
|
||||||
|
}
|
||||||
|
SPDLOG_LOGGER_CATCH()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (should_flush_(msg))
|
||||||
|
{
|
||||||
|
flush_();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SPDLOG_INLINE void logger::flush_()
|
||||||
|
{
|
||||||
|
for (auto &sink : sinks_)
|
||||||
|
{
|
||||||
|
SPDLOG_TRY
|
||||||
|
{
|
||||||
|
sink->flush();
|
||||||
|
}
|
||||||
|
SPDLOG_LOGGER_CATCH()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SPDLOG_INLINE void logger::dump_backtrace_()
|
||||||
|
{
|
||||||
|
using details::log_msg;
|
||||||
|
if (tracer_.enabled())
|
||||||
|
{
|
||||||
|
sink_it_(log_msg{name(), level::info, "****************** Backtrace Start ******************"});
|
||||||
|
tracer_.foreach_pop([this](const log_msg &msg) { this->sink_it_(msg); });
|
||||||
|
sink_it_(log_msg{name(), level::info, "****************** Backtrace End ********************"});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SPDLOG_INLINE bool logger::should_flush_(const details::log_msg &msg)
|
||||||
|
{
|
||||||
|
auto flush_level = flush_level_.load(std::memory_order_relaxed);
|
||||||
|
return (msg.level >= flush_level) && (msg.level != level::off);
|
||||||
|
}
|
||||||
|
|
||||||
|
SPDLOG_INLINE void logger::err_handler_(const std::string &msg)
|
||||||
|
{
|
||||||
|
if (custom_err_handler_)
|
||||||
|
{
|
||||||
|
custom_err_handler_(msg);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
using std::chrono::system_clock;
|
||||||
|
static std::mutex mutex;
|
||||||
|
static std::chrono::system_clock::time_point last_report_time;
|
||||||
|
static size_t err_counter = 0;
|
||||||
|
std::lock_guard<std::mutex> lk{mutex};
|
||||||
|
auto now = system_clock::now();
|
||||||
|
err_counter++;
|
||||||
|
if (now - last_report_time < std::chrono::seconds(1))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
last_report_time = now;
|
||||||
|
auto tm_time = details::os::localtime(system_clock::to_time_t(now));
|
||||||
|
char date_buf[64];
|
||||||
|
std::strftime(date_buf, sizeof(date_buf), "%Y-%m-%d %H:%M:%S", &tm_time);
|
||||||
|
#if defined(USING_R) && defined(R_R_H) // if in R environment
|
||||||
|
REprintf("[*** LOG ERROR #%04zu ***] [%s] [%s] {%s}\n", err_counter, date_buf, name().c_str(), msg.c_str());
|
||||||
|
#else
|
||||||
|
std::fprintf(stderr, "[*** LOG ERROR #%04zu ***] [%s] [%s] {%s}\n", err_counter, date_buf, name().c_str(), msg.c_str());
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // namespace spdlog
|
||||||
403
thirdparty/spdlog/logger.h
vendored
Normal file
403
thirdparty/spdlog/logger.h
vendored
Normal file
@@ -0,0 +1,403 @@
|
|||||||
|
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
|
||||||
|
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
// Thread safe logger (except for set_error_handler())
|
||||||
|
// Has name, log level, vector of std::shared sink pointers and formatter
|
||||||
|
// Upon each log write the logger:
|
||||||
|
// 1. Checks if its log level is enough to log the message and if yes:
|
||||||
|
// 2. Call the underlying sinks to do the job.
|
||||||
|
// 3. Each sink use its own private copy of a formatter to format the message
|
||||||
|
// and send to its destination.
|
||||||
|
//
|
||||||
|
// The use of private formatter per sink provides the opportunity to cache some
|
||||||
|
// formatted data, and support for different format per sink.
|
||||||
|
|
||||||
|
#include <spdlog/common.h>
|
||||||
|
#include <spdlog/details/log_msg.h>
|
||||||
|
#include <spdlog/details/backtracer.h>
|
||||||
|
|
||||||
|
#ifdef SPDLOG_WCHAR_TO_UTF8_SUPPORT
|
||||||
|
# ifndef _WIN32
|
||||||
|
# error SPDLOG_WCHAR_TO_UTF8_SUPPORT only supported on windows
|
||||||
|
# endif
|
||||||
|
# include <spdlog/details/os.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#ifndef SPDLOG_NO_EXCEPTIONS
|
||||||
|
# define SPDLOG_LOGGER_CATCH() \
|
||||||
|
catch (const std::exception &ex) \
|
||||||
|
{ \
|
||||||
|
err_handler_(ex.what()); \
|
||||||
|
} \
|
||||||
|
catch (...) \
|
||||||
|
{ \
|
||||||
|
err_handler_("Rethrowing unknown exception in logger"); \
|
||||||
|
throw; \
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
# define SPDLOG_LOGGER_CATCH()
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace spdlog {
|
||||||
|
|
||||||
|
class SPDLOG_API logger
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// Empty logger
|
||||||
|
explicit logger(std::string name)
|
||||||
|
: name_(std::move(name))
|
||||||
|
, sinks_()
|
||||||
|
{}
|
||||||
|
|
||||||
|
// Logger with range on sinks
|
||||||
|
template<typename It>
|
||||||
|
logger(std::string name, It begin, It end)
|
||||||
|
: name_(std::move(name))
|
||||||
|
, sinks_(begin, end)
|
||||||
|
{}
|
||||||
|
|
||||||
|
// Logger with single sink
|
||||||
|
logger(std::string name, sink_ptr single_sink)
|
||||||
|
: logger(std::move(name), {std::move(single_sink)})
|
||||||
|
{}
|
||||||
|
|
||||||
|
// Logger with sinks init list
|
||||||
|
logger(std::string name, sinks_init_list sinks)
|
||||||
|
: logger(std::move(name), sinks.begin(), sinks.end())
|
||||||
|
{}
|
||||||
|
|
||||||
|
virtual ~logger() = default;
|
||||||
|
|
||||||
|
logger(const logger &other);
|
||||||
|
logger(logger &&other) SPDLOG_NOEXCEPT;
|
||||||
|
logger &operator=(logger other) SPDLOG_NOEXCEPT;
|
||||||
|
void swap(spdlog::logger &other) SPDLOG_NOEXCEPT;
|
||||||
|
|
||||||
|
template<typename... Args>
|
||||||
|
void log(source_loc loc, level::level_enum lvl, fmt::format_string<Args...> fmt, Args &&...args)
|
||||||
|
{
|
||||||
|
log_(loc, lvl, fmt, std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename... Args>
|
||||||
|
void log(level::level_enum lvl, fmt::format_string<Args...> fmt, Args &&...args)
|
||||||
|
{
|
||||||
|
log(source_loc{}, lvl, fmt, std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void log(level::level_enum lvl, const T &msg)
|
||||||
|
{
|
||||||
|
log(source_loc{}, lvl, msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
// T can be statically converted to string_view
|
||||||
|
template<class T, typename std::enable_if<std::is_convertible<const T &, spdlog::string_view_t>::value, int>::type = 0>
|
||||||
|
void log(source_loc loc, level::level_enum lvl, const T &msg)
|
||||||
|
{
|
||||||
|
log(loc, lvl, string_view_t{msg});
|
||||||
|
}
|
||||||
|
|
||||||
|
// T cannot be statically converted to format string (including string_view)
|
||||||
|
template<class T, typename std::enable_if<!is_convertible_to_any_format_string<const T &>::value, int>::type = 0>
|
||||||
|
void log(source_loc loc, level::level_enum lvl, const T &msg)
|
||||||
|
{
|
||||||
|
log(loc, lvl, "{}", msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void log(log_clock::time_point log_time, source_loc loc, level::level_enum lvl, string_view_t msg)
|
||||||
|
{
|
||||||
|
bool log_enabled = should_log(lvl);
|
||||||
|
bool traceback_enabled = tracer_.enabled();
|
||||||
|
if (!log_enabled && !traceback_enabled)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
details::log_msg log_msg(log_time, loc, name_, lvl, msg);
|
||||||
|
log_it_(log_msg, log_enabled, traceback_enabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
void log(source_loc loc, level::level_enum lvl, string_view_t msg)
|
||||||
|
{
|
||||||
|
bool log_enabled = should_log(lvl);
|
||||||
|
bool traceback_enabled = tracer_.enabled();
|
||||||
|
if (!log_enabled && !traceback_enabled)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
details::log_msg log_msg(loc, name_, lvl, msg);
|
||||||
|
log_it_(log_msg, log_enabled, traceback_enabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
void log(level::level_enum lvl, string_view_t msg)
|
||||||
|
{
|
||||||
|
log(source_loc{}, lvl, msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename... Args>
|
||||||
|
void trace(fmt::format_string<Args...> fmt, Args &&...args)
|
||||||
|
{
|
||||||
|
log(level::trace, fmt, std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename... Args>
|
||||||
|
void debug(fmt::format_string<Args...> fmt, Args &&...args)
|
||||||
|
{
|
||||||
|
log(level::debug, fmt, std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename... Args>
|
||||||
|
void info(fmt::format_string<Args...> fmt, Args &&...args)
|
||||||
|
{
|
||||||
|
log(level::info, fmt, std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename... Args>
|
||||||
|
void warn(fmt::format_string<Args...> fmt, Args &&...args)
|
||||||
|
{
|
||||||
|
log(level::warn, fmt, std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename... Args>
|
||||||
|
void error(fmt::format_string<Args...> fmt, Args &&...args)
|
||||||
|
{
|
||||||
|
log(level::err, fmt, std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename... Args>
|
||||||
|
void critical(fmt::format_string<Args...> fmt, Args &&...args)
|
||||||
|
{
|
||||||
|
log(level::critical, fmt, std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef SPDLOG_WCHAR_TO_UTF8_SUPPORT
|
||||||
|
template<typename... Args>
|
||||||
|
void log(level::level_enum lvl, fmt::wformat_string<Args...> fmt, Args &&...args)
|
||||||
|
{
|
||||||
|
log(source_loc{}, lvl, fmt, std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename... Args>
|
||||||
|
void log(source_loc loc, level::level_enum lvl, fmt::wformat_string<Args...> fmt, Args &&...args)
|
||||||
|
{
|
||||||
|
log_(loc, lvl, fmt, std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename... Args>
|
||||||
|
void trace(fmt::wformat_string<Args...> fmt, Args &&...args)
|
||||||
|
{
|
||||||
|
log(level::trace, fmt, std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename... Args>
|
||||||
|
void debug(fmt::wformat_string<Args...> fmt, Args &&...args)
|
||||||
|
{
|
||||||
|
log(level::debug, fmt, std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename... Args>
|
||||||
|
void info(fmt::wformat_string<Args...> fmt, Args &&...args)
|
||||||
|
{
|
||||||
|
log(level::info, fmt, std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename... Args>
|
||||||
|
void warn(fmt::wformat_string<Args...> fmt, Args &&...args)
|
||||||
|
{
|
||||||
|
log(level::warn, fmt, std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename... Args>
|
||||||
|
void error(fmt::wformat_string<Args...> fmt, Args &&...args)
|
||||||
|
{
|
||||||
|
log(level::err, fmt, std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename... Args>
|
||||||
|
void critical(fmt::wformat_string<Args...> fmt, Args &&...args)
|
||||||
|
{
|
||||||
|
log(level::critical, fmt, std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void trace(const T &msg)
|
||||||
|
{
|
||||||
|
log(level::trace, msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void debug(const T &msg)
|
||||||
|
{
|
||||||
|
log(level::debug, msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void info(const T &msg)
|
||||||
|
{
|
||||||
|
log(level::info, msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void warn(const T &msg)
|
||||||
|
{
|
||||||
|
log(level::warn, msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void error(const T &msg)
|
||||||
|
{
|
||||||
|
log(level::err, msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void critical(const T &msg)
|
||||||
|
{
|
||||||
|
log(level::critical, msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
// return true logging is enabled for the given level.
|
||||||
|
bool should_log(level::level_enum msg_level) const
|
||||||
|
{
|
||||||
|
return msg_level >= level_.load(std::memory_order_relaxed);
|
||||||
|
}
|
||||||
|
|
||||||
|
// return true if backtrace logging is enabled.
|
||||||
|
bool should_backtrace() const
|
||||||
|
{
|
||||||
|
return tracer_.enabled();
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_level(level::level_enum log_level);
|
||||||
|
|
||||||
|
level::level_enum level() const;
|
||||||
|
|
||||||
|
const std::string &name() const;
|
||||||
|
|
||||||
|
// set formatting for the sinks in this logger.
|
||||||
|
// each sink will get a separate instance of the formatter object.
|
||||||
|
void set_formatter(std::unique_ptr<formatter> f);
|
||||||
|
|
||||||
|
void set_pattern(std::string pattern, pattern_time_type time_type = pattern_time_type::local);
|
||||||
|
|
||||||
|
// backtrace support.
|
||||||
|
// efficiently store all debug/trace messages in a circular buffer until needed for debugging.
|
||||||
|
void enable_backtrace(size_t n_messages);
|
||||||
|
void disable_backtrace();
|
||||||
|
void dump_backtrace();
|
||||||
|
|
||||||
|
// flush functions
|
||||||
|
void flush();
|
||||||
|
void flush_on(level::level_enum log_level);
|
||||||
|
level::level_enum flush_level() const;
|
||||||
|
|
||||||
|
// sinks
|
||||||
|
const std::vector<sink_ptr> &sinks() const;
|
||||||
|
|
||||||
|
std::vector<sink_ptr> &sinks();
|
||||||
|
|
||||||
|
// error handler
|
||||||
|
void set_error_handler(err_handler);
|
||||||
|
|
||||||
|
// create new logger with same sinks and configuration.
|
||||||
|
virtual std::shared_ptr<logger> clone(std::string logger_name);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
std::string name_;
|
||||||
|
std::vector<sink_ptr> sinks_;
|
||||||
|
spdlog::level_t level_{level::info};
|
||||||
|
spdlog::level_t flush_level_{level::off};
|
||||||
|
err_handler custom_err_handler_{nullptr};
|
||||||
|
details::backtracer tracer_;
|
||||||
|
|
||||||
|
// common implementation for after templated public api has been resolved
|
||||||
|
template<typename... Args>
|
||||||
|
void log_(source_loc loc, level::level_enum lvl, string_view_t fmt, Args &&...args)
|
||||||
|
{
|
||||||
|
bool log_enabled = should_log(lvl);
|
||||||
|
bool traceback_enabled = tracer_.enabled();
|
||||||
|
if (!log_enabled && !traceback_enabled)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
SPDLOG_TRY
|
||||||
|
{
|
||||||
|
memory_buf_t buf;
|
||||||
|
fmt::detail::vformat_to(buf, fmt, fmt::make_format_args(args...));
|
||||||
|
details::log_msg log_msg(loc, name_, lvl, string_view_t(buf.data(), buf.size()));
|
||||||
|
log_it_(log_msg, log_enabled, traceback_enabled);
|
||||||
|
}
|
||||||
|
SPDLOG_LOGGER_CATCH()
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef SPDLOG_WCHAR_TO_UTF8_SUPPORT
|
||||||
|
template<typename... Args>
|
||||||
|
void log_(source_loc loc, level::level_enum lvl, wstring_view_t fmt, Args &&...args)
|
||||||
|
{
|
||||||
|
bool log_enabled = should_log(lvl);
|
||||||
|
bool traceback_enabled = tracer_.enabled();
|
||||||
|
if (!log_enabled && !traceback_enabled)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
SPDLOG_TRY
|
||||||
|
{
|
||||||
|
// format to wmemory_buffer and convert to utf8
|
||||||
|
fmt::wmemory_buffer wbuf;
|
||||||
|
fmt::detail::vformat_to(wbuf, fmt, fmt::make_format_args<fmt::wformat_context>(args...));
|
||||||
|
memory_buf_t buf;
|
||||||
|
details::os::wstr_to_utf8buf(wstring_view_t(wbuf.data(), wbuf.size()), buf);
|
||||||
|
details::log_msg log_msg(loc, name_, lvl, string_view_t(buf.data(), buf.size()));
|
||||||
|
log_it_(log_msg, log_enabled, traceback_enabled);
|
||||||
|
}
|
||||||
|
SPDLOG_LOGGER_CATCH()
|
||||||
|
}
|
||||||
|
|
||||||
|
// T can be statically converted to wstring_view, and no formatting needed.
|
||||||
|
template<class T, typename std::enable_if<std::is_convertible<const T &, spdlog::wstring_view_t>::value, int>::type = 0>
|
||||||
|
void log_(source_loc loc, level::level_enum lvl, const T &msg)
|
||||||
|
{
|
||||||
|
bool log_enabled = should_log(lvl);
|
||||||
|
bool traceback_enabled = tracer_.enabled();
|
||||||
|
if (!log_enabled && !traceback_enabled)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
SPDLOG_TRY
|
||||||
|
{
|
||||||
|
memory_buf_t buf;
|
||||||
|
details::os::wstr_to_utf8buf(msg, buf);
|
||||||
|
details::log_msg log_msg(loc, name_, lvl, string_view_t(buf.data(), buf.size()));
|
||||||
|
log_it_(log_msg, log_enabled, traceback_enabled);
|
||||||
|
}
|
||||||
|
SPDLOG_LOGGER_CATCH()
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // SPDLOG_WCHAR_TO_UTF8_SUPPORT
|
||||||
|
|
||||||
|
// log the given message (if the given log level is high enough),
|
||||||
|
// and save backtrace (if backtrace is enabled).
|
||||||
|
void log_it_(const details::log_msg &log_msg, bool log_enabled, bool traceback_enabled);
|
||||||
|
virtual void sink_it_(const details::log_msg &msg);
|
||||||
|
virtual void flush_();
|
||||||
|
void dump_backtrace_();
|
||||||
|
bool should_flush_(const details::log_msg &msg);
|
||||||
|
|
||||||
|
// handle errors during logging.
|
||||||
|
// default handler prints the error to stderr at max rate of 1 message/sec.
|
||||||
|
void err_handler_(const std::string &msg);
|
||||||
|
};
|
||||||
|
|
||||||
|
void swap(logger &a, logger &b);
|
||||||
|
|
||||||
|
} // namespace spdlog
|
||||||
|
|
||||||
|
#ifdef SPDLOG_HEADER_ONLY
|
||||||
|
# include "logger-inl.h"
|
||||||
|
#endif
|
||||||
1395
thirdparty/spdlog/pattern_formatter-inl.h
vendored
Normal file
1395
thirdparty/spdlog/pattern_formatter-inl.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
126
thirdparty/spdlog/pattern_formatter.h
vendored
Normal file
126
thirdparty/spdlog/pattern_formatter.h
vendored
Normal file
@@ -0,0 +1,126 @@
|
|||||||
|
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
|
||||||
|
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <spdlog/common.h>
|
||||||
|
#include <spdlog/details/log_msg.h>
|
||||||
|
#include <spdlog/details/os.h>
|
||||||
|
#include <spdlog/formatter.h>
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
#include <ctime>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
|
namespace spdlog {
|
||||||
|
namespace details {
|
||||||
|
|
||||||
|
// padding information.
|
||||||
|
struct padding_info
|
||||||
|
{
|
||||||
|
enum class pad_side
|
||||||
|
{
|
||||||
|
left,
|
||||||
|
right,
|
||||||
|
center
|
||||||
|
};
|
||||||
|
|
||||||
|
padding_info() = default;
|
||||||
|
padding_info(size_t width, padding_info::pad_side side, bool truncate)
|
||||||
|
: width_(width)
|
||||||
|
, side_(side)
|
||||||
|
, truncate_(truncate)
|
||||||
|
, enabled_(true)
|
||||||
|
{}
|
||||||
|
|
||||||
|
bool enabled() const
|
||||||
|
{
|
||||||
|
return enabled_;
|
||||||
|
}
|
||||||
|
size_t width_ = 0;
|
||||||
|
pad_side side_ = pad_side::left;
|
||||||
|
bool truncate_ = false;
|
||||||
|
bool enabled_ = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
class SPDLOG_API flag_formatter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit flag_formatter(padding_info padinfo)
|
||||||
|
: padinfo_(padinfo)
|
||||||
|
{}
|
||||||
|
flag_formatter() = default;
|
||||||
|
virtual ~flag_formatter() = default;
|
||||||
|
virtual void format(const details::log_msg &msg, const std::tm &tm_time, memory_buf_t &dest) = 0;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
padding_info padinfo_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace details
|
||||||
|
|
||||||
|
class SPDLOG_API custom_flag_formatter : public details::flag_formatter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual std::unique_ptr<custom_flag_formatter> clone() const = 0;
|
||||||
|
|
||||||
|
void set_padding_info(details::padding_info padding)
|
||||||
|
{
|
||||||
|
flag_formatter::padinfo_ = padding;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class SPDLOG_API pattern_formatter final : public formatter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using custom_flags = std::unordered_map<char, std::unique_ptr<custom_flag_formatter>>;
|
||||||
|
|
||||||
|
explicit pattern_formatter(std::string pattern, pattern_time_type time_type = pattern_time_type::local,
|
||||||
|
std::string eol = spdlog::details::os::default_eol, custom_flags custom_user_flags = custom_flags());
|
||||||
|
|
||||||
|
// use default pattern is not given
|
||||||
|
explicit pattern_formatter(pattern_time_type time_type = pattern_time_type::local, std::string eol = spdlog::details::os::default_eol);
|
||||||
|
|
||||||
|
pattern_formatter(const pattern_formatter &other) = delete;
|
||||||
|
pattern_formatter &operator=(const pattern_formatter &other) = delete;
|
||||||
|
|
||||||
|
std::unique_ptr<formatter> clone() const override;
|
||||||
|
void format(const details::log_msg &msg, memory_buf_t &dest) override;
|
||||||
|
|
||||||
|
template<typename T, typename... Args>
|
||||||
|
pattern_formatter &add_flag(char flag, Args &&...args)
|
||||||
|
{
|
||||||
|
custom_handlers_[flag] = details::make_unique<T>(std::forward<Args>(args)...);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
void set_pattern(std::string pattern);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string pattern_;
|
||||||
|
std::string eol_;
|
||||||
|
pattern_time_type pattern_time_type_;
|
||||||
|
std::tm cached_tm_;
|
||||||
|
std::chrono::seconds last_log_secs_;
|
||||||
|
std::vector<std::unique_ptr<details::flag_formatter>> formatters_;
|
||||||
|
custom_flags custom_handlers_;
|
||||||
|
|
||||||
|
std::tm get_time_(const details::log_msg &msg);
|
||||||
|
template<typename Padder>
|
||||||
|
void handle_flag_(char flag, details::padding_info padding);
|
||||||
|
|
||||||
|
// Extract given pad spec (e.g. %8X)
|
||||||
|
// Advance the given it pass the end of the padding spec found (if any)
|
||||||
|
// Return padding.
|
||||||
|
static details::padding_info handle_padspec_(std::string::const_iterator &it, std::string::const_iterator end);
|
||||||
|
|
||||||
|
void compile_pattern_(const std::string &pattern);
|
||||||
|
};
|
||||||
|
} // namespace spdlog
|
||||||
|
|
||||||
|
#ifdef SPDLOG_HEADER_ONLY
|
||||||
|
# include "pattern_formatter-inl.h"
|
||||||
|
#endif
|
||||||
119
thirdparty/spdlog/sinks/android_sink.h
vendored
Normal file
119
thirdparty/spdlog/sinks/android_sink.h
vendored
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
|
||||||
|
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifdef __ANDROID__
|
||||||
|
|
||||||
|
# include <spdlog/details/fmt_helper.h>
|
||||||
|
# include <spdlog/details/null_mutex.h>
|
||||||
|
# include <spdlog/details/os.h>
|
||||||
|
# include <spdlog/sinks/base_sink.h>
|
||||||
|
# include <spdlog/details/synchronous_factory.h>
|
||||||
|
|
||||||
|
# include <android/log.h>
|
||||||
|
# include <chrono>
|
||||||
|
# include <mutex>
|
||||||
|
# include <string>
|
||||||
|
# include <thread>
|
||||||
|
|
||||||
|
# if !defined(SPDLOG_ANDROID_RETRIES)
|
||||||
|
# define SPDLOG_ANDROID_RETRIES 2
|
||||||
|
# endif
|
||||||
|
|
||||||
|
namespace spdlog {
|
||||||
|
namespace sinks {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Android sink (logging using __android_log_write)
|
||||||
|
*/
|
||||||
|
template<typename Mutex>
|
||||||
|
class android_sink final : public base_sink<Mutex>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit android_sink(std::string tag = "spdlog", bool use_raw_msg = false)
|
||||||
|
: tag_(std::move(tag))
|
||||||
|
, use_raw_msg_(use_raw_msg)
|
||||||
|
{}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void sink_it_(const details::log_msg &msg) override
|
||||||
|
{
|
||||||
|
const android_LogPriority priority = convert_to_android_(msg.level);
|
||||||
|
memory_buf_t formatted;
|
||||||
|
if (use_raw_msg_)
|
||||||
|
{
|
||||||
|
details::fmt_helper::append_string_view(msg.payload, formatted);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
base_sink<Mutex>::formatter_->format(msg, formatted);
|
||||||
|
}
|
||||||
|
formatted.push_back('\0');
|
||||||
|
const char *msg_output = formatted.data();
|
||||||
|
|
||||||
|
// See system/core/liblog/logger_write.c for explanation of return value
|
||||||
|
int ret = __android_log_write(priority, tag_.c_str(), msg_output);
|
||||||
|
int retry_count = 0;
|
||||||
|
while ((ret == -11 /*EAGAIN*/) && (retry_count < SPDLOG_ANDROID_RETRIES))
|
||||||
|
{
|
||||||
|
details::os::sleep_for_millis(5);
|
||||||
|
ret = __android_log_write(priority, tag_.c_str(), msg_output);
|
||||||
|
retry_count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret < 0)
|
||||||
|
{
|
||||||
|
throw_spdlog_ex("__android_log_write() failed", ret);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void flush_() override {}
|
||||||
|
|
||||||
|
private:
|
||||||
|
static android_LogPriority convert_to_android_(spdlog::level::level_enum level)
|
||||||
|
{
|
||||||
|
switch (level)
|
||||||
|
{
|
||||||
|
case spdlog::level::trace:
|
||||||
|
return ANDROID_LOG_VERBOSE;
|
||||||
|
case spdlog::level::debug:
|
||||||
|
return ANDROID_LOG_DEBUG;
|
||||||
|
case spdlog::level::info:
|
||||||
|
return ANDROID_LOG_INFO;
|
||||||
|
case spdlog::level::warn:
|
||||||
|
return ANDROID_LOG_WARN;
|
||||||
|
case spdlog::level::err:
|
||||||
|
return ANDROID_LOG_ERROR;
|
||||||
|
case spdlog::level::critical:
|
||||||
|
return ANDROID_LOG_FATAL;
|
||||||
|
default:
|
||||||
|
return ANDROID_LOG_DEFAULT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string tag_;
|
||||||
|
bool use_raw_msg_;
|
||||||
|
};
|
||||||
|
|
||||||
|
using android_sink_mt = android_sink<std::mutex>;
|
||||||
|
using android_sink_st = android_sink<details::null_mutex>;
|
||||||
|
} // namespace sinks
|
||||||
|
|
||||||
|
// Create and register android syslog logger
|
||||||
|
|
||||||
|
template<typename Factory = spdlog::synchronous_factory>
|
||||||
|
inline std::shared_ptr<logger> android_logger_mt(const std::string &logger_name, const std::string &tag = "spdlog")
|
||||||
|
{
|
||||||
|
return Factory::template create<sinks::android_sink_mt>(logger_name, tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Factory = spdlog::synchronous_factory>
|
||||||
|
inline std::shared_ptr<logger> android_logger_st(const std::string &logger_name, const std::string &tag = "spdlog")
|
||||||
|
{
|
||||||
|
return Factory::template create<sinks::android_sink_st>(logger_name, tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace spdlog
|
||||||
|
|
||||||
|
#endif // __ANDROID__
|
||||||
145
thirdparty/spdlog/sinks/ansicolor_sink-inl.h
vendored
Normal file
145
thirdparty/spdlog/sinks/ansicolor_sink-inl.h
vendored
Normal file
@@ -0,0 +1,145 @@
|
|||||||
|
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
|
||||||
|
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifndef SPDLOG_HEADER_ONLY
|
||||||
|
# include <spdlog/sinks/ansicolor_sink.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <spdlog/pattern_formatter.h>
|
||||||
|
#include <spdlog/details/os.h>
|
||||||
|
|
||||||
|
namespace spdlog {
|
||||||
|
namespace sinks {
|
||||||
|
|
||||||
|
template<typename ConsoleMutex>
|
||||||
|
SPDLOG_INLINE ansicolor_sink<ConsoleMutex>::ansicolor_sink(FILE *target_file, color_mode mode)
|
||||||
|
: target_file_(target_file)
|
||||||
|
, mutex_(ConsoleMutex::mutex())
|
||||||
|
, formatter_(details::make_unique<spdlog::pattern_formatter>())
|
||||||
|
|
||||||
|
{
|
||||||
|
set_color_mode(mode);
|
||||||
|
colors_[level::trace] = to_string_(white);
|
||||||
|
colors_[level::debug] = to_string_(cyan);
|
||||||
|
colors_[level::info] = to_string_(green);
|
||||||
|
colors_[level::warn] = to_string_(yellow_bold);
|
||||||
|
colors_[level::err] = to_string_(red_bold);
|
||||||
|
colors_[level::critical] = to_string_(bold_on_red);
|
||||||
|
colors_[level::off] = to_string_(reset);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename ConsoleMutex>
|
||||||
|
SPDLOG_INLINE void ansicolor_sink<ConsoleMutex>::set_color(level::level_enum color_level, string_view_t color)
|
||||||
|
{
|
||||||
|
std::lock_guard<mutex_t> lock(mutex_);
|
||||||
|
colors_[color_level] = to_string_(color);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename ConsoleMutex>
|
||||||
|
SPDLOG_INLINE void ansicolor_sink<ConsoleMutex>::log(const details::log_msg &msg)
|
||||||
|
{
|
||||||
|
// Wrap the originally formatted message in color codes.
|
||||||
|
// If color is not supported in the terminal, log as is instead.
|
||||||
|
std::lock_guard<mutex_t> lock(mutex_);
|
||||||
|
msg.color_range_start = 0;
|
||||||
|
msg.color_range_end = 0;
|
||||||
|
memory_buf_t formatted;
|
||||||
|
formatter_->format(msg, formatted);
|
||||||
|
if (should_do_colors_ && msg.color_range_end > msg.color_range_start)
|
||||||
|
{
|
||||||
|
// before color range
|
||||||
|
print_range_(formatted, 0, msg.color_range_start);
|
||||||
|
// in color range
|
||||||
|
print_ccode_(colors_[msg.level]);
|
||||||
|
print_range_(formatted, msg.color_range_start, msg.color_range_end);
|
||||||
|
print_ccode_(reset);
|
||||||
|
// after color range
|
||||||
|
print_range_(formatted, msg.color_range_end, formatted.size());
|
||||||
|
}
|
||||||
|
else // no color
|
||||||
|
{
|
||||||
|
print_range_(formatted, 0, formatted.size());
|
||||||
|
}
|
||||||
|
fflush(target_file_);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename ConsoleMutex>
|
||||||
|
SPDLOG_INLINE void ansicolor_sink<ConsoleMutex>::flush()
|
||||||
|
{
|
||||||
|
std::lock_guard<mutex_t> lock(mutex_);
|
||||||
|
fflush(target_file_);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename ConsoleMutex>
|
||||||
|
SPDLOG_INLINE void ansicolor_sink<ConsoleMutex>::set_pattern(const std::string &pattern)
|
||||||
|
{
|
||||||
|
std::lock_guard<mutex_t> lock(mutex_);
|
||||||
|
formatter_ = std::unique_ptr<spdlog::formatter>(new pattern_formatter(pattern));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename ConsoleMutex>
|
||||||
|
SPDLOG_INLINE void ansicolor_sink<ConsoleMutex>::set_formatter(std::unique_ptr<spdlog::formatter> sink_formatter)
|
||||||
|
{
|
||||||
|
std::lock_guard<mutex_t> lock(mutex_);
|
||||||
|
formatter_ = std::move(sink_formatter);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename ConsoleMutex>
|
||||||
|
SPDLOG_INLINE bool ansicolor_sink<ConsoleMutex>::should_color()
|
||||||
|
{
|
||||||
|
return should_do_colors_;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename ConsoleMutex>
|
||||||
|
SPDLOG_INLINE void ansicolor_sink<ConsoleMutex>::set_color_mode(color_mode mode)
|
||||||
|
{
|
||||||
|
switch (mode)
|
||||||
|
{
|
||||||
|
case color_mode::always:
|
||||||
|
should_do_colors_ = true;
|
||||||
|
return;
|
||||||
|
case color_mode::automatic:
|
||||||
|
should_do_colors_ = details::os::in_terminal(target_file_) && details::os::is_color_terminal();
|
||||||
|
return;
|
||||||
|
case color_mode::never:
|
||||||
|
should_do_colors_ = false;
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
should_do_colors_ = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename ConsoleMutex>
|
||||||
|
SPDLOG_INLINE void ansicolor_sink<ConsoleMutex>::print_ccode_(const string_view_t &color_code)
|
||||||
|
{
|
||||||
|
fwrite(color_code.data(), sizeof(char), color_code.size(), target_file_);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename ConsoleMutex>
|
||||||
|
SPDLOG_INLINE void ansicolor_sink<ConsoleMutex>::print_range_(const memory_buf_t &formatted, size_t start, size_t end)
|
||||||
|
{
|
||||||
|
fwrite(formatted.data() + start, sizeof(char), end - start, target_file_);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename ConsoleMutex>
|
||||||
|
SPDLOG_INLINE std::string ansicolor_sink<ConsoleMutex>::to_string_(const string_view_t &sv)
|
||||||
|
{
|
||||||
|
return std::string(sv.data(), sv.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
// ansicolor_stdout_sink
|
||||||
|
template<typename ConsoleMutex>
|
||||||
|
SPDLOG_INLINE ansicolor_stdout_sink<ConsoleMutex>::ansicolor_stdout_sink(color_mode mode)
|
||||||
|
: ansicolor_sink<ConsoleMutex>(stdout, mode)
|
||||||
|
{}
|
||||||
|
|
||||||
|
// ansicolor_stderr_sink
|
||||||
|
template<typename ConsoleMutex>
|
||||||
|
SPDLOG_INLINE ansicolor_stderr_sink<ConsoleMutex>::ansicolor_stderr_sink(color_mode mode)
|
||||||
|
: ansicolor_sink<ConsoleMutex>(stderr, mode)
|
||||||
|
{}
|
||||||
|
|
||||||
|
} // namespace sinks
|
||||||
|
} // namespace spdlog
|
||||||
118
thirdparty/spdlog/sinks/ansicolor_sink.h
vendored
Normal file
118
thirdparty/spdlog/sinks/ansicolor_sink.h
vendored
Normal file
@@ -0,0 +1,118 @@
|
|||||||
|
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
|
||||||
|
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <spdlog/details/console_globals.h>
|
||||||
|
#include <spdlog/details/null_mutex.h>
|
||||||
|
#include <spdlog/sinks/sink.h>
|
||||||
|
#include <memory>
|
||||||
|
#include <mutex>
|
||||||
|
#include <string>
|
||||||
|
#include <array>
|
||||||
|
|
||||||
|
namespace spdlog {
|
||||||
|
namespace sinks {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This sink prefixes the output with an ANSI escape sequence color code
|
||||||
|
* depending on the severity
|
||||||
|
* of the message.
|
||||||
|
* If no color terminal detected, omit the escape codes.
|
||||||
|
*/
|
||||||
|
|
||||||
|
template<typename ConsoleMutex>
|
||||||
|
class ansicolor_sink : public sink
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using mutex_t = typename ConsoleMutex::mutex_t;
|
||||||
|
ansicolor_sink(FILE *target_file, color_mode mode);
|
||||||
|
~ansicolor_sink() override = default;
|
||||||
|
|
||||||
|
ansicolor_sink(const ansicolor_sink &other) = delete;
|
||||||
|
ansicolor_sink(ansicolor_sink &&other) = delete;
|
||||||
|
|
||||||
|
ansicolor_sink &operator=(const ansicolor_sink &other) = delete;
|
||||||
|
ansicolor_sink &operator=(ansicolor_sink &&other) = delete;
|
||||||
|
|
||||||
|
void set_color(level::level_enum color_level, string_view_t color);
|
||||||
|
void set_color_mode(color_mode mode);
|
||||||
|
bool should_color();
|
||||||
|
|
||||||
|
void log(const details::log_msg &msg) override;
|
||||||
|
void flush() override;
|
||||||
|
void set_pattern(const std::string &pattern) final;
|
||||||
|
void set_formatter(std::unique_ptr<spdlog::formatter> sink_formatter) override;
|
||||||
|
|
||||||
|
// Formatting codes
|
||||||
|
const string_view_t reset = "\033[m";
|
||||||
|
const string_view_t bold = "\033[1m";
|
||||||
|
const string_view_t dark = "\033[2m";
|
||||||
|
const string_view_t underline = "\033[4m";
|
||||||
|
const string_view_t blink = "\033[5m";
|
||||||
|
const string_view_t reverse = "\033[7m";
|
||||||
|
const string_view_t concealed = "\033[8m";
|
||||||
|
const string_view_t clear_line = "\033[K";
|
||||||
|
|
||||||
|
// Foreground colors
|
||||||
|
const string_view_t black = "\033[30m";
|
||||||
|
const string_view_t red = "\033[31m";
|
||||||
|
const string_view_t green = "\033[32m";
|
||||||
|
const string_view_t yellow = "\033[33m";
|
||||||
|
const string_view_t blue = "\033[34m";
|
||||||
|
const string_view_t magenta = "\033[35m";
|
||||||
|
const string_view_t cyan = "\033[36m";
|
||||||
|
const string_view_t white = "\033[37m";
|
||||||
|
|
||||||
|
/// Background colors
|
||||||
|
const string_view_t on_black = "\033[40m";
|
||||||
|
const string_view_t on_red = "\033[41m";
|
||||||
|
const string_view_t on_green = "\033[42m";
|
||||||
|
const string_view_t on_yellow = "\033[43m";
|
||||||
|
const string_view_t on_blue = "\033[44m";
|
||||||
|
const string_view_t on_magenta = "\033[45m";
|
||||||
|
const string_view_t on_cyan = "\033[46m";
|
||||||
|
const string_view_t on_white = "\033[47m";
|
||||||
|
|
||||||
|
/// Bold colors
|
||||||
|
const string_view_t yellow_bold = "\033[33m\033[1m";
|
||||||
|
const string_view_t red_bold = "\033[31m\033[1m";
|
||||||
|
const string_view_t bold_on_red = "\033[1m\033[41m";
|
||||||
|
|
||||||
|
private:
|
||||||
|
FILE *target_file_;
|
||||||
|
mutex_t &mutex_;
|
||||||
|
bool should_do_colors_;
|
||||||
|
std::unique_ptr<spdlog::formatter> formatter_;
|
||||||
|
std::array<std::string, level::n_levels> colors_;
|
||||||
|
void print_ccode_(const string_view_t &color_code);
|
||||||
|
void print_range_(const memory_buf_t &formatted, size_t start, size_t end);
|
||||||
|
static std::string to_string_(const string_view_t &sv);
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename ConsoleMutex>
|
||||||
|
class ansicolor_stdout_sink : public ansicolor_sink<ConsoleMutex>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit ansicolor_stdout_sink(color_mode mode = color_mode::automatic);
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename ConsoleMutex>
|
||||||
|
class ansicolor_stderr_sink : public ansicolor_sink<ConsoleMutex>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit ansicolor_stderr_sink(color_mode mode = color_mode::automatic);
|
||||||
|
};
|
||||||
|
|
||||||
|
using ansicolor_stdout_sink_mt = ansicolor_stdout_sink<details::console_mutex>;
|
||||||
|
using ansicolor_stdout_sink_st = ansicolor_stdout_sink<details::console_nullmutex>;
|
||||||
|
|
||||||
|
using ansicolor_stderr_sink_mt = ansicolor_stderr_sink<details::console_mutex>;
|
||||||
|
using ansicolor_stderr_sink_st = ansicolor_stderr_sink<details::console_nullmutex>;
|
||||||
|
|
||||||
|
} // namespace sinks
|
||||||
|
} // namespace spdlog
|
||||||
|
|
||||||
|
#ifdef SPDLOG_HEADER_ONLY
|
||||||
|
# include "ansicolor_sink-inl.h"
|
||||||
|
#endif
|
||||||
63
thirdparty/spdlog/sinks/base_sink-inl.h
vendored
Normal file
63
thirdparty/spdlog/sinks/base_sink-inl.h
vendored
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
|
||||||
|
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifndef SPDLOG_HEADER_ONLY
|
||||||
|
# include <spdlog/sinks/base_sink.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <spdlog/common.h>
|
||||||
|
#include <spdlog/pattern_formatter.h>
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
template<typename Mutex>
|
||||||
|
SPDLOG_INLINE spdlog::sinks::base_sink<Mutex>::base_sink()
|
||||||
|
: formatter_{details::make_unique<spdlog::pattern_formatter>()}
|
||||||
|
{}
|
||||||
|
|
||||||
|
template<typename Mutex>
|
||||||
|
SPDLOG_INLINE spdlog::sinks::base_sink<Mutex>::base_sink(std::unique_ptr<spdlog::formatter> formatter)
|
||||||
|
: formatter_{std::move(formatter)}
|
||||||
|
{}
|
||||||
|
|
||||||
|
template<typename Mutex>
|
||||||
|
void SPDLOG_INLINE spdlog::sinks::base_sink<Mutex>::log(const details::log_msg &msg)
|
||||||
|
{
|
||||||
|
std::lock_guard<Mutex> lock(mutex_);
|
||||||
|
sink_it_(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Mutex>
|
||||||
|
void SPDLOG_INLINE spdlog::sinks::base_sink<Mutex>::flush()
|
||||||
|
{
|
||||||
|
std::lock_guard<Mutex> lock(mutex_);
|
||||||
|
flush_();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Mutex>
|
||||||
|
void SPDLOG_INLINE spdlog::sinks::base_sink<Mutex>::set_pattern(const std::string &pattern)
|
||||||
|
{
|
||||||
|
std::lock_guard<Mutex> lock(mutex_);
|
||||||
|
set_pattern_(pattern);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Mutex>
|
||||||
|
void SPDLOG_INLINE spdlog::sinks::base_sink<Mutex>::set_formatter(std::unique_ptr<spdlog::formatter> sink_formatter)
|
||||||
|
{
|
||||||
|
std::lock_guard<Mutex> lock(mutex_);
|
||||||
|
set_formatter_(std::move(sink_formatter));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Mutex>
|
||||||
|
void SPDLOG_INLINE spdlog::sinks::base_sink<Mutex>::set_pattern_(const std::string &pattern)
|
||||||
|
{
|
||||||
|
set_formatter_(details::make_unique<spdlog::pattern_formatter>(pattern));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Mutex>
|
||||||
|
void SPDLOG_INLINE spdlog::sinks::base_sink<Mutex>::set_formatter_(std::unique_ptr<spdlog::formatter> sink_formatter)
|
||||||
|
{
|
||||||
|
formatter_ = std::move(sink_formatter);
|
||||||
|
}
|
||||||
52
thirdparty/spdlog/sinks/base_sink.h
vendored
Normal file
52
thirdparty/spdlog/sinks/base_sink.h
vendored
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
|
||||||
|
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
//
|
||||||
|
// base sink templated over a mutex (either dummy or real)
|
||||||
|
// concrete implementation should override the sink_it_() and flush_() methods.
|
||||||
|
// locking is taken care of in this class - no locking needed by the
|
||||||
|
// implementers..
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <spdlog/common.h>
|
||||||
|
#include <spdlog/details/log_msg.h>
|
||||||
|
#include <spdlog/sinks/sink.h>
|
||||||
|
|
||||||
|
namespace spdlog {
|
||||||
|
namespace sinks {
|
||||||
|
template<typename Mutex>
|
||||||
|
class base_sink : public sink
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
base_sink();
|
||||||
|
explicit base_sink(std::unique_ptr<spdlog::formatter> formatter);
|
||||||
|
~base_sink() override = default;
|
||||||
|
|
||||||
|
base_sink(const base_sink &) = delete;
|
||||||
|
base_sink(base_sink &&) = delete;
|
||||||
|
|
||||||
|
base_sink &operator=(const base_sink &) = delete;
|
||||||
|
base_sink &operator=(base_sink &&) = delete;
|
||||||
|
|
||||||
|
void log(const details::log_msg &msg) final;
|
||||||
|
void flush() final;
|
||||||
|
void set_pattern(const std::string &pattern) final;
|
||||||
|
void set_formatter(std::unique_ptr<spdlog::formatter> sink_formatter) final;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// sink formatter
|
||||||
|
std::unique_ptr<spdlog::formatter> formatter_;
|
||||||
|
mutable Mutex mutex_;
|
||||||
|
|
||||||
|
virtual void sink_it_(const details::log_msg &msg) = 0;
|
||||||
|
virtual void flush_() = 0;
|
||||||
|
virtual void set_pattern_(const std::string &pattern);
|
||||||
|
virtual void set_formatter_(std::unique_ptr<spdlog::formatter> sink_formatter);
|
||||||
|
};
|
||||||
|
} // namespace sinks
|
||||||
|
} // namespace spdlog
|
||||||
|
|
||||||
|
#ifdef SPDLOG_HEADER_ONLY
|
||||||
|
# include "base_sink-inl.h"
|
||||||
|
#endif
|
||||||
43
thirdparty/spdlog/sinks/basic_file_sink-inl.h
vendored
Normal file
43
thirdparty/spdlog/sinks/basic_file_sink-inl.h
vendored
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
|
||||||
|
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifndef SPDLOG_HEADER_ONLY
|
||||||
|
# include <spdlog/sinks/basic_file_sink.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <spdlog/common.h>
|
||||||
|
#include <spdlog/details/os.h>
|
||||||
|
|
||||||
|
namespace spdlog {
|
||||||
|
namespace sinks {
|
||||||
|
|
||||||
|
template<typename Mutex>
|
||||||
|
SPDLOG_INLINE basic_file_sink<Mutex>::basic_file_sink(const filename_t &filename, bool truncate)
|
||||||
|
{
|
||||||
|
file_helper_.open(filename, truncate);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Mutex>
|
||||||
|
SPDLOG_INLINE const filename_t &basic_file_sink<Mutex>::filename() const
|
||||||
|
{
|
||||||
|
return file_helper_.filename();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Mutex>
|
||||||
|
SPDLOG_INLINE void basic_file_sink<Mutex>::sink_it_(const details::log_msg &msg)
|
||||||
|
{
|
||||||
|
memory_buf_t formatted;
|
||||||
|
base_sink<Mutex>::formatter_->format(msg, formatted);
|
||||||
|
file_helper_.write(formatted);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Mutex>
|
||||||
|
SPDLOG_INLINE void basic_file_sink<Mutex>::flush_()
|
||||||
|
{
|
||||||
|
file_helper_.flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace sinks
|
||||||
|
} // namespace spdlog
|
||||||
58
thirdparty/spdlog/sinks/basic_file_sink.h
vendored
Normal file
58
thirdparty/spdlog/sinks/basic_file_sink.h
vendored
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
|
||||||
|
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <spdlog/details/file_helper.h>
|
||||||
|
#include <spdlog/details/null_mutex.h>
|
||||||
|
#include <spdlog/sinks/base_sink.h>
|
||||||
|
#include <spdlog/details/synchronous_factory.h>
|
||||||
|
|
||||||
|
#include <mutex>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace spdlog {
|
||||||
|
namespace sinks {
|
||||||
|
/*
|
||||||
|
* Trivial file sink with single file as target
|
||||||
|
*/
|
||||||
|
template<typename Mutex>
|
||||||
|
class basic_file_sink final : public base_sink<Mutex>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit basic_file_sink(const filename_t &filename, bool truncate = false);
|
||||||
|
const filename_t &filename() const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void sink_it_(const details::log_msg &msg) override;
|
||||||
|
void flush_() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
details::file_helper file_helper_;
|
||||||
|
};
|
||||||
|
|
||||||
|
using basic_file_sink_mt = basic_file_sink<std::mutex>;
|
||||||
|
using basic_file_sink_st = basic_file_sink<details::null_mutex>;
|
||||||
|
|
||||||
|
} // namespace sinks
|
||||||
|
|
||||||
|
//
|
||||||
|
// factory functions
|
||||||
|
//
|
||||||
|
template<typename Factory = spdlog::synchronous_factory>
|
||||||
|
inline std::shared_ptr<logger> basic_logger_mt(const std::string &logger_name, const filename_t &filename, bool truncate = false)
|
||||||
|
{
|
||||||
|
return Factory::template create<sinks::basic_file_sink_mt>(logger_name, filename, truncate);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Factory = spdlog::synchronous_factory>
|
||||||
|
inline std::shared_ptr<logger> basic_logger_st(const std::string &logger_name, const filename_t &filename, bool truncate = false)
|
||||||
|
{
|
||||||
|
return Factory::template create<sinks::basic_file_sink_st>(logger_name, filename, truncate);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace spdlog
|
||||||
|
|
||||||
|
#ifdef SPDLOG_HEADER_ONLY
|
||||||
|
# include "basic_file_sink-inl.h"
|
||||||
|
#endif
|
||||||
242
thirdparty/spdlog/sinks/daily_file_sink.h
vendored
Normal file
242
thirdparty/spdlog/sinks/daily_file_sink.h
vendored
Normal file
@@ -0,0 +1,242 @@
|
|||||||
|
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
|
||||||
|
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <spdlog/common.h>
|
||||||
|
#include <spdlog/details/file_helper.h>
|
||||||
|
#include <spdlog/details/null_mutex.h>
|
||||||
|
#include <spdlog/fmt/fmt.h>
|
||||||
|
#include <spdlog/fmt/chrono.h>
|
||||||
|
#include <spdlog/sinks/base_sink.h>
|
||||||
|
#include <spdlog/details/os.h>
|
||||||
|
#include <spdlog/details/circular_q.h>
|
||||||
|
#include <spdlog/details/synchronous_factory.h>
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
#include <cstdio>
|
||||||
|
#include <ctime>
|
||||||
|
#include <mutex>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace spdlog {
|
||||||
|
namespace sinks {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Generator of daily log file names in format basename.YYYY-MM-DD.ext
|
||||||
|
*/
|
||||||
|
struct daily_filename_calculator
|
||||||
|
{
|
||||||
|
// Create filename for the form basename.YYYY-MM-DD
|
||||||
|
static filename_t calc_filename(const filename_t &filename, const tm &now_tm)
|
||||||
|
{
|
||||||
|
filename_t basename, ext;
|
||||||
|
std::tie(basename, ext) = details::file_helper::split_by_extension(filename);
|
||||||
|
return fmt::format(
|
||||||
|
SPDLOG_FILENAME_T("{}_{:04d}-{:02d}-{:02d}{}"), basename, now_tm.tm_year + 1900, now_tm.tm_mon + 1, now_tm.tm_mday, ext);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Generator of daily log file names with strftime format.
|
||||||
|
* Usages:
|
||||||
|
* auto sink = std::make_shared<spdlog::sinks::daily_file_format_sink_mt>("myapp-%Y-%m-%d:%H:%M:%S.log", hour, minute);"
|
||||||
|
* auto logger = spdlog::daily_logger_format_mt("loggername, "myapp-%Y-%m-%d:%X.log", hour, minute)"
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
struct daily_filename_format_calculator
|
||||||
|
{
|
||||||
|
static filename_t calc_filename(const filename_t &filename, const tm &now_tm)
|
||||||
|
{
|
||||||
|
// generate fmt datetime format string, e.g. {:%Y-%m-%d}.
|
||||||
|
filename_t fmt_filename = fmt::format(SPDLOG_FILENAME_T("{{:{}}}"), filename);
|
||||||
|
#if defined(_MSC_VER) && defined(SPDLOG_WCHAR_FILENAMES) // for some reason msvc doesnt allow fmt::runtime(..) with wchar here
|
||||||
|
return fmt::format(fmt_filename, now_tm);
|
||||||
|
#else
|
||||||
|
return fmt::format(SPDLOG_FMT_RUNTIME(fmt_filename), now_tm);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Rotating file sink based on date.
|
||||||
|
* If truncate != false , the created file will be truncated.
|
||||||
|
* If max_files > 0, retain only the last max_files and delete previous.
|
||||||
|
*/
|
||||||
|
template<typename Mutex, typename FileNameCalc = daily_filename_calculator>
|
||||||
|
class daily_file_sink final : public base_sink<Mutex>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// create daily file sink which rotates on given time
|
||||||
|
daily_file_sink(filename_t base_filename, int rotation_hour, int rotation_minute, bool truncate = false, uint16_t max_files = 0)
|
||||||
|
: base_filename_(std::move(base_filename))
|
||||||
|
, rotation_h_(rotation_hour)
|
||||||
|
, rotation_m_(rotation_minute)
|
||||||
|
, truncate_(truncate)
|
||||||
|
, max_files_(max_files)
|
||||||
|
, filenames_q_()
|
||||||
|
{
|
||||||
|
if (rotation_hour < 0 || rotation_hour > 23 || rotation_minute < 0 || rotation_minute > 59)
|
||||||
|
{
|
||||||
|
throw_spdlog_ex("daily_file_sink: Invalid rotation time in ctor");
|
||||||
|
}
|
||||||
|
|
||||||
|
auto now = log_clock::now();
|
||||||
|
auto filename = FileNameCalc::calc_filename(base_filename_, now_tm(now));
|
||||||
|
file_helper_.open(filename, truncate_);
|
||||||
|
rotation_tp_ = next_rotation_tp_();
|
||||||
|
|
||||||
|
if (max_files_ > 0)
|
||||||
|
{
|
||||||
|
init_filenames_q_();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
filename_t filename()
|
||||||
|
{
|
||||||
|
std::lock_guard<Mutex> lock(base_sink<Mutex>::mutex_);
|
||||||
|
return file_helper_.filename();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void sink_it_(const details::log_msg &msg) override
|
||||||
|
{
|
||||||
|
auto time = msg.time;
|
||||||
|
bool should_rotate = time >= rotation_tp_;
|
||||||
|
if (should_rotate)
|
||||||
|
{
|
||||||
|
auto filename = FileNameCalc::calc_filename(base_filename_, now_tm(time));
|
||||||
|
file_helper_.open(filename, truncate_);
|
||||||
|
rotation_tp_ = next_rotation_tp_();
|
||||||
|
}
|
||||||
|
memory_buf_t formatted;
|
||||||
|
base_sink<Mutex>::formatter_->format(msg, formatted);
|
||||||
|
file_helper_.write(formatted);
|
||||||
|
|
||||||
|
// Do the cleaning only at the end because it might throw on failure.
|
||||||
|
if (should_rotate && max_files_ > 0)
|
||||||
|
{
|
||||||
|
delete_old_();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void flush_() override
|
||||||
|
{
|
||||||
|
file_helper_.flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void init_filenames_q_()
|
||||||
|
{
|
||||||
|
using details::os::path_exists;
|
||||||
|
|
||||||
|
filenames_q_ = details::circular_q<filename_t>(static_cast<size_t>(max_files_));
|
||||||
|
std::vector<filename_t> filenames;
|
||||||
|
auto now = log_clock::now();
|
||||||
|
while (filenames.size() < max_files_)
|
||||||
|
{
|
||||||
|
auto filename = FileNameCalc::calc_filename(base_filename_, now_tm(now));
|
||||||
|
if (!path_exists(filename))
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
filenames.emplace_back(filename);
|
||||||
|
now -= std::chrono::hours(24);
|
||||||
|
}
|
||||||
|
for (auto iter = filenames.rbegin(); iter != filenames.rend(); ++iter)
|
||||||
|
{
|
||||||
|
filenames_q_.push_back(std::move(*iter));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tm now_tm(log_clock::time_point tp)
|
||||||
|
{
|
||||||
|
time_t tnow = log_clock::to_time_t(tp);
|
||||||
|
return spdlog::details::os::localtime(tnow);
|
||||||
|
}
|
||||||
|
|
||||||
|
log_clock::time_point next_rotation_tp_()
|
||||||
|
{
|
||||||
|
auto now = log_clock::now();
|
||||||
|
tm date = now_tm(now);
|
||||||
|
date.tm_hour = rotation_h_;
|
||||||
|
date.tm_min = rotation_m_;
|
||||||
|
date.tm_sec = 0;
|
||||||
|
auto rotation_time = log_clock::from_time_t(std::mktime(&date));
|
||||||
|
if (rotation_time > now)
|
||||||
|
{
|
||||||
|
return rotation_time;
|
||||||
|
}
|
||||||
|
return {rotation_time + std::chrono::hours(24)};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete the file N rotations ago.
|
||||||
|
// Throw spdlog_ex on failure to delete the old file.
|
||||||
|
void delete_old_()
|
||||||
|
{
|
||||||
|
using details::os::filename_to_str;
|
||||||
|
using details::os::remove_if_exists;
|
||||||
|
|
||||||
|
filename_t current_file = file_helper_.filename();
|
||||||
|
if (filenames_q_.full())
|
||||||
|
{
|
||||||
|
auto old_filename = std::move(filenames_q_.front());
|
||||||
|
filenames_q_.pop_front();
|
||||||
|
bool ok = remove_if_exists(old_filename) == 0;
|
||||||
|
if (!ok)
|
||||||
|
{
|
||||||
|
filenames_q_.push_back(std::move(current_file));
|
||||||
|
throw_spdlog_ex("Failed removing daily file " + filename_to_str(old_filename), errno);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
filenames_q_.push_back(std::move(current_file));
|
||||||
|
}
|
||||||
|
|
||||||
|
filename_t base_filename_;
|
||||||
|
int rotation_h_;
|
||||||
|
int rotation_m_;
|
||||||
|
log_clock::time_point rotation_tp_;
|
||||||
|
details::file_helper file_helper_;
|
||||||
|
bool truncate_;
|
||||||
|
uint16_t max_files_;
|
||||||
|
details::circular_q<filename_t> filenames_q_;
|
||||||
|
};
|
||||||
|
|
||||||
|
using daily_file_sink_mt = daily_file_sink<std::mutex>;
|
||||||
|
using daily_file_sink_st = daily_file_sink<details::null_mutex>;
|
||||||
|
using daily_file_format_sink_mt = daily_file_sink<std::mutex, daily_filename_format_calculator>;
|
||||||
|
using daily_file_format_sink_st = daily_file_sink<details::null_mutex, daily_filename_format_calculator>;
|
||||||
|
|
||||||
|
} // namespace sinks
|
||||||
|
|
||||||
|
//
|
||||||
|
// factory functions
|
||||||
|
//
|
||||||
|
template<typename Factory = spdlog::synchronous_factory>
|
||||||
|
inline std::shared_ptr<logger> daily_logger_mt(
|
||||||
|
const std::string &logger_name, const filename_t &filename, int hour = 0, int minute = 0, bool truncate = false, uint16_t max_files = 0)
|
||||||
|
{
|
||||||
|
return Factory::template create<sinks::daily_file_sink_mt>(logger_name, filename, hour, minute, truncate, max_files);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Factory = spdlog::synchronous_factory>
|
||||||
|
inline std::shared_ptr<logger> daily_logger_format_mt(
|
||||||
|
const std::string &logger_name, const filename_t &filename, int hour = 0, int minute = 0, bool truncate = false, uint16_t max_files = 0)
|
||||||
|
{
|
||||||
|
return Factory::template create<sinks::daily_file_format_sink_mt>(logger_name, filename, hour, minute, truncate, max_files);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Factory = spdlog::synchronous_factory>
|
||||||
|
inline std::shared_ptr<logger> daily_logger_st(
|
||||||
|
const std::string &logger_name, const filename_t &filename, int hour = 0, int minute = 0, bool truncate = false, uint16_t max_files = 0)
|
||||||
|
{
|
||||||
|
return Factory::template create<sinks::daily_file_sink_st>(logger_name, filename, hour, minute, truncate, max_files);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Factory = spdlog::synchronous_factory>
|
||||||
|
inline std::shared_ptr<logger> daily_logger_format_st(
|
||||||
|
const std::string &logger_name, const filename_t &filename, int hour = 0, int minute = 0, bool truncate = false, uint16_t max_files = 0)
|
||||||
|
{
|
||||||
|
return Factory::template create<sinks::daily_file_format_sink_st>(logger_name, filename, hour, minute, truncate, max_files);
|
||||||
|
}
|
||||||
|
} // namespace spdlog
|
||||||
97
thirdparty/spdlog/sinks/dist_sink.h
vendored
Normal file
97
thirdparty/spdlog/sinks/dist_sink.h
vendored
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
|
||||||
|
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "base_sink.h"
|
||||||
|
#include <spdlog/details/log_msg.h>
|
||||||
|
#include <spdlog/details/null_mutex.h>
|
||||||
|
#include <spdlog/pattern_formatter.h>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <memory>
|
||||||
|
#include <mutex>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
// Distribution sink (mux). Stores a vector of sinks which get called when log
|
||||||
|
// is called
|
||||||
|
|
||||||
|
namespace spdlog {
|
||||||
|
namespace sinks {
|
||||||
|
|
||||||
|
template<typename Mutex>
|
||||||
|
class dist_sink : public base_sink<Mutex>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
dist_sink() = default;
|
||||||
|
explicit dist_sink(std::vector<std::shared_ptr<sink>> sinks)
|
||||||
|
: sinks_(sinks)
|
||||||
|
{}
|
||||||
|
|
||||||
|
dist_sink(const dist_sink &) = delete;
|
||||||
|
dist_sink &operator=(const dist_sink &) = delete;
|
||||||
|
|
||||||
|
void add_sink(std::shared_ptr<sink> sink)
|
||||||
|
{
|
||||||
|
std::lock_guard<Mutex> lock(base_sink<Mutex>::mutex_);
|
||||||
|
sinks_.push_back(sink);
|
||||||
|
}
|
||||||
|
|
||||||
|
void remove_sink(std::shared_ptr<sink> sink)
|
||||||
|
{
|
||||||
|
std::lock_guard<Mutex> lock(base_sink<Mutex>::mutex_);
|
||||||
|
sinks_.erase(std::remove(sinks_.begin(), sinks_.end(), sink), sinks_.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_sinks(std::vector<std::shared_ptr<sink>> sinks)
|
||||||
|
{
|
||||||
|
std::lock_guard<Mutex> lock(base_sink<Mutex>::mutex_);
|
||||||
|
sinks_ = std::move(sinks);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::shared_ptr<sink>> &sinks()
|
||||||
|
{
|
||||||
|
return sinks_;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void sink_it_(const details::log_msg &msg) override
|
||||||
|
{
|
||||||
|
for (auto &sink : sinks_)
|
||||||
|
{
|
||||||
|
if (sink->should_log(msg.level))
|
||||||
|
{
|
||||||
|
sink->log(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void flush_() override
|
||||||
|
{
|
||||||
|
for (auto &sink : sinks_)
|
||||||
|
{
|
||||||
|
sink->flush();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_pattern_(const std::string &pattern) override
|
||||||
|
{
|
||||||
|
set_formatter_(details::make_unique<spdlog::pattern_formatter>(pattern));
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_formatter_(std::unique_ptr<spdlog::formatter> sink_formatter) override
|
||||||
|
{
|
||||||
|
base_sink<Mutex>::formatter_ = std::move(sink_formatter);
|
||||||
|
for (auto &sink : sinks_)
|
||||||
|
{
|
||||||
|
sink->set_formatter(base_sink<Mutex>::formatter_->clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
std::vector<std::shared_ptr<sink>> sinks_;
|
||||||
|
};
|
||||||
|
|
||||||
|
using dist_sink_mt = dist_sink<std::mutex>;
|
||||||
|
using dist_sink_st = dist_sink<details::null_mutex>;
|
||||||
|
|
||||||
|
} // namespace sinks
|
||||||
|
} // namespace spdlog
|
||||||
94
thirdparty/spdlog/sinks/dup_filter_sink.h
vendored
Normal file
94
thirdparty/spdlog/sinks/dup_filter_sink.h
vendored
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
// Copyright(c) 2015-present, Gabi Melman & spdlog contributors.
|
||||||
|
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "dist_sink.h"
|
||||||
|
#include <spdlog/details/null_mutex.h>
|
||||||
|
#include <spdlog/details/log_msg.h>
|
||||||
|
|
||||||
|
#include <cstdio>
|
||||||
|
#include <mutex>
|
||||||
|
#include <string>
|
||||||
|
#include <chrono>
|
||||||
|
|
||||||
|
// Duplicate message removal sink.
|
||||||
|
// Skip the message if previous one is identical and less than "max_skip_duration" have passed
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
//
|
||||||
|
// #include <spdlog/sinks/dup_filter_sink.h>
|
||||||
|
//
|
||||||
|
// int main() {
|
||||||
|
// auto dup_filter = std::make_shared<dup_filter_sink_st>(std::chrono::seconds(5));
|
||||||
|
// dup_filter->add_sink(std::make_shared<stdout_color_sink_mt>());
|
||||||
|
// spdlog::logger l("logger", dup_filter);
|
||||||
|
// l.info("Hello");
|
||||||
|
// l.info("Hello");
|
||||||
|
// l.info("Hello");
|
||||||
|
// l.info("Different Hello");
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// Will produce:
|
||||||
|
// [2019-06-25 17:50:56.511] [logger] [info] Hello
|
||||||
|
// [2019-06-25 17:50:56.512] [logger] [info] Skipped 3 duplicate messages..
|
||||||
|
// [2019-06-25 17:50:56.512] [logger] [info] Different Hello
|
||||||
|
|
||||||
|
namespace spdlog {
|
||||||
|
namespace sinks {
|
||||||
|
template<typename Mutex>
|
||||||
|
class dup_filter_sink : public dist_sink<Mutex>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
template<class Rep, class Period>
|
||||||
|
explicit dup_filter_sink(std::chrono::duration<Rep, Period> max_skip_duration)
|
||||||
|
: max_skip_duration_{max_skip_duration}
|
||||||
|
{}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
std::chrono::microseconds max_skip_duration_;
|
||||||
|
log_clock::time_point last_msg_time_;
|
||||||
|
std::string last_msg_payload_;
|
||||||
|
size_t skip_counter_ = 0;
|
||||||
|
|
||||||
|
void sink_it_(const details::log_msg &msg) override
|
||||||
|
{
|
||||||
|
bool filtered = filter_(msg);
|
||||||
|
if (!filtered)
|
||||||
|
{
|
||||||
|
skip_counter_ += 1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// log the "skipped.." message
|
||||||
|
if (skip_counter_ > 0)
|
||||||
|
{
|
||||||
|
char buf[64];
|
||||||
|
auto msg_size = ::snprintf(buf, sizeof(buf), "Skipped %u duplicate messages..", static_cast<unsigned>(skip_counter_));
|
||||||
|
if (msg_size > 0 && static_cast<size_t>(msg_size) < sizeof(buf))
|
||||||
|
{
|
||||||
|
details::log_msg skipped_msg{msg.logger_name, level::info, string_view_t{buf, static_cast<size_t>(msg_size)}};
|
||||||
|
dist_sink<Mutex>::sink_it_(skipped_msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// log current message
|
||||||
|
dist_sink<Mutex>::sink_it_(msg);
|
||||||
|
last_msg_time_ = msg.time;
|
||||||
|
skip_counter_ = 0;
|
||||||
|
last_msg_payload_.assign(msg.payload.data(), msg.payload.data() + msg.payload.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
// return whether the log msg should be displayed (true) or skipped (false)
|
||||||
|
bool filter_(const details::log_msg &msg)
|
||||||
|
{
|
||||||
|
auto filter_duration = msg.time - last_msg_time_;
|
||||||
|
return (filter_duration > max_skip_duration_) || (msg.payload != last_msg_payload_);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
using dup_filter_sink_mt = dup_filter_sink<std::mutex>;
|
||||||
|
using dup_filter_sink_st = dup_filter_sink<details::null_mutex>;
|
||||||
|
|
||||||
|
} // namespace sinks
|
||||||
|
} // namespace spdlog
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user