summaryrefslogtreecommitdiff
path: root/matching/include/spdlog/details
diff options
context:
space:
mode:
Diffstat (limited to 'matching/include/spdlog/details')
-rw-r--r--matching/include/spdlog/details/async_logger_impl.h110
-rw-r--r--matching/include/spdlog/details/circular_q.h72
-rw-r--r--matching/include/spdlog/details/console_globals.h74
-rw-r--r--matching/include/spdlog/details/file_helper.h152
-rw-r--r--matching/include/spdlog/details/fmt_helper.h122
-rw-r--r--matching/include/spdlog/details/log_msg.h55
-rw-r--r--matching/include/spdlog/details/logger_impl.h441
-rw-r--r--matching/include/spdlog/details/mpmc_blocking_q.h121
-rw-r--r--matching/include/spdlog/details/null_mutex.h45
-rw-r--r--matching/include/spdlog/details/os.h421
-rw-r--r--matching/include/spdlog/details/pattern_formatter.h1336
-rw-r--r--matching/include/spdlog/details/periodic_worker.h71
-rw-r--r--matching/include/spdlog/details/registry.h285
-rw-r--r--matching/include/spdlog/details/thread_pool.h238
14 files changed, 3543 insertions, 0 deletions
diff --git a/matching/include/spdlog/details/async_logger_impl.h b/matching/include/spdlog/details/async_logger_impl.h
new file mode 100644
index 0000000..aafcae6
--- /dev/null
+++ b/matching/include/spdlog/details/async_logger_impl.h
@@ -0,0 +1,110 @@
+//
+// Copyright(c) 2015 Gabi Melman.
+// Distributed under the MIT License (http://opensource.org/licenses/MIT)
+//
+
+#pragma once
+
+// async logger implementation
+// uses a thread pool to perform the actual logging
+
+#include "spdlog/details/thread_pool.h"
+
+#include <chrono>
+#include <memory>
+#include <string>
+
+template<typename It>
+inline spdlog::async_logger::async_logger(
+ std::string logger_name, It begin, It end, std::weak_ptr<details::thread_pool> tp, async_overflow_policy overflow_policy)
+ : logger(std::move(logger_name), begin, end)
+ , thread_pool_(std::move(tp))
+ , overflow_policy_(overflow_policy)
+{
+}
+
+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)
+{
+}
+
+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
+inline void spdlog::async_logger::sink_it_(details::log_msg &msg)
+{
+#if defined(SPDLOG_ENABLE_MESSAGE_COUNTER)
+ incr_msg_counter_(msg);
+#endif
+ 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
+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
+//
+inline void spdlog::async_logger::backend_log_(const details::log_msg &incoming_log_msg)
+{
+ try
+ {
+ for (auto &s : sinks_)
+ {
+ if (s->should_log(incoming_log_msg.level))
+ {
+ s->log(incoming_log_msg);
+ }
+ }
+ }
+ SPDLOG_CATCH_AND_HANDLE
+
+ if (should_flush_(incoming_log_msg))
+ {
+ backend_flush_();
+ }
+}
+
+inline void spdlog::async_logger::backend_flush_()
+{
+ try
+ {
+ for (auto &sink : sinks_)
+ {
+ sink->flush();
+ }
+ }
+ SPDLOG_CATCH_AND_HANDLE
+}
+
+inline std::shared_ptr<spdlog::logger> spdlog::async_logger::clone(std::string new_name)
+{
+ auto cloned = std::make_shared<spdlog::async_logger>(std::move(new_name), sinks_.begin(), sinks_.end(), thread_pool_, overflow_policy_);
+
+ cloned->set_level(this->level());
+ cloned->flush_on(this->flush_level());
+ cloned->set_error_handler(this->error_handler());
+ return std::move(cloned);
+}
diff --git a/matching/include/spdlog/details/circular_q.h b/matching/include/spdlog/details/circular_q.h
new file mode 100644
index 0000000..b01325b
--- /dev/null
+++ b/matching/include/spdlog/details/circular_q.h
@@ -0,0 +1,72 @@
+//
+// Copyright(c) 2018 Gabi Melman.
+// Distributed under the MIT License (http://opensource.org/licenses/MIT)
+//
+
+// cirucal q view of std::vector.
+#pragma once
+
+#include <vector>
+
+namespace spdlog {
+namespace details {
+template<typename T>
+class circular_q
+{
+public:
+ using item_type = T;
+
+ explicit circular_q(size_t max_items)
+ : max_items_(max_items + 1) // one item is reserved as marker for full q
+ , v_(max_items_)
+ {
+ }
+
+ // push back, overrun (oldest) item if no room left
+ void push_back(T &&item)
+ {
+ 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_;
+ }
+ }
+
+ // Pop item from front.
+ // If there are no elements in the container, the behavior is undefined.
+ void pop_front(T &popped_item)
+ {
+ popped_item = std::move(v_[head_]);
+ head_ = (head_ + 1) % max_items_;
+ }
+
+ bool empty()
+ {
+ return tail_ == head_;
+ }
+
+ bool full()
+ {
+ // head is ahead of the tail by 1
+ return ((tail_ + 1) % max_items_) == head_;
+ }
+
+ size_t overrun_counter() const
+ {
+ return overrun_counter_;
+ }
+
+private:
+ size_t max_items_;
+ typename std::vector<T>::size_type head_ = 0;
+ typename std::vector<T>::size_type tail_ = 0;
+
+ std::vector<T> v_;
+
+ size_t overrun_counter_ = 0;
+};
+} // namespace details
+} // namespace spdlog
diff --git a/matching/include/spdlog/details/console_globals.h b/matching/include/spdlog/details/console_globals.h
new file mode 100644
index 0000000..e2afb6b
--- /dev/null
+++ b/matching/include/spdlog/details/console_globals.h
@@ -0,0 +1,74 @@
+#pragma once
+//
+// Copyright(c) 2018 Gabi Melman.
+// Distributed under the MIT License (http://opensource.org/licenses/MIT)
+//
+
+#include "spdlog/details/null_mutex.h"
+#include <cstdio>
+#include <mutex>
+
+#ifdef _WIN32
+
+#ifndef NOMINMAX
+#define NOMINMAX // prevent windows redefining min/max
+#endif
+
+#ifndef WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN
+#endif
+
+#include <windows.h>
+#endif
+
+namespace spdlog {
+namespace details {
+struct console_stdout
+{
+ static std::FILE *stream()
+ {
+ return stdout;
+ }
+#ifdef _WIN32
+ static HANDLE handle()
+ {
+ return ::GetStdHandle(STD_OUTPUT_HANDLE);
+ }
+#endif
+};
+
+struct console_stderr
+{
+ static std::FILE *stream()
+ {
+ return stderr;
+ }
+#ifdef _WIN32
+ static HANDLE handle()
+ {
+ return ::GetStdHandle(STD_ERROR_HANDLE);
+ }
+#endif
+};
+
+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
diff --git a/matching/include/spdlog/details/file_helper.h b/matching/include/spdlog/details/file_helper.h
new file mode 100644
index 0000000..8c1132d
--- /dev/null
+++ b/matching/include/spdlog/details/file_helper.h
@@ -0,0 +1,152 @@
+//
+// Copyright(c) 2015 Gabi Melman.
+// Distributed under the MIT License (http://opensource.org/licenses/MIT)
+//
+
+#pragma once
+
+// 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.
+
+#include "spdlog/details/log_msg.h"
+#include "spdlog/details/os.h"
+
+#include <cerrno>
+#include <chrono>
+#include <cstdio>
+#include <string>
+#include <thread>
+#include <tuple>
+
+namespace spdlog {
+namespace details {
+
+class file_helper
+{
+
+public:
+ const int open_tries = 5;
+ const int open_interval = 10;
+
+ explicit file_helper() = default;
+
+ file_helper(const file_helper &) = delete;
+ file_helper &operator=(const file_helper &) = delete;
+
+ ~file_helper()
+ {
+ close();
+ }
+
+ void open(const filename_t &fname, bool truncate = false)
+ {
+ close();
+ auto *mode = truncate ? SPDLOG_FILENAME_T("wb") : SPDLOG_FILENAME_T("ab");
+ _filename = fname;
+ for (int tries = 0; tries < open_tries; ++tries)
+ {
+ 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);
+ }
+
+ void reopen(bool truncate)
+ {
+ if (_filename.empty())
+ {
+ throw spdlog_ex("Failed re opening file - was not opened before");
+ }
+ open(_filename, truncate);
+ }
+
+ void flush()
+ {
+ std::fflush(fd_);
+ }
+
+ void close()
+ {
+ if (fd_ != nullptr)
+ {
+ std::fclose(fd_);
+ fd_ = nullptr;
+ }
+ }
+
+ void write(const fmt::memory_buffer &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);
+ }
+ }
+
+ size_t size() const
+ {
+ if (fd_ == nullptr)
+ {
+ throw spdlog_ex("Cannot use size() on closed file " + os::filename_to_str(_filename));
+ }
+ return os::filesize(fd_);
+ }
+
+ const filename_t &filename() const
+ {
+ return _filename;
+ }
+
+ static bool file_exists(const filename_t &fname)
+ {
+ return os::file_exists(fname);
+ }
+
+ //
+ // 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 spdlog::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, spdlog::filename_t());
+ }
+
+ // treat casese like "/etc/rc.d/somelogfile or "/abc/.hiddenfile"
+ auto folder_index = fname.rfind(details::os::folder_sep);
+ if (folder_index != filename_t::npos && folder_index >= ext_index - 1)
+ {
+ return std::make_tuple(fname, spdlog::filename_t());
+ }
+
+ // finally - return a valid base and extension tuple
+ return std::make_tuple(fname.substr(0, ext_index), fname.substr(ext_index));
+ }
+
+private:
+ std::FILE *fd_{nullptr};
+ filename_t _filename;
+};
+} // namespace details
+} // namespace spdlog
diff --git a/matching/include/spdlog/details/fmt_helper.h b/matching/include/spdlog/details/fmt_helper.h
new file mode 100644
index 0000000..d76aac4
--- /dev/null
+++ b/matching/include/spdlog/details/fmt_helper.h
@@ -0,0 +1,122 @@
+//
+// Created by gabi on 6/15/18.
+//
+
+#pragma once
+
+#include <chrono>
+#include <type_traits>
+#include "spdlog/fmt/fmt.h"
+
+// Some fmt helpers to efficiently format and pad ints and strings
+namespace spdlog {
+namespace details {
+namespace fmt_helper {
+
+template<size_t Buffer_Size>
+inline spdlog::string_view_t to_string_view(const fmt::basic_memory_buffer<char, Buffer_Size> &buf) SPDLOG_NOEXCEPT
+{
+ return spdlog::string_view_t(buf.data(), buf.size());
+}
+
+template<size_t Buffer_Size1, size_t Buffer_Size2>
+inline void append_buf(const fmt::basic_memory_buffer<char, Buffer_Size1> &buf, fmt::basic_memory_buffer<char, Buffer_Size2> &dest)
+{
+ auto *buf_ptr = buf.data();
+ dest.append(buf_ptr, buf_ptr + buf.size());
+}
+
+template<size_t Buffer_Size>
+inline void append_string_view(spdlog::string_view_t view, fmt::basic_memory_buffer<char, Buffer_Size> &dest)
+{
+ auto *buf_ptr = view.data();
+ if (buf_ptr != nullptr)
+ {
+ dest.append(buf_ptr, buf_ptr + view.size());
+ }
+}
+
+template<typename T, size_t Buffer_Size>
+inline void append_int(T n, fmt::basic_memory_buffer<char, Buffer_Size> &dest)
+{
+ fmt::format_int i(n);
+ dest.append(i.data(), i.data() + i.size());
+}
+
+template<typename T>
+inline unsigned count_digits(T n)
+{
+ using count_type = typename std::conditional<(sizeof(T) > sizeof(uint32_t)), uint64_t, uint32_t>::type;
+ return static_cast<unsigned>(fmt::internal::count_digits(static_cast<count_type>(n)));
+}
+
+template<size_t Buffer_Size>
+inline void pad2(int n, fmt::basic_memory_buffer<char, Buffer_Size> &dest)
+{
+ if (n > 99)
+ {
+ append_int(n, dest);
+ }
+ else if (n > 9) // 10-99
+ {
+ dest.push_back(static_cast<char>('0' + n / 10));
+ dest.push_back(static_cast<char>('0' + n % 10));
+ }
+ else if (n >= 0) // 0-9
+ {
+ dest.push_back('0');
+ dest.push_back(static_cast<char>('0' + n));
+ }
+ else // negatives (unlikely, but just in case, let fmt deal with it)
+ {
+ fmt::format_to(dest, "{:02}", n);
+ }
+}
+
+template<typename T, size_t Buffer_Size>
+inline void pad_uint(T n, unsigned int width, fmt::basic_memory_buffer<char, Buffer_Size> &dest)
+{
+ static_assert(std::is_unsigned<T>::value, "pad_uint must get unsigned T");
+ auto digits = count_digits(n);
+ if (width > digits)
+ {
+ const char *zeroes = "0000000000000000000";
+ dest.append(zeroes, zeroes + width - digits);
+ }
+ append_int(n, dest);
+}
+
+template<typename T, size_t Buffer_Size>
+inline void pad3(T n, fmt::basic_memory_buffer<char, Buffer_Size> &dest)
+{
+ pad_uint(n, 3, dest);
+}
+
+template<typename T, size_t Buffer_Size>
+inline void pad6(T n, fmt::basic_memory_buffer<char, Buffer_Size> &dest)
+{
+ pad_uint(n, 6, dest);
+}
+
+template<typename T, size_t Buffer_Size>
+inline void pad9(T n, fmt::basic_memory_buffer<char, Buffer_Size> &dest)
+{
+ pad_uint(n, 9, dest);
+}
+
+// return fraction of a second of the given time_point.
+// e.g.
+// fraction<std::milliseconds>(tp) -> will return the millis part of the second
+template<typename ToDuration>
+inline ToDuration time_fraction(const 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
diff --git a/matching/include/spdlog/details/log_msg.h b/matching/include/spdlog/details/log_msg.h
new file mode 100644
index 0000000..69422ba
--- /dev/null
+++ b/matching/include/spdlog/details/log_msg.h
@@ -0,0 +1,55 @@
+//
+// Copyright(c) 2015 Gabi Melman.
+// Distributed under the MIT License (http://opensource.org/licenses/MIT)
+//
+
+#pragma once
+
+#include "spdlog/common.h"
+#include "spdlog/details/os.h"
+
+#include <string>
+#include <utility>
+
+namespace spdlog {
+namespace details {
+struct log_msg
+{
+
+ log_msg(source_loc loc, const std::string *loggers_name, level::level_enum lvl, string_view_t view)
+ : logger_name(loggers_name)
+ , level(lvl)
+#ifndef SPDLOG_NO_DATETIME
+ , time(os::now())
+#endif
+
+#ifndef SPDLOG_NO_THREAD_ID
+ , thread_id(os::thread_id())
+#endif
+ , source(loc)
+ , payload(view)
+ {
+ }
+
+ log_msg(const std::string *loggers_name, level::level_enum lvl, string_view_t view)
+ : log_msg(source_loc{}, loggers_name, lvl, view)
+ {
+ }
+
+ log_msg(const log_msg &other) = default;
+
+ const std::string *logger_name{nullptr};
+ level::level_enum level{level::off};
+ log_clock::time_point time;
+ size_t thread_id{0};
+ size_t msg_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;
+ const string_view_t payload;
+};
+} // namespace details
+} // namespace spdlog
diff --git a/matching/include/spdlog/details/logger_impl.h b/matching/include/spdlog/details/logger_impl.h
new file mode 100644
index 0000000..0212ede
--- /dev/null
+++ b/matching/include/spdlog/details/logger_impl.h
@@ -0,0 +1,441 @@
+//
+// Copyright(c) 2015 Gabi Melman.
+// Distributed under the MIT License (http://opensource.org/licenses/MIT)
+//
+
+#pragma once
+
+#include "spdlog/details/fmt_helper.h"
+
+#include <memory>
+#include <string>
+
+#define SPDLOG_CATCH_AND_HANDLE \
+ catch (const std::exception &ex) \
+ { \
+ err_handler_(ex.what()); \
+ } \
+ catch (...) \
+ { \
+ err_handler_("Unknown exception in logger"); \
+ }
+
+// create logger with given name, sinks and the default pattern formatter
+// all other ctors will call this one
+template<typename It>
+inline spdlog::logger::logger(std::string logger_name, It begin, It end)
+ : name_(std::move(logger_name))
+ , sinks_(begin, end)
+{
+}
+
+// ctor with sinks as init list
+inline spdlog::logger::logger(std::string logger_name, sinks_init_list sinks_list)
+ : logger(std::move(logger_name), sinks_list.begin(), sinks_list.end())
+{
+}
+
+// ctor with single sink
+inline spdlog::logger::logger(std::string logger_name, spdlog::sink_ptr single_sink)
+ : logger(std::move(logger_name), {std::move(single_sink)})
+{
+}
+
+inline spdlog::logger::~logger() = default;
+
+inline void spdlog::logger::set_formatter(std::unique_ptr<spdlog::formatter> f)
+{
+ for (auto &sink : sinks_)
+ {
+ sink->set_formatter(f->clone());
+ }
+}
+
+inline void spdlog::logger::set_pattern(std::string pattern, pattern_time_type time_type)
+{
+ auto new_formatter = details::make_unique<spdlog::pattern_formatter>(std::move(pattern), time_type);
+ set_formatter(std::move(new_formatter));
+}
+
+template<typename... Args>
+inline void spdlog::logger::log(source_loc source, level::level_enum lvl, const char *fmt, const Args &... args)
+{
+ if (!should_log(lvl))
+ {
+ return;
+ }
+
+ try
+ {
+ using details::fmt_helper::to_string_view;
+ fmt::memory_buffer buf;
+ fmt::format_to(buf, fmt, args...);
+ details::log_msg log_msg(source, &name_, lvl, to_string_view(buf));
+ sink_it_(log_msg);
+ }
+ SPDLOG_CATCH_AND_HANDLE
+}
+
+template<typename... Args>
+inline void spdlog::logger::log(level::level_enum lvl, const char *fmt, const Args &... args)
+{
+ log(source_loc{}, lvl, fmt, args...);
+}
+
+inline void spdlog::logger::log(source_loc source, level::level_enum lvl, const char *msg)
+{
+ if (!should_log(lvl))
+ {
+ return;
+ }
+
+ try
+ {
+ details::log_msg log_msg(source, &name_, lvl, spdlog::string_view_t(msg));
+ sink_it_(log_msg);
+ }
+ SPDLOG_CATCH_AND_HANDLE
+}
+
+inline void spdlog::logger::log(level::level_enum lvl, const char *msg)
+{
+ log(source_loc{}, lvl, msg);
+}
+
+template<class T, typename std::enable_if<std::is_convertible<T, spdlog::string_view_t>::value, T>::type *>
+inline void spdlog::logger::log(source_loc source, level::level_enum lvl, const T &msg)
+{
+ if (!should_log(lvl))
+ {
+ return;
+ }
+ try
+ {
+ details::log_msg log_msg(source, &name_, lvl, msg);
+ sink_it_(log_msg);
+ }
+ SPDLOG_CATCH_AND_HANDLE
+}
+
+template<class T, typename std::enable_if<std::is_convertible<T, spdlog::string_view_t>::value, T>::type *>
+inline void spdlog::logger::log(level::level_enum lvl, const T &msg)
+{
+ log(source_loc{}, lvl, msg);
+}
+
+template<class T, typename std::enable_if<!std::is_convertible<T, spdlog::string_view_t>::value, T>::type *>
+inline void spdlog::logger::log(source_loc source, level::level_enum lvl, const T &msg)
+{
+ if (!should_log(lvl))
+ {
+ return;
+ }
+ try
+ {
+ using details::fmt_helper::to_string_view;
+ fmt::memory_buffer buf;
+ fmt::format_to(buf, "{}", msg);
+ details::log_msg log_msg(source, &name_, lvl, to_string_view(buf));
+ sink_it_(log_msg);
+ }
+ SPDLOG_CATCH_AND_HANDLE
+}
+
+template<class T, typename std::enable_if<!std::is_convertible<T, spdlog::string_view_t>::value, T>::type *>
+inline void spdlog::logger::log(level::level_enum lvl, const T &msg)
+{
+ log(source_loc{}, lvl, msg);
+}
+
+template<typename... Args>
+inline void spdlog::logger::trace(const char *fmt, const Args &... args)
+{
+ log(level::trace, fmt, args...);
+}
+
+template<typename... Args>
+inline void spdlog::logger::debug(const char *fmt, const Args &... args)
+{
+ log(level::debug, fmt, args...);
+}
+
+template<typename... Args>
+inline void spdlog::logger::info(const char *fmt, const Args &... args)
+{
+ log(level::info, fmt, args...);
+}
+
+template<typename... Args>
+inline void spdlog::logger::warn(const char *fmt, const Args &... args)
+{
+ log(level::warn, fmt, args...);
+}
+
+template<typename... Args>
+inline void spdlog::logger::error(const char *fmt, const Args &... args)
+{
+ log(level::err, fmt, args...);
+}
+
+template<typename... Args>
+inline void spdlog::logger::critical(const char *fmt, const Args &... args)
+{
+ log(level::critical, fmt, args...);
+}
+
+template<typename T>
+inline void spdlog::logger::trace(const T &msg)
+{
+ log(level::trace, msg);
+}
+
+template<typename T>
+inline void spdlog::logger::debug(const T &msg)
+{
+ log(level::debug, msg);
+}
+
+template<typename T>
+inline void spdlog::logger::info(const T &msg)
+{
+ log(level::info, msg);
+}
+
+template<typename T>
+inline void spdlog::logger::warn(const T &msg)
+{
+ log(level::warn, msg);
+}
+
+template<typename T>
+inline void spdlog::logger::error(const T &msg)
+{
+ log(level::err, msg);
+}
+
+template<typename T>
+inline void spdlog::logger::critical(const T &msg)
+{
+ log(level::critical, msg);
+}
+
+#ifdef SPDLOG_WCHAR_TO_UTF8_SUPPORT
+
+inline void wbuf_to_utf8buf(const fmt::wmemory_buffer &wbuf, fmt::memory_buffer &target)
+{
+ int wbuf_size = static_cast<int>(wbuf.size());
+ if (wbuf_size == 0)
+ {
+ return;
+ }
+
+ auto result_size = ::WideCharToMultiByte(CP_UTF8, 0, wbuf.data(), wbuf_size, NULL, 0, NULL, NULL);
+
+ if (result_size > 0)
+ {
+ target.resize(result_size);
+ ::WideCharToMultiByte(CP_UTF8, 0, wbuf.data(), wbuf_size, &target.data()[0], result_size, NULL, NULL);
+ }
+ else
+ {
+ throw spdlog::spdlog_ex(fmt::format("WideCharToMultiByte failed. Last error: {}", ::GetLastError()));
+ }
+}
+
+template<typename... Args>
+inline void spdlog::logger::log(source_loc source, level::level_enum lvl, const wchar_t *fmt, const Args &... args)
+{
+ if (!should_log(lvl))
+ {
+ return;
+ }
+
+ try
+ {
+ // format to wmemory_buffer and convert to utf8
+ using details::fmt_helper::to_string_view;
+ fmt::wmemory_buffer wbuf;
+ fmt::format_to(wbuf, fmt, args...);
+ fmt::memory_buffer buf;
+ wbuf_to_utf8buf(wbuf, buf);
+ details::log_msg log_msg(source, &name_, lvl, to_string_view(buf));
+ sink_it_(log_msg);
+ }
+ SPDLOG_CATCH_AND_HANDLE
+}
+
+template<typename... Args>
+inline void spdlog::logger::log(level::level_enum lvl, const wchar_t *fmt, const Args &... args)
+{
+ log(source_loc{}, lvl, fmt, args...);
+}
+
+template<typename... Args>
+inline void spdlog::logger::trace(const wchar_t *fmt, const Args &... args)
+{
+ log(level::trace, fmt, args...);
+}
+
+template<typename... Args>
+inline void spdlog::logger::debug(const wchar_t *fmt, const Args &... args)
+{
+ log(level::debug, fmt, args...);
+}
+
+template<typename... Args>
+inline void spdlog::logger::info(const wchar_t *fmt, const Args &... args)
+{
+ log(level::info, fmt, args...);
+}
+
+template<typename... Args>
+inline void spdlog::logger::warn(const wchar_t *fmt, const Args &... args)
+{
+ log(level::warn, fmt, args...);
+}
+
+template<typename... Args>
+inline void spdlog::logger::error(const wchar_t *fmt, const Args &... args)
+{
+ log(level::err, fmt, args...);
+}
+
+template<typename... Args>
+inline void spdlog::logger::critical(const wchar_t *fmt, const Args &... args)
+{
+ log(level::critical, fmt, args...);
+}
+
+#endif // SPDLOG_WCHAR_TO_UTF8_SUPPORT
+
+//
+// name and level
+//
+inline const std::string &spdlog::logger::name() const
+{
+ return name_;
+}
+
+inline void spdlog::logger::set_level(spdlog::level::level_enum log_level)
+{
+ level_.store(log_level);
+}
+
+inline void spdlog::logger::set_error_handler(spdlog::log_err_handler err_handler)
+{
+ err_handler_ = std::move(err_handler);
+}
+
+inline spdlog::log_err_handler spdlog::logger::error_handler() const
+{
+ return err_handler_;
+}
+
+inline void spdlog::logger::flush()
+{
+ try
+ {
+ flush_();
+ }
+ SPDLOG_CATCH_AND_HANDLE
+}
+
+inline void spdlog::logger::flush_on(level::level_enum log_level)
+{
+ flush_level_.store(log_level);
+}
+
+inline spdlog::level::level_enum spdlog::logger::flush_level() const
+{
+ return static_cast<spdlog::level::level_enum>(flush_level_.load(std::memory_order_relaxed));
+}
+
+inline bool spdlog::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);
+}
+
+inline spdlog::level::level_enum spdlog::logger::default_level()
+{
+ return static_cast<spdlog::level::level_enum>(SPDLOG_ACTIVE_LEVEL);
+}
+
+inline spdlog::level::level_enum spdlog::logger::level() const
+{
+ return static_cast<spdlog::level::level_enum>(level_.load(std::memory_order_relaxed));
+}
+
+inline bool spdlog::logger::should_log(spdlog::level::level_enum msg_level) const
+{
+ return msg_level >= level_.load(std::memory_order_relaxed);
+}
+
+//
+// protected virtual called at end of each user log call (if enabled) by the
+// line_logger
+//
+inline void spdlog::logger::sink_it_(details::log_msg &msg)
+{
+#if defined(SPDLOG_ENABLE_MESSAGE_COUNTER)
+ incr_msg_counter_(msg);
+#endif
+ for (auto &sink : sinks_)
+ {
+ if (sink->should_log(msg.level))
+ {
+ sink->log(msg);
+ }
+ }
+
+ if (should_flush_(msg))
+ {
+ flush_();
+ }
+}
+
+inline void spdlog::logger::flush_()
+{
+ for (auto &sink : sinks_)
+ {
+ sink->flush();
+ }
+}
+
+inline void spdlog::logger::default_err_handler_(const std::string &msg)
+{
+ auto now = time(nullptr);
+ if (now - last_err_time_ < 60)
+ {
+ return;
+ }
+ last_err_time_ = now;
+ auto tm_time = details::os::localtime(now);
+ char date_buf[100];
+ std::strftime(date_buf, sizeof(date_buf), "%Y-%m-%d %H:%M:%S", &tm_time);
+ fmt::print(stderr, "[*** LOG ERROR ***] [{}] [{}] {}\n", date_buf, name(), msg);
+}
+
+inline void spdlog::logger::incr_msg_counter_(details::log_msg &msg)
+{
+ msg.msg_id = msg_counter_.fetch_add(1, std::memory_order_relaxed);
+}
+
+inline const std::vector<spdlog::sink_ptr> &spdlog::logger::sinks() const
+{
+ return sinks_;
+}
+
+inline std::vector<spdlog::sink_ptr> &spdlog::logger::sinks()
+{
+ return sinks_;
+}
+
+inline std::shared_ptr<spdlog::logger> spdlog::logger::clone(std::string logger_name)
+{
+ auto cloned = std::make_shared<spdlog::logger>(std::move(logger_name), sinks_.begin(), sinks_.end());
+ cloned->set_level(this->level());
+ cloned->flush_on(this->flush_level());
+ cloned->set_error_handler(this->error_handler());
+ return cloned;
+}
diff --git a/matching/include/spdlog/details/mpmc_blocking_q.h b/matching/include/spdlog/details/mpmc_blocking_q.h
new file mode 100644
index 0000000..ca789fc
--- /dev/null
+++ b/matching/include/spdlog/details/mpmc_blocking_q.h
@@ -0,0 +1,121 @@
+#pragma once
+
+//
+// Copyright(c) 2018 Gabi Melman.
+// Distributed under the MIT License (http://opensource.org/licenses/MIT)
+//
+
+// 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;
+ }
+ q_.pop_front(popped_item);
+ }
+ 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;
+ }
+ q_.pop_front(popped_item);
+ pop_cv_.notify_one();
+ return true;
+ }
+
+#endif
+
+ size_t overrun_counter()
+ {
+ std::unique_lock<std::mutex> lock(queue_mutex_);
+ return q_.overrun_counter();
+ }
+
+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
diff --git a/matching/include/spdlog/details/null_mutex.h b/matching/include/spdlog/details/null_mutex.h
new file mode 100644
index 0000000..3f495bd
--- /dev/null
+++ b/matching/include/spdlog/details/null_mutex.h
@@ -0,0 +1,45 @@
+//
+// Copyright(c) 2015 Gabi Melman.
+// Distributed under the MIT License (http://opensource.org/licenses/MIT)
+//
+
+#pragma once
+
+#include <atomic>
+// null, no cost dummy "mutex" and dummy "atomic" int
+
+namespace spdlog {
+namespace details {
+struct null_mutex
+{
+ void lock() {}
+ void unlock() {}
+ bool try_lock()
+ {
+ return true;
+ }
+};
+
+struct null_atomic_int
+{
+ int value;
+ null_atomic_int() = default;
+
+ explicit null_atomic_int(int val)
+ : value(val)
+ {
+ }
+
+ int load(std::memory_order) const
+ {
+ return value;
+ }
+
+ void store(int val)
+ {
+ value = val;
+ }
+};
+
+} // namespace details
+} // namespace spdlog
diff --git a/matching/include/spdlog/details/os.h b/matching/include/spdlog/details/os.h
new file mode 100644
index 0000000..646805e
--- /dev/null
+++ b/matching/include/spdlog/details/os.h
@@ -0,0 +1,421 @@
+//
+// Copyright(c) 2015 Gabi Melman.
+// Distributed under the MIT License (http://opensource.org/licenses/MIT)
+//
+#pragma once
+
+#include "../common.h"
+
+#include <algorithm>
+#include <chrono>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <ctime>
+#include <functional>
+#include <string>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <thread>
+
+#ifdef _WIN32
+
+#ifndef NOMINMAX
+#define NOMINMAX // prevent windows redefining min/max
+#endif
+
+#ifndef WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN
+#endif
+#include <io.h> // _get_osfhandle and _isatty support
+#include <process.h> // _get_pid support
+#include <windows.h>
+
+#ifdef __MINGW32__
+#include <share.h>
+#endif
+
+#else // unix
+
+#include <fcntl.h>
+#include <unistd.h>
+
+#ifdef __linux__
+#include <sys/syscall.h> //Use gettid() syscall under linux to get thread id
+
+#elif __FreeBSD__
+#include <sys/thr.h> //Use thr_self() syscall under FreeBSD to get thread id
+#endif
+
+#endif // unix
+
+#ifndef __has_feature // Clang - feature checking macros.
+#define __has_feature(x) 0 // Compatibility with non-clang compilers.
+#endif
+
+namespace spdlog {
+namespace details {
+namespace os {
+
+inline spdlog::log_clock::time_point now() SPDLOG_NOEXCEPT
+{
+
+#if defined __linux__ && defined SPDLOG_CLOCK_COARSE
+ timespec ts;
+ ::clock_gettime(CLOCK_REALTIME_COARSE, &ts);
+ return std::chrono::time_point<log_clock, typename log_clock::duration>(
+ std::chrono::duration_cast<typename log_clock::duration>(std::chrono::seconds(ts.tv_sec) + std::chrono::nanoseconds(ts.tv_nsec)));
+
+#else
+ return log_clock::now();
+#endif
+}
+inline std::tm localtime(const std::time_t &time_tt) SPDLOG_NOEXCEPT
+{
+
+#ifdef _WIN32
+ std::tm tm;
+ localtime_s(&tm, &time_tt);
+#else
+ std::tm tm;
+ localtime_r(&time_tt, &tm);
+#endif
+ return tm;
+}
+
+inline std::tm localtime() SPDLOG_NOEXCEPT
+{
+ std::time_t now_t = time(nullptr);
+ return localtime(now_t);
+}
+
+inline std::tm gmtime(const std::time_t &time_tt) SPDLOG_NOEXCEPT
+{
+
+#ifdef _WIN32
+ std::tm tm;
+ gmtime_s(&tm, &time_tt);
+#else
+ std::tm tm;
+ gmtime_r(&time_tt, &tm);
+#endif
+ return tm;
+}
+
+inline std::tm gmtime() SPDLOG_NOEXCEPT
+{
+ std::time_t now_t = time(nullptr);
+ return gmtime(now_t);
+}
+
+// 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
+#ifdef _WIN32
+SPDLOG_CONSTEXPR static const char folder_sep = '\\';
+#else
+SPDLOG_CONSTEXPR static const char folder_sep = '/';
+#endif
+
+inline void prevent_child_fd(FILE *f)
+{
+
+#ifdef _WIN32
+#if !defined(__cplusplus_winrt)
+ auto file_handle = (HANDLE)_get_osfhandle(_fileno(f));
+ if (!::SetHandleInformation(file_handle, HANDLE_FLAG_INHERIT, 0))
+ throw spdlog_ex("SetHandleInformation failed", errno);
+#endif
+#else
+ auto fd = fileno(f);
+ if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1)
+ {
+ throw spdlog_ex("fcntl with FD_CLOEXEC failed", errno);
+ }
+#endif
+}
+
+// fopen_s on non windows for writing
+inline bool fopen_s(FILE **fp, const filename_t &filename, const filename_t &mode)
+{
+#ifdef _WIN32
+#ifdef SPDLOG_WCHAR_FILENAMES
+ *fp = _wfsopen((filename.c_str()), mode.c_str(), _SH_DENYNO);
+#else
+ *fp = _fsopen((filename.c_str()), mode.c_str(), _SH_DENYNO);
+#endif
+#else // unix
+ *fp = fopen((filename.c_str()), mode.c_str());
+#endif
+
+#ifdef SPDLOG_PREVENT_CHILD_FD
+ if (*fp != nullptr)
+ {
+ prevent_child_fd(*fp);
+ }
+#endif
+ return *fp == nullptr;
+}
+
+inline int remove(const filename_t &filename) SPDLOG_NOEXCEPT
+{
+#if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES)
+ return _wremove(filename.c_str());
+#else
+ return std::remove(filename.c_str());
+#endif
+}
+
+inline int rename(const filename_t &filename1, const filename_t &filename2) SPDLOG_NOEXCEPT
+{
+#if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES)
+ return _wrename(filename1.c_str(), filename2.c_str());
+#else
+ return std::rename(filename1.c_str(), filename2.c_str());
+#endif
+}
+
+// Return if file exists
+inline bool file_exists(const filename_t &filename) SPDLOG_NOEXCEPT
+{
+#ifdef _WIN32
+#ifdef SPDLOG_WCHAR_FILENAMES
+ auto attribs = GetFileAttributesW(filename.c_str());
+#else
+ auto attribs = GetFileAttributesA(filename.c_str());
+#endif
+ return (attribs != INVALID_FILE_ATTRIBUTES && !(attribs & FILE_ATTRIBUTE_DIRECTORY));
+#else // common linux/unix all have the stat system call
+ struct stat buffer;
+ return (stat(filename.c_str(), &buffer) == 0);
+#endif
+}
+
+// Return file size according to open FILE* object
+inline size_t filesize(FILE *f)
+{
+ if (f == nullptr)
+ {
+ throw spdlog_ex("Failed getting file size. fd is null");
+ }
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ int fd = _fileno(f);
+#if _WIN64 // 64 bits
+ __int64 ret = _filelengthi64(fd);
+ if (ret >= 0)
+ {
+ return static_cast<size_t>(ret);
+ }
+
+#else // windows 32 bits
+ long ret = _filelength(fd);
+ if (ret >= 0)
+ {
+ return static_cast<size_t>(ret);
+ }
+#endif
+
+#else // unix
+ int fd = fileno(f);
+// 64 bits(but not in osx or cygwin, where fstat64 is deprecated)
+#if !defined(__FreeBSD__) && !defined(__APPLE__) && (defined(__x86_64__) || defined(__ppc64__)) && !defined(__CYGWIN__)
+ struct stat64 st;
+ if (fstat64(fd, &st) == 0)
+ {
+ return static_cast<size_t>(st.st_size);
+ }
+#else // unix 32 bits or cygwin
+ struct stat st;
+
+ if (fstat(fd, &st) == 0)
+ {
+ return static_cast<size_t>(st.st_size);
+ }
+#endif
+#endif
+ throw spdlog_ex("Failed getting file size from fd", errno);
+}
+
+// Return utc offset in minutes or throw spdlog_ex on failure
+inline int utc_minutes_offset(const std::tm &tm = details::os::localtime())
+{
+
+#ifdef _WIN32
+#if _WIN32_WINNT < _WIN32_WINNT_WS08
+ TIME_ZONE_INFORMATION tzinfo;
+ auto rv = GetTimeZoneInformation(&tzinfo);
+#else
+ DYNAMIC_TIME_ZONE_INFORMATION tzinfo;
+ auto rv = GetDynamicTimeZoneInformation(&tzinfo);
+#endif
+ if (rv == TIME_ZONE_ID_INVALID)
+ throw spdlog::spdlog_ex("Failed getting timezone info. ", errno);
+
+ int offset = -tzinfo.Bias;
+ if (tm.tm_isdst)
+ {
+ offset -= tzinfo.DaylightBias;
+ }
+ else
+ {
+ offset -= tzinfo.StandardBias;
+ }
+ return offset;
+#else
+
+#if defined(sun) || defined(__sun) || defined(_AIX)
+ // 'tm_gmtoff' field is BSD extension and it's missing on SunOS/Solaris
+ struct helper
+ {
+ static long int calculate_gmt_offset(const std::tm &localtm = details::os::localtime(), const std::tm &gmtm = details::os::gmtime())
+ {
+ int local_year = localtm.tm_year + (1900 - 1);
+ int gmt_year = gmtm.tm_year + (1900 - 1);
+
+ long int days = (
+ // difference in day of year
+ localtm.tm_yday -
+ gmtm.tm_yday
+
+ // + intervening leap days
+ + ((local_year >> 2) - (gmt_year >> 2)) - (local_year / 100 - gmt_year / 100) +
+ ((local_year / 100 >> 2) - (gmt_year / 100 >> 2))
+
+ // + difference in years * 365 */
+ + (long int)(local_year - gmt_year) * 365);
+
+ long int hours = (24 * days) + (localtm.tm_hour - gmtm.tm_hour);
+ long int mins = (60 * hours) + (localtm.tm_min - gmtm.tm_min);
+ long int secs = (60 * mins) + (localtm.tm_sec - gmtm.tm_sec);
+
+ return secs;
+ }
+ };
+
+ auto offset_seconds = helper::calculate_gmt_offset(tm);
+#else
+ auto offset_seconds = tm.tm_gmtoff;
+#endif
+
+ return static_cast<int>(offset_seconds / 60);
+#endif
+}
+
+// Return current thread id as size_t
+// It exists because the std::this_thread::get_id() is much slower(especially
+// under VS 2013)
+inline size_t _thread_id() SPDLOG_NOEXCEPT
+{
+#ifdef _WIN32
+ return static_cast<size_t>(::GetCurrentThreadId());
+#elif __linux__
+#if defined(__ANDROID__) && defined(__ANDROID_API__) && (__ANDROID_API__ < 21)
+#define SYS_gettid __NR_gettid
+#endif
+ return static_cast<size_t>(syscall(SYS_gettid));
+#elif __FreeBSD__
+ long tid;
+ thr_self(&tid);
+ return static_cast<size_t>(tid);
+#elif __APPLE__
+ uint64_t tid;
+ pthread_threadid_np(nullptr, &tid);
+ return static_cast<size_t>(tid);
+#else // Default to standard C++11 (other Unix)
+ return static_cast<size_t>(std::hash<std::thread::id>()(std::this_thread::get_id()));
+#endif
+}
+
+// Return current thread id as size_t (from thread local storage)
+inline size_t thread_id() SPDLOG_NOEXCEPT
+{
+#if defined(SPDLOG_NO_TLS)
+ return _thread_id();
+#else // cache thread id in tls
+ static thread_local const size_t tid = _thread_id();
+ return tid;
+#endif
+}
+
+// This is avoid msvc issue in sleep_for that happens if the clock changes.
+// See https://github.com/gabime/spdlog/issues/609
+inline void sleep_for_millis(int milliseconds) SPDLOG_NOEXCEPT
+{
+#if defined(_WIN32)
+ ::Sleep(milliseconds);
+#else
+ std::this_thread::sleep_for(std::chrono::milliseconds(milliseconds));
+#endif
+}
+
+// wchar support for windows file names (SPDLOG_WCHAR_FILENAMES must be defined)
+#if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES)
+#define SPDLOG_FILENAME_T(s) L##s
+inline std::string filename_to_str(const filename_t &filename)
+{
+ std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> c;
+ return c.to_bytes(filename);
+}
+#else
+#define SPDLOG_FILENAME_T(s) s
+inline std::string filename_to_str(const filename_t &filename)
+{
+ return filename;
+}
+#endif
+
+inline int pid()
+{
+
+#ifdef _WIN32
+ return static_cast<int>(::GetCurrentProcessId());
+#else
+ return static_cast<int>(::getpid());
+#endif
+}
+
+// Determine if the terminal supports colors
+// Source: https://github.com/agauniyal/rang/
+inline bool is_color_terminal() SPDLOG_NOEXCEPT
+{
+#ifdef _WIN32
+ return true;
+#else
+ static constexpr const char *Terms[] = {
+ "ansi", "color", "console", "cygwin", "gnome", "konsole", "kterm", "linux", "msys", "putty", "rxvt", "screen", "vt100", "xterm"};
+
+ const char *env_p = std::getenv("TERM");
+ if (env_p == nullptr)
+ {
+ return false;
+ }
+
+ static const bool result =
+ std::any_of(std::begin(Terms), std::end(Terms), [&](const char *term) { return std::strstr(env_p, term) != nullptr; });
+ return result;
+#endif
+}
+
+// Detrmine if the terminal attached
+// Source: https://github.com/agauniyal/rang/
+inline bool in_terminal(FILE *file) SPDLOG_NOEXCEPT
+{
+
+#ifdef _WIN32
+ return _isatty(_fileno(file)) != 0;
+#else
+ return isatty(fileno(file)) != 0;
+#endif
+}
+} // namespace os
+} // namespace details
+} // namespace spdlog
diff --git a/matching/include/spdlog/details/pattern_formatter.h b/matching/include/spdlog/details/pattern_formatter.h
new file mode 100644
index 0000000..c0ad86e
--- /dev/null
+++ b/matching/include/spdlog/details/pattern_formatter.h
@@ -0,0 +1,1336 @@
+//
+// Copyright(c) 2015 Gabi Melman.
+// Distributed under the MIT License (http://opensource.org/licenses/MIT)
+//
+
+#pragma once
+
+#include "spdlog/details/fmt_helper.h"
+#include "spdlog/details/log_msg.h"
+#include "spdlog/details/os.h"
+#include "spdlog/fmt/fmt.h"
+#include "spdlog/formatter.h"
+
+#include <array>
+#include <chrono>
+#include <ctime>
+#include <cctype>
+#include <memory>
+#include <mutex>
+#include <string>
+#include <thread>
+#include <utility>
+#include <vector>
+
+namespace spdlog {
+namespace details {
+
+// padding information.
+struct padding_info
+{
+ enum pad_side
+ {
+ left,
+ right,
+ center
+ };
+
+ padding_info() = default;
+ padding_info(size_t width, padding_info::pad_side side)
+ : width_(width)
+ , side_(side)
+ {
+ }
+
+ bool enabled() const
+ {
+ return width_ != 0;
+ }
+ const size_t width_ = 0;
+ const pad_side side_ = left;
+};
+
+class scoped_pad
+{
+public:
+ scoped_pad(size_t wrapped_size, padding_info &padinfo, fmt::memory_buffer &dest)
+ : padinfo_(padinfo)
+ , dest_(dest)
+ {
+
+ if (padinfo_.width_ <= wrapped_size)
+ {
+ total_pad_ = 0;
+ return;
+ }
+
+ total_pad_ = padinfo.width_ - wrapped_size;
+ if (padinfo_.side_ == padding_info::left)
+ {
+ pad_it(total_pad_);
+ total_pad_ = 0;
+ }
+ else if (padinfo_.side_ == padding_info::center)
+ {
+ auto half_pad = total_pad_ / 2;
+ auto reminder = total_pad_ & 1;
+ pad_it(half_pad);
+ total_pad_ = half_pad + reminder; // for the right side
+ }
+ }
+
+ scoped_pad(spdlog::string_view_t txt, padding_info &padinfo, fmt::memory_buffer &dest)
+ : scoped_pad(txt.size(), padinfo, dest)
+ {
+ }
+
+ ~scoped_pad()
+ {
+ if (total_pad_)
+ {
+ pad_it(total_pad_);
+ }
+ }
+
+private:
+ void pad_it(size_t count)
+ {
+ // count = std::min(count, spaces_.size());
+ assert(count <= spaces_.size());
+ fmt_helper::append_string_view(string_view_t(spaces_.data(), count), dest_);
+ }
+
+ const padding_info &padinfo_;
+ fmt::memory_buffer &dest_;
+ size_t total_pad_;
+ string_view_t spaces_{" "
+ " ",
+ 128};
+};
+
+class 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, fmt::memory_buffer &dest) = 0;
+
+protected:
+ padding_info padinfo_;
+};
+
+///////////////////////////////////////////////////////////////////////
+// name & level pattern appender
+///////////////////////////////////////////////////////////////////////
+class name_formatter : public flag_formatter
+{
+public:
+ explicit name_formatter(padding_info padinfo)
+ : flag_formatter(padinfo)
+ {
+ }
+
+ void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override
+ {
+ if (padinfo_.enabled())
+ {
+ scoped_pad p(*msg.logger_name, padinfo_, dest);
+ fmt_helper::append_string_view(*msg.logger_name, dest);
+ }
+ else
+ {
+ fmt_helper::append_string_view(*msg.logger_name, dest);
+ }
+ }
+};
+
+// log level appender
+class level_formatter : public flag_formatter
+{
+public:
+ explicit level_formatter(padding_info padinfo)
+ : flag_formatter(padinfo)
+ {
+ }
+
+ void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override
+ {
+ string_view_t &level_name = level::to_string_view(msg.level);
+ if (padinfo_.enabled())
+ {
+ scoped_pad p(level_name, padinfo_, dest);
+ fmt_helper::append_string_view(level_name, dest);
+ }
+ else
+ {
+ fmt_helper::append_string_view(level_name, dest);
+ }
+ }
+};
+
+// short log level appender
+class short_level_formatter : public flag_formatter
+{
+public:
+ explicit short_level_formatter(padding_info padinfo)
+ : flag_formatter(padinfo)
+ {
+ }
+
+ void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override
+ {
+ string_view_t level_name{level::to_short_c_str(msg.level)};
+ scoped_pad p(level_name, padinfo_, dest);
+ fmt_helper::append_string_view(level_name, dest);
+ }
+};
+
+///////////////////////////////////////////////////////////////////////
+// Date time pattern appenders
+///////////////////////////////////////////////////////////////////////
+
+static const char *ampm(const tm &t)
+{
+ return t.tm_hour >= 12 ? "PM" : "AM";
+}
+
+static int to12h(const tm &t)
+{
+ return t.tm_hour > 12 ? t.tm_hour - 12 : t.tm_hour;
+}
+
+// Abbreviated weekday name
+static const char *days[]{"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
+class a_formatter : public flag_formatter
+{
+public:
+ explicit a_formatter(padding_info padinfo)
+ : flag_formatter(padinfo)
+ {
+ }
+
+ void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override
+ {
+ string_view_t field_value{days[tm_time.tm_wday]};
+ scoped_pad p(field_value, padinfo_, dest);
+ fmt_helper::append_string_view(field_value, dest);
+ }
+};
+
+// Full weekday name
+static const char *full_days[]{"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
+class A_formatter : public flag_formatter
+{
+public:
+ explicit A_formatter(padding_info padinfo)
+ : flag_formatter(padinfo)
+ {
+ }
+
+ void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override
+ {
+ string_view_t field_value{full_days[tm_time.tm_wday]};
+ scoped_pad p(field_value, padinfo_, dest);
+ fmt_helper::append_string_view(field_value, dest);
+ }
+};
+
+// Abbreviated month
+static const char *months[]{"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sept", "Oct", "Nov", "Dec"};
+class b_formatter : public flag_formatter
+{
+public:
+ explicit b_formatter(padding_info padinfo)
+ : flag_formatter(padinfo)
+ {
+ }
+
+ void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override
+ {
+ string_view_t field_value{months[tm_time.tm_mon]};
+ scoped_pad p(field_value, padinfo_, dest);
+ fmt_helper::append_string_view(field_value, dest);
+ }
+};
+
+// Full month name
+static const char *full_months[]{
+ "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"};
+class B_formatter : public flag_formatter
+{
+public:
+ explicit B_formatter(padding_info padinfo)
+ : flag_formatter(padinfo)
+ {
+ }
+
+ void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override
+ {
+ string_view_t field_value{full_months[tm_time.tm_mon]};
+ scoped_pad p(field_value, padinfo_, dest);
+ fmt_helper::append_string_view(field_value, dest);
+ }
+};
+
+// Date and time representation (Thu Aug 23 15:35:46 2014)
+class c_formatter final : public flag_formatter
+{
+public:
+ explicit c_formatter(padding_info padinfo)
+ : flag_formatter(padinfo)
+ {
+ }
+
+ void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override
+ {
+ const size_t field_size = 24;
+ scoped_pad p(field_size, padinfo_, dest);
+
+ fmt_helper::append_string_view(days[tm_time.tm_wday], dest);
+ dest.push_back(' ');
+ fmt_helper::append_string_view(months[tm_time.tm_mon], dest);
+ dest.push_back(' ');
+ fmt_helper::append_int(tm_time.tm_mday, dest);
+ dest.push_back(' ');
+ // time
+
+ fmt_helper::pad2(tm_time.tm_hour, dest);
+ dest.push_back(':');
+ fmt_helper::pad2(tm_time.tm_min, dest);
+ dest.push_back(':');
+ fmt_helper::pad2(tm_time.tm_sec, dest);
+ dest.push_back(' ');
+ fmt_helper::append_int(tm_time.tm_year + 1900, dest);
+ }
+};
+
+// year - 2 digit
+class C_formatter final : public flag_formatter
+{
+public:
+ explicit C_formatter(padding_info padinfo)
+ : flag_formatter(padinfo)
+ {
+ }
+
+ void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override
+ {
+ const size_t field_size = 2;
+ scoped_pad p(field_size, padinfo_, dest);
+ fmt_helper::pad2(tm_time.tm_year % 100, dest);
+ }
+};
+
+// Short MM/DD/YY date, equivalent to %m/%d/%y 08/23/01
+class D_formatter final : public flag_formatter
+{
+public:
+ explicit D_formatter(padding_info padinfo)
+ : flag_formatter(padinfo)
+ {
+ }
+
+ void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override
+ {
+ const size_t field_size = 10;
+ scoped_pad p(field_size, padinfo_, dest);
+
+ fmt_helper::pad2(tm_time.tm_mon + 1, dest);
+ dest.push_back('/');
+ fmt_helper::pad2(tm_time.tm_mday, dest);
+ dest.push_back('/');
+ fmt_helper::pad2(tm_time.tm_year % 100, dest);
+ }
+};
+
+// year - 4 digit
+class Y_formatter final : public flag_formatter
+{
+public:
+ explicit Y_formatter(padding_info padinfo)
+ : flag_formatter(padinfo){};
+
+ void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override
+ {
+ const size_t field_size = 4;
+ scoped_pad p(field_size, padinfo_, dest);
+ fmt_helper::append_int(tm_time.tm_year + 1900, dest);
+ }
+};
+
+// month 1-12
+class m_formatter final : public flag_formatter
+{
+public:
+ explicit m_formatter(padding_info padinfo)
+ : flag_formatter(padinfo)
+ {
+ }
+
+ void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override
+ {
+ const size_t field_size = 2;
+ scoped_pad p(field_size, padinfo_, dest);
+ fmt_helper::pad2(tm_time.tm_mon + 1, dest);
+ }
+};
+
+// day of month 1-31
+class d_formatter final : public flag_formatter
+{
+public:
+ explicit d_formatter(padding_info padinfo)
+ : flag_formatter(padinfo)
+ {
+ }
+
+ void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override
+ {
+ const size_t field_size = 2;
+ scoped_pad p(field_size, padinfo_, dest);
+ fmt_helper::pad2(tm_time.tm_mday, dest);
+ }
+};
+
+// hours in 24 format 0-23
+class H_formatter final : public flag_formatter
+{
+public:
+ explicit H_formatter(padding_info padinfo)
+ : flag_formatter(padinfo)
+ {
+ }
+
+ void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override
+ {
+ const size_t field_size = 2;
+ scoped_pad p(field_size, padinfo_, dest);
+ fmt_helper::pad2(tm_time.tm_hour, dest);
+ }
+};
+
+// hours in 12 format 1-12
+class I_formatter final : public flag_formatter
+{
+public:
+ explicit I_formatter(padding_info padinfo)
+ : flag_formatter(padinfo){};
+
+ void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override
+ {
+ const size_t field_size = 2;
+ scoped_pad p(field_size, padinfo_, dest);
+ fmt_helper::pad2(to12h(tm_time), dest);
+ }
+};
+
+// minutes 0-59
+class M_formatter final : public flag_formatter
+{
+public:
+ explicit M_formatter(padding_info padinfo)
+ : flag_formatter(padinfo){};
+
+ void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override
+ {
+ const size_t field_size = 2;
+ scoped_pad p(field_size, padinfo_, dest);
+ fmt_helper::pad2(tm_time.tm_min, dest);
+ }
+};
+
+// seconds 0-59
+class S_formatter final : public flag_formatter
+{
+public:
+ explicit S_formatter(padding_info padinfo)
+ : flag_formatter(padinfo){};
+
+ void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override
+ {
+ const size_t field_size = 2;
+ scoped_pad p(field_size, padinfo_, dest);
+ fmt_helper::pad2(tm_time.tm_sec, dest);
+ }
+};
+
+// milliseconds
+class e_formatter final : public flag_formatter
+{
+public:
+ explicit e_formatter(padding_info padinfo)
+ : flag_formatter(padinfo){};
+
+ void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override
+ {
+ auto millis = fmt_helper::time_fraction<std::chrono::milliseconds>(msg.time);
+ if (padinfo_.enabled())
+ {
+ const size_t field_size = 3;
+ scoped_pad p(field_size, padinfo_, dest);
+ fmt_helper::pad3(static_cast<uint32_t>(millis.count()), dest);
+ }
+ else
+ {
+ fmt_helper::pad3(static_cast<uint32_t>(millis.count()), dest);
+ }
+ }
+};
+
+// microseconds
+class f_formatter final : public flag_formatter
+{
+public:
+ explicit f_formatter(padding_info padinfo)
+ : flag_formatter(padinfo){};
+
+ void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override
+ {
+ auto micros = fmt_helper::time_fraction<std::chrono::microseconds>(msg.time);
+ if (padinfo_.enabled())
+ {
+ const size_t field_size = 6;
+ scoped_pad p(field_size, padinfo_, dest);
+ fmt_helper::pad6(static_cast<size_t>(micros.count()), dest);
+ }
+ else
+ {
+ fmt_helper::pad6(static_cast<size_t>(micros.count()), dest);
+ }
+ }
+};
+
+// nanoseconds
+class F_formatter final : public flag_formatter
+{
+public:
+ explicit F_formatter(padding_info padinfo)
+ : flag_formatter(padinfo){};
+
+ void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override
+ {
+ auto ns = fmt_helper::time_fraction<std::chrono::nanoseconds>(msg.time);
+ if (padinfo_.enabled())
+ {
+ const size_t field_size = 9;
+ scoped_pad p(field_size, padinfo_, dest);
+ fmt_helper::pad9(static_cast<size_t>(ns.count()), dest);
+ }
+ else
+ {
+ fmt_helper::pad9(static_cast<size_t>(ns.count()), dest);
+ }
+ }
+};
+
+// seconds since epoch
+class E_formatter final : public flag_formatter
+{
+public:
+ explicit E_formatter(padding_info padinfo)
+ : flag_formatter(padinfo){};
+
+ void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override
+ {
+ const size_t field_size = 10;
+ scoped_pad p(field_size, padinfo_, dest);
+ auto duration = msg.time.time_since_epoch();
+ auto seconds = std::chrono::duration_cast<std::chrono::seconds>(duration).count();
+ fmt_helper::append_int(seconds, dest);
+ }
+};
+
+// AM/PM
+class p_formatter final : public flag_formatter
+{
+public:
+ explicit p_formatter(padding_info padinfo)
+ : flag_formatter(padinfo){};
+
+ void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override
+ {
+ const size_t field_size = 2;
+ scoped_pad p(field_size, padinfo_, dest);
+ fmt_helper::append_string_view(ampm(tm_time), dest);
+ }
+};
+
+// 12 hour clock 02:55:02 pm
+class r_formatter final : public flag_formatter
+{
+public:
+ explicit r_formatter(padding_info padinfo)
+ : flag_formatter(padinfo){};
+
+ void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override
+ {
+ const size_t field_size = 11;
+ scoped_pad p(field_size, padinfo_, dest);
+
+ fmt_helper::pad2(to12h(tm_time), dest);
+ dest.push_back(':');
+ fmt_helper::pad2(tm_time.tm_min, dest);
+ dest.push_back(':');
+ fmt_helper::pad2(tm_time.tm_sec, dest);
+ dest.push_back(' ');
+ fmt_helper::append_string_view(ampm(tm_time), dest);
+ }
+};
+
+// 24-hour HH:MM time, equivalent to %H:%M
+class R_formatter final : public flag_formatter
+{
+public:
+ explicit R_formatter(padding_info padinfo)
+ : flag_formatter(padinfo){};
+
+ void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override
+ {
+ const size_t field_size = 5;
+ scoped_pad p(field_size, padinfo_, dest);
+
+ fmt_helper::pad2(tm_time.tm_hour, dest);
+ dest.push_back(':');
+ fmt_helper::pad2(tm_time.tm_min, dest);
+ }
+};
+
+// ISO 8601 time format (HH:MM:SS), equivalent to %H:%M:%S
+class T_formatter final : public flag_formatter
+{
+public:
+ explicit T_formatter(padding_info padinfo)
+ : flag_formatter(padinfo){};
+
+ void format(const details::log_msg &, const std::tm &tm_time, fmt::memory_buffer &dest) override
+ {
+ const size_t field_size = 8;
+ scoped_pad p(field_size, padinfo_, dest);
+
+ fmt_helper::pad2(tm_time.tm_hour, dest);
+ dest.push_back(':');
+ fmt_helper::pad2(tm_time.tm_min, dest);
+ dest.push_back(':');
+ fmt_helper::pad2(tm_time.tm_sec, dest);
+ }
+};
+
+// ISO 8601 offset from UTC in timezone (+-HH:MM)
+class z_formatter final : public flag_formatter
+{
+public:
+ explicit z_formatter(padding_info padinfo)
+ : flag_formatter(padinfo){};
+
+ const std::chrono::seconds cache_refresh = std::chrono::seconds(5);
+
+ z_formatter() = default;
+ z_formatter(const z_formatter &) = delete;
+ z_formatter &operator=(const z_formatter &) = delete;
+
+ void format(const details::log_msg &msg, const std::tm &tm_time, fmt::memory_buffer &dest) override
+ {
+ const size_t field_size = 6;
+ scoped_pad p(field_size, padinfo_, dest);
+
+#ifdef _WIN32
+ int total_minutes = get_cached_offset(msg, tm_time);
+#else
+ // No need to chache under gcc,
+ // it is very fast (already stored in tm.tm_gmtoff)
+ (void)(msg);
+ int total_minutes = os::utc_minutes_offset(tm_time);
+#endif
+ bool is_negative = total_minutes < 0;
+ if (is_negative)
+ {
+ total_minutes = -total_minutes;
+ dest.push_back('-');
+ }
+ else
+ {
+ dest.push_back('+');
+ }
+
+ fmt_helper::pad2(total_minutes / 60, dest); // hours
+ dest.push_back(':');
+ fmt_helper::pad2(total_minutes % 60, dest); // minutes
+ }
+
+private:
+ log_clock::time_point last_update_{std::chrono::seconds(0)};
+#ifdef _WIN32
+ int offset_minutes_{0};
+
+ int get_cached_offset(const log_msg &msg, const std::tm &tm_time)
+ {
+ if (msg.time - last_update_ >= cache_refresh)
+ {
+ offset_minutes_ = os::utc_minutes_offset(tm_time);
+ last_update_ = msg.time;
+ }
+ return offset_minutes_;
+ }
+#endif
+};
+
+// Thread id
+class t_formatter final : public flag_formatter
+{
+public:
+ explicit t_formatter(padding_info padinfo)
+ : flag_formatter(padinfo){};
+
+ void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override
+ {
+ if (padinfo_.enabled())
+ {
+ const auto field_size = fmt_helper::count_digits(msg.thread_id);
+ scoped_pad p(field_size, padinfo_, dest);
+ fmt_helper::append_int(msg.thread_id, dest);
+ }
+ else
+ {
+ fmt_helper::append_int(msg.thread_id, dest);
+ }
+ }
+};
+
+// Current pid
+class pid_formatter final : public flag_formatter
+{
+public:
+ explicit pid_formatter(padding_info padinfo)
+ : flag_formatter(padinfo){};
+
+ void format(const details::log_msg &, const std::tm &, fmt::memory_buffer &dest) override
+ {
+ const auto pid = static_cast<uint32_t>(details::os::pid());
+ if (padinfo_.enabled())
+ {
+ auto field_size = fmt_helper::count_digits(pid);
+ scoped_pad p(field_size, padinfo_, dest);
+ fmt_helper::append_int(pid, dest);
+ }
+ else
+ {
+ fmt_helper::append_int(pid, dest);
+ }
+ }
+};
+
+// message counter formatter
+class i_formatter final : public flag_formatter
+{
+public:
+ explicit i_formatter(padding_info padinfo)
+ : flag_formatter(padinfo){};
+
+ void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override
+ {
+ const size_t field_size = 6;
+ scoped_pad p(field_size, padinfo_, dest);
+ fmt_helper::pad6(msg.msg_id, dest);
+ }
+};
+
+class v_formatter final : public flag_formatter
+{
+public:
+ explicit v_formatter(padding_info padinfo)
+ : flag_formatter(padinfo){};
+
+ void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override
+ {
+ if (padinfo_.enabled())
+ {
+ scoped_pad p(msg.payload, padinfo_, dest);
+ fmt_helper::append_string_view(msg.payload, dest);
+ }
+ else
+ {
+ fmt_helper::append_string_view(msg.payload, dest);
+ }
+ }
+};
+
+class ch_formatter final : public flag_formatter
+{
+public:
+ explicit ch_formatter(char ch)
+ : ch_(ch)
+ {
+ }
+
+ void format(const details::log_msg &, const std::tm &, fmt::memory_buffer &dest) override
+ {
+ const size_t field_size = 1;
+ scoped_pad p(field_size, padinfo_, dest);
+ dest.push_back(ch_);
+ }
+
+private:
+ char ch_;
+};
+
+// aggregate user chars to display as is
+class aggregate_formatter final : public flag_formatter
+{
+public:
+ aggregate_formatter() = default;
+
+ void add_ch(char ch)
+ {
+ str_ += ch;
+ }
+ void format(const details::log_msg &, const std::tm &, fmt::memory_buffer &dest) override
+ {
+ fmt_helper::append_string_view(str_, dest);
+ }
+
+private:
+ std::string str_;
+};
+
+// mark the color range. expect it to be in the form of "%^colored text%$"
+class color_start_formatter final : public flag_formatter
+{
+public:
+ explicit color_start_formatter(padding_info padinfo)
+ : flag_formatter(padinfo)
+ {
+ }
+
+ void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override
+ {
+ msg.color_range_start = dest.size();
+ }
+};
+class color_stop_formatter final : public flag_formatter
+{
+public:
+ explicit color_stop_formatter(padding_info padinfo)
+ : flag_formatter(padinfo)
+ {
+ }
+
+ void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override
+ {
+ msg.color_range_end = dest.size();
+ }
+};
+
+// print source location
+class source_location_formatter final : public flag_formatter
+{
+public:
+ explicit source_location_formatter(padding_info padinfo)
+ : flag_formatter(padinfo){};
+
+ void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override
+ {
+ if (msg.source.empty())
+ {
+ return;
+ }
+ if (padinfo_.enabled())
+ {
+ const auto text_size = std::char_traits<char>::length(msg.source.filename) + fmt_helper::count_digits(msg.source.line) + 1;
+ scoped_pad p(text_size, padinfo_, dest);
+ fmt_helper::append_string_view(msg.source.filename, dest);
+ dest.push_back(':');
+ fmt_helper::append_int(msg.source.line, dest);
+ }
+ else
+ {
+ fmt_helper::append_string_view(msg.source.filename, dest);
+ dest.push_back(':');
+ fmt_helper::append_int(msg.source.line, dest);
+ }
+ }
+};
+// print source filename
+class source_filename_formatter final : public flag_formatter
+{
+public:
+ explicit source_filename_formatter(padding_info padinfo)
+ : flag_formatter(padinfo){};
+
+ void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override
+ {
+ if (msg.source.empty())
+ {
+ return;
+ }
+ scoped_pad p(msg.source.filename, padinfo_, dest);
+ fmt_helper::append_string_view(msg.source.filename, dest);
+ }
+};
+
+class source_linenum_formatter final : public flag_formatter
+{
+public:
+ explicit source_linenum_formatter(padding_info padinfo)
+ : flag_formatter(padinfo){};
+
+ void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override
+ {
+ if (msg.source.empty())
+ {
+ return;
+ }
+ if (padinfo_.enabled())
+ {
+ auto field_size = fmt_helper::count_digits(msg.source.line);
+ scoped_pad p(field_size, padinfo_, dest);
+ fmt_helper::append_int(msg.source.line, dest);
+ }
+ else
+ {
+ fmt_helper::append_int(msg.source.line, dest);
+ }
+ }
+};
+// print source funcname
+class source_funcname_formatter final : public flag_formatter
+{
+public:
+ explicit source_funcname_formatter(padding_info padinfo)
+ : flag_formatter(padinfo){};
+
+ void format(const details::log_msg &msg, const std::tm &, fmt::memory_buffer &dest) override
+ {
+ if (msg.source.empty())
+ {
+ return;
+ }
+ scoped_pad p(msg.source.funcname, padinfo_, dest);
+ fmt_helper::append_string_view(msg.source.funcname, dest);
+ }
+};
+
+// Full info formatter
+// pattern: [%Y-%m-%d %H:%M:%S.%e] [%n] [%l] %v
+class full_formatter final : public flag_formatter
+{
+public:
+ explicit full_formatter(padding_info padinfo)
+ : flag_formatter(padinfo)
+ {
+ }
+
+ void format(const details::log_msg &msg, const std::tm &tm_time, fmt::memory_buffer &dest) override
+ {
+ using std::chrono::duration_cast;
+ using std::chrono::milliseconds;
+ using std::chrono::seconds;
+
+#ifndef SPDLOG_NO_DATETIME
+
+ // cache the date/time part for the next second.
+ auto duration = msg.time.time_since_epoch();
+ auto secs = duration_cast<seconds>(duration);
+
+ if (cache_timestamp_ != secs || cached_datetime_.size() == 0)
+ {
+ cached_datetime_.clear();
+ cached_datetime_.push_back('[');
+ fmt_helper::append_int(tm_time.tm_year + 1900, cached_datetime_);
+ cached_datetime_.push_back('-');
+
+ fmt_helper::pad2(tm_time.tm_mon + 1, cached_datetime_);
+ cached_datetime_.push_back('-');
+
+ fmt_helper::pad2(tm_time.tm_mday, cached_datetime_);
+ cached_datetime_.push_back(' ');
+
+ fmt_helper::pad2(tm_time.tm_hour, cached_datetime_);
+ cached_datetime_.push_back(':');
+
+ fmt_helper::pad2(tm_time.tm_min, cached_datetime_);
+ cached_datetime_.push_back(':');
+
+ fmt_helper::pad2(tm_time.tm_sec, cached_datetime_);
+ cached_datetime_.push_back('.');
+
+ cache_timestamp_ = secs;
+ }
+ fmt_helper::append_buf(cached_datetime_, dest);
+
+ auto millis = fmt_helper::time_fraction<milliseconds>(msg.time);
+ fmt_helper::pad3(static_cast<uint32_t>(millis.count()), dest);
+ dest.push_back(']');
+ dest.push_back(' ');
+
+#else // no datetime needed
+ (void)tm_time;
+#endif
+
+#ifndef SPDLOG_NO_NAME
+ if (!msg.logger_name->empty())
+ {
+ dest.push_back('[');
+ // fmt_helper::append_str(*msg.logger_name, dest);
+ fmt_helper::append_string_view(*msg.logger_name, dest);
+ dest.push_back(']');
+ dest.push_back(' ');
+ }
+#endif
+
+ dest.push_back('[');
+ // wrap the level name with color
+ msg.color_range_start = dest.size();
+ // fmt_helper::append_string_view(level::to_c_str(msg.level), dest);
+ fmt_helper::append_string_view(level::to_string_view(msg.level), dest);
+ msg.color_range_end = dest.size();
+ dest.push_back(']');
+ dest.push_back(' ');
+
+ // add source location if present
+ if (!msg.source.empty())
+ {
+ dest.push_back('[');
+ fmt_helper::append_string_view(msg.source.filename, dest);
+ dest.push_back(':');
+ fmt_helper::append_int(msg.source.line, dest);
+ dest.push_back(']');
+ dest.push_back(' ');
+ }
+ // fmt_helper::append_string_view(msg.msg(), dest);
+ fmt_helper::append_string_view(msg.payload, dest);
+ }
+
+private:
+ std::chrono::seconds cache_timestamp_{0};
+ fmt::basic_memory_buffer<char, 128> cached_datetime_;
+};
+
+} // namespace details
+
+class pattern_formatter final : public formatter
+{
+public:
+ explicit pattern_formatter(
+ std::string pattern, pattern_time_type time_type = pattern_time_type::local, std::string eol = spdlog::details::os::default_eol)
+ : pattern_(std::move(pattern))
+ , eol_(std::move(eol))
+ , pattern_time_type_(time_type)
+ , last_log_secs_(0)
+ {
+ std::memset(&cached_tm_, 0, sizeof(cached_tm_));
+ compile_pattern_(pattern_);
+ }
+
+ // use by default full formatter for if 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_("%+")
+ , eol_(std::move(eol))
+ , pattern_time_type_(time_type)
+ , last_log_secs_(0)
+ {
+ std::memset(&cached_tm_, 0, sizeof(cached_tm_));
+ formatters_.push_back(details::make_unique<details::full_formatter>(details::padding_info{}));
+ }
+
+ pattern_formatter(const pattern_formatter &other) = delete;
+ pattern_formatter &operator=(const pattern_formatter &other) = delete;
+
+ std::unique_ptr<formatter> clone() const override
+ {
+ return details::make_unique<pattern_formatter>(pattern_, pattern_time_type_, eol_);
+ }
+
+ void format(const details::log_msg &msg, fmt::memory_buffer &dest) override
+ {
+#ifndef SPDLOG_NO_DATETIME
+ auto secs = std::chrono::duration_cast<std::chrono::seconds>(msg.time.time_since_epoch());
+ if (secs != last_log_secs_)
+ {
+ cached_tm_ = get_time_(msg);
+ last_log_secs_ = secs;
+ }
+#endif
+ for (auto &f : formatters_)
+ {
+ f->format(msg, cached_tm_, dest);
+ }
+ // write eol
+ details::fmt_helper::append_string_view(eol_, dest);
+ }
+
+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_;
+
+ std::tm get_time_(const details::log_msg &msg)
+ {
+ if (pattern_time_type_ == pattern_time_type::local)
+ {
+ return details::os::localtime(log_clock::to_time_t(msg.time));
+ }
+ return details::os::gmtime(log_clock::to_time_t(msg.time));
+ }
+
+ void handle_flag_(char flag, details::padding_info padding)
+ {
+ switch (flag)
+ {
+
+ case ('+'): // default formatter
+ formatters_.push_back(details::make_unique<details::full_formatter>(padding));
+ break;
+
+ case 'n': // logger name
+ formatters_.push_back(details::make_unique<details::name_formatter>(padding));
+ break;
+
+ case 'l': // level
+ formatters_.push_back(details::make_unique<details::level_formatter>(padding));
+ break;
+
+ case 'L': // short level
+ formatters_.push_back(details::make_unique<details::short_level_formatter>(padding));
+ break;
+
+ case ('t'): // thread id
+ formatters_.push_back(details::make_unique<details::t_formatter>(padding));
+ break;
+
+ case ('v'): // the message text
+ formatters_.push_back(details::make_unique<details::v_formatter>(padding));
+ break;
+
+ case ('a'): // weekday
+ formatters_.push_back(details::make_unique<details::a_formatter>(padding));
+ break;
+
+ case ('A'): // short weekday
+ formatters_.push_back(details::make_unique<details::A_formatter>(padding));
+ break;
+
+ case ('b'):
+ case ('h'): // month
+ formatters_.push_back(details::make_unique<details::b_formatter>(padding));
+ break;
+
+ case ('B'): // short month
+ formatters_.push_back(details::make_unique<details::B_formatter>(padding));
+ break;
+
+ case ('c'): // datetime
+ formatters_.push_back(details::make_unique<details::c_formatter>(padding));
+ break;
+
+ case ('C'): // year 2 digits
+ formatters_.push_back(details::make_unique<details::C_formatter>(padding));
+ break;
+
+ case ('Y'): // year 4 digits
+ formatters_.push_back(details::make_unique<details::Y_formatter>(padding));
+ break;
+
+ case ('D'):
+ case ('x'): // datetime MM/DD/YY
+ formatters_.push_back(details::make_unique<details::D_formatter>(padding));
+ break;
+
+ case ('m'): // month 1-12
+ formatters_.push_back(details::make_unique<details::m_formatter>(padding));
+ break;
+
+ case ('d'): // day of month 1-31
+ formatters_.push_back(details::make_unique<details::d_formatter>(padding));
+ break;
+
+ case ('H'): // hours 24
+ formatters_.push_back(details::make_unique<details::H_formatter>(padding));
+ break;
+
+ case ('I'): // hours 12
+ formatters_.push_back(details::make_unique<details::I_formatter>(padding));
+ break;
+
+ case ('M'): // minutes
+ formatters_.push_back(details::make_unique<details::M_formatter>(padding));
+ break;
+
+ case ('S'): // seconds
+ formatters_.push_back(details::make_unique<details::S_formatter>(padding));
+ break;
+
+ case ('e'): // milliseconds
+ formatters_.push_back(details::make_unique<details::e_formatter>(padding));
+ break;
+
+ case ('f'): // microseconds
+ formatters_.push_back(details::make_unique<details::f_formatter>(padding));
+ break;
+
+ case ('F'): // nanoseconds
+ formatters_.push_back(details::make_unique<details::F_formatter>(padding));
+ break;
+
+ case ('E'): // seconds since epoch
+ formatters_.push_back(details::make_unique<details::E_formatter>(padding));
+ break;
+
+ case ('p'): // am/pm
+ formatters_.push_back(details::make_unique<details::p_formatter>(padding));
+ break;
+
+ case ('r'): // 12 hour clock 02:55:02 pm
+ formatters_.push_back(details::make_unique<details::r_formatter>(padding));
+ break;
+
+ case ('R'): // 24-hour HH:MM time
+ formatters_.push_back(details::make_unique<details::R_formatter>(padding));
+ break;
+
+ case ('T'):
+ case ('X'): // ISO 8601 time format (HH:MM:SS)
+ formatters_.push_back(details::make_unique<details::T_formatter>(padding));
+ break;
+
+ case ('z'): // timezone
+ formatters_.push_back(details::make_unique<details::z_formatter>(padding));
+ break;
+
+ case ('P'): // pid
+ formatters_.push_back(details::make_unique<details::pid_formatter>(padding));
+ break;
+
+#ifdef SPDLOG_ENABLE_MESSAGE_COUNTER
+ case ('i'):
+ formatters_.push_back(details::make_unique<details::i_formatter>(padding));
+ break;
+#endif
+ case ('^'): // color range start
+ formatters_.push_back(details::make_unique<details::color_start_formatter>(padding));
+ break;
+
+ case ('$'): // color range end
+ formatters_.push_back(details::make_unique<details::color_stop_formatter>(padding));
+ break;
+
+ case ('@'): // source location (filename:filenumber)
+ formatters_.push_back(details::make_unique<details::source_location_formatter>(padding));
+ break;
+
+ case ('s'): // source filename
+ formatters_.push_back(details::make_unique<details::source_filename_formatter>(padding));
+ break;
+
+ case ('#'): // source line number
+ formatters_.push_back(details::make_unique<details::source_linenum_formatter>(padding));
+ break;
+
+ case ('!'): // source funcname
+ formatters_.push_back(details::make_unique<details::source_funcname_formatter>(padding));
+ break;
+
+ case ('%'): // % char
+ formatters_.push_back(details::make_unique<details::ch_formatter>('%'));
+ break;
+
+ default: // Unknown flag appears as is
+ auto unknown_flag = details::make_unique<details::aggregate_formatter>();
+ unknown_flag->add_ch('%');
+ unknown_flag->add_ch(flag);
+ formatters_.push_back((std::move(unknown_flag)));
+ break;
+ }
+ }
+
+ // Extract given pad spec (e.g. %8X)
+ // Advance the given it pass the end of the padding spec found (if any)
+ // Return padding.
+ details::padding_info handle_padspec_(std::string::const_iterator &it, std::string::const_iterator end)
+ {
+ using details::padding_info;
+ using details::scoped_pad;
+ const size_t max_width = 128;
+ if (it == end)
+ {
+ return padding_info{};
+ }
+
+ padding_info::pad_side side;
+ switch (*it)
+ {
+ case '-':
+ side = padding_info::right;
+ ++it;
+ break;
+ case '=':
+ side = padding_info::center;
+ ++it;
+ break;
+ default:
+ side = details::padding_info::left;
+ break;
+ }
+
+ if (it == end || !std::isdigit(static_cast<unsigned char>(*it)))
+ {
+ return padding_info{0, side};
+ }
+
+ auto width = static_cast<size_t>(*it - '0');
+ for (++it; it != end && std::isdigit(static_cast<unsigned char>(*it)); ++it)
+ {
+ auto digit = static_cast<size_t>(*it - '0');
+ width = width * 10 + digit;
+ }
+ return details::padding_info{std::min<size_t>(width, max_width), side};
+ }
+
+ void compile_pattern_(const std::string &pattern)
+ {
+ auto end = pattern.end();
+ std::unique_ptr<details::aggregate_formatter> user_chars;
+ formatters_.clear();
+ for (auto it = pattern.begin(); it != end; ++it)
+ {
+ if (*it == '%')
+ {
+ if (user_chars) // append user chars found so far
+ {
+ formatters_.push_back(std::move(user_chars));
+ }
+
+ auto padding = handle_padspec_(++it, end);
+
+ if (it != end)
+ {
+ handle_flag_(*it, padding);
+ }
+ else
+ {
+ break;
+ }
+ }
+ else // chars not following the % sign should be displayed as is
+ {
+ if (!user_chars)
+ {
+ user_chars = details::make_unique<details::aggregate_formatter>();
+ }
+ user_chars->add_ch(*it);
+ }
+ }
+ if (user_chars) // append raw chars found so far
+ {
+ formatters_.push_back(std::move(user_chars));
+ }
+ }
+};
+} // namespace spdlog
diff --git a/matching/include/spdlog/details/periodic_worker.h b/matching/include/spdlog/details/periodic_worker.h
new file mode 100644
index 0000000..fa6488d
--- /dev/null
+++ b/matching/include/spdlog/details/periodic_worker.h
@@ -0,0 +1,71 @@
+
+//
+// Copyright(c) 2018 Gabi Melman.
+// 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 periodic_worker
+{
+public:
+ 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();
+ }
+ });
+ }
+
+ periodic_worker(const periodic_worker &) = delete;
+ periodic_worker &operator=(const periodic_worker &) = delete;
+
+ // stop the worker thread and join it
+ ~periodic_worker()
+ {
+ if (worker_thread_.joinable())
+ {
+ {
+ std::lock_guard<std::mutex> lock(mutex_);
+ active_ = false;
+ }
+ cv_.notify_one();
+ worker_thread_.join();
+ }
+ }
+
+private:
+ bool active_;
+ std::thread worker_thread_;
+ std::mutex mutex_;
+ std::condition_variable cv_;
+};
+} // namespace details
+} // namespace spdlog
diff --git a/matching/include/spdlog/details/registry.h b/matching/include/spdlog/details/registry.h
new file mode 100644
index 0000000..ccd5395
--- /dev/null
+++ b/matching/include/spdlog/details/registry.h
@@ -0,0 +1,285 @@
+//
+// Copyright(c) 2015 Gabi Melman.
+// Distributed under the MIT License (http://opensource.org/licenses/MIT)
+//
+
+#pragma once
+
+// Loggers registy of unique name->logger pointer
+// An attempt to create a logger with an already existing name will be ignored
+// If user requests a non existing logger, nullptr will be returned
+// This class is thread safe
+
+#include "spdlog/common.h"
+#include "spdlog/details/periodic_worker.h"
+#include "spdlog/logger.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 {
+class thread_pool;
+
+class registry
+{
+public:
+ registry(const registry &) = delete;
+ registry &operator=(const registry &) = delete;
+
+ void register_logger(std::shared_ptr<logger> new_logger)
+ {
+ std::lock_guard<std::mutex> lock(logger_map_mutex_);
+ register_logger_(std::move(new_logger));
+ }
+
+ void 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_);
+ }
+
+ new_logger->set_level(level_);
+ new_logger->flush_on(flush_level_);
+
+ if (automatic_registration_)
+ {
+ register_logger_(std::move(new_logger));
+ }
+ }
+
+ std::shared_ptr<logger> 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;
+ }
+
+ std::shared_ptr<logger> 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.
+ logger *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.
+ void 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);
+ }
+
+ void set_tp(std::shared_ptr<thread_pool> tp)
+ {
+ std::lock_guard<std::recursive_mutex> lock(tp_mutex_);
+ tp_ = std::move(tp);
+ }
+
+ std::shared_ptr<thread_pool> 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
+ void 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());
+ }
+ }
+
+ void 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);
+ }
+ level_ = log_level;
+ }
+
+ void 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;
+ }
+
+ void flush_every(std::chrono::seconds interval)
+ {
+ std::lock_guard<std::mutex> lock(flusher_mutex_);
+ std::function<void()> clbk = std::bind(&registry::flush_all, this);
+ periodic_flusher_ = details::make_unique<periodic_worker>(clbk, interval);
+ }
+
+ void set_error_handler(log_err_handler handler)
+ {
+ std::lock_guard<std::mutex> lock(logger_map_mutex_);
+ for (auto &l : loggers_)
+ {
+ l.second->set_error_handler(handler);
+ }
+ err_handler_ = handler;
+ }
+
+ void 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);
+ }
+ }
+
+ void flush_all()
+ {
+ std::lock_guard<std::mutex> lock(logger_map_mutex_);
+ for (auto &l : loggers_)
+ {
+ l.second->flush();
+ }
+ }
+
+ void 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();
+ }
+ }
+
+ void 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
+ void 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();
+ }
+ }
+
+ std::recursive_mutex &tp_mutex()
+ {
+ return tp_mutex_;
+ }
+
+ void set_automatic_registration(bool automatic_regsistration)
+ {
+ std::lock_guard<std::mutex> lock(logger_map_mutex_);
+ automatic_registration_ = automatic_regsistration;
+ }
+
+ static registry &instance()
+ {
+ static registry s_instance;
+ return s_instance;
+ }
+
+private:
+ 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
+ }
+
+ ~registry() = default;
+
+ void 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");
+ }
+ }
+
+ void 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);
+ }
+
+ std::mutex logger_map_mutex_, flusher_mutex_;
+ std::recursive_mutex tp_mutex_;
+ std::unordered_map<std::string, std::shared_ptr<logger>> loggers_;
+ std::unique_ptr<formatter> formatter_;
+ level::level_enum level_ = spdlog::logger::default_level();
+ level::level_enum flush_level_ = level::off;
+ log_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;
+};
+
+} // namespace details
+} // namespace spdlog
diff --git a/matching/include/spdlog/details/thread_pool.h b/matching/include/spdlog/details/thread_pool.h
new file mode 100644
index 0000000..3557897
--- /dev/null
+++ b/matching/include/spdlog/details/thread_pool.h
@@ -0,0 +1,238 @@
+#pragma once
+
+#include "spdlog/details/fmt_helper.h"
+#include "spdlog/details/log_msg.h"
+#include "spdlog/details/mpmc_blocking_q.h"
+#include "spdlog/details/os.h"
+
+#include <chrono>
+#include <memory>
+#include <thread>
+#include <vector>
+
+namespace spdlog {
+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
+{
+ async_msg_type msg_type;
+ level::level_enum level;
+ log_clock::time_point time;
+ size_t thread_id;
+ fmt::basic_memory_buffer<char, 176> raw;
+
+ size_t msg_id;
+ source_loc source;
+ 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) SPDLOG_NOEXCEPT : msg_type(other.msg_type),
+ level(other.level),
+ time(other.time),
+ thread_id(other.thread_id),
+ raw(move(other.raw)),
+ msg_id(other.msg_id),
+ source(other.source),
+ worker_ptr(std::move(other.worker_ptr))
+ {
+ }
+
+ async_msg &operator=(async_msg &&other) SPDLOG_NOEXCEPT
+ {
+ msg_type = other.msg_type;
+ level = other.level;
+ time = other.time;
+ thread_id = other.thread_id;
+ raw = std::move(other.raw);
+ msg_id = other.msg_id;
+ source = other.source;
+ worker_ptr = std::move(other.worker_ptr);
+ return *this;
+ }
+#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, details::log_msg &m)
+ : msg_type(the_type)
+ , level(m.level)
+ , time(m.time)
+ , thread_id(m.thread_id)
+ , msg_id(m.msg_id)
+ , source(m.source)
+ , worker_ptr(std::move(worker))
+ {
+ fmt_helper::append_string_view(m.payload, raw);
+ }
+
+ async_msg(async_logger_ptr &&worker, async_msg_type the_type)
+ : msg_type(the_type)
+ , level(level::off)
+ , time()
+ , thread_id(0)
+ , msg_id(0)
+ , source()
+ , worker_ptr(std::move(worker))
+ {
+ }
+
+ explicit async_msg(async_msg_type the_type)
+ : async_msg(nullptr, the_type)
+ {
+ }
+
+ // copy into log_msg
+ log_msg to_log_msg()
+ {
+ log_msg msg(&worker_ptr->name(), level, string_view_t(raw.data(), raw.size()));
+ msg.time = time;
+ msg.thread_id = thread_id;
+ msg.msg_id = msg_id;
+ msg.source = source;
+ msg.color_range_start = 0;
+ msg.color_range_end = 0;
+ return msg;
+ }
+};
+
+class 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)
+ : q_(q_max_items)
+ {
+ // std::cout << "thread_pool() q_size_bytes: " << q_size_bytes <<
+ // "\tthreads_n: " << threads_n << std::endl;
+ 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(&thread_pool::worker_loop_, this);
+ }
+ }
+
+ // message all threads to terminate gracefully join them
+ ~thread_pool()
+ {
+ 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();
+ }
+ }
+ catch (...)
+ {
+ }
+ }
+
+ thread_pool(const thread_pool &) = delete;
+ thread_pool &operator=(thread_pool &&) = delete;
+
+ void post_log(async_logger_ptr &&worker_ptr, 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 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 overrun_counter()
+ {
+ return q_.overrun_counter();
+ }
+
+private:
+ q_type q_;
+
+ std::vector<std::thread> threads_;
+
+ void 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 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 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:
+ {
+ auto msg = incoming_async_msg.to_log_msg();
+ incoming_async_msg.worker_ptr->backend_log_(msg);
+ return true;
+ }
+ case async_msg_type::flush:
+ {
+ incoming_async_msg.worker_ptr->backend_flush_();
+ return true;
+ }
+
+ case async_msg_type::terminate:
+ {
+ return false;
+ }
+ }
+ assert(false && "Unexpected async_msg_type");
+ return true;
+ }
+};
+
+} // namespace details
+} // namespace spdlog